mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git
synced 2024-11-24 10:31:03 +00:00
gst: implement IdStr bindings and compatibility versions
IdStr represents UTF-8 immutable strings which perform optimizations for short strings (< 16 bytes). The C type `GstIdStr` was introduced in GStreamer 1.26 as a replacement for GQuarks. This commit adds Rust bindings for the C type `GstIdStr`. Since this type will be used in API which previously relied on GQuarks, the commit also adds a compatibility implementation which can be used with GStreamer versions prior to 1.26, which is the first version to implement and use `GstIdStr`. The crate [KString] was used as the inner implementation for the compatibility version as it performs similar optimizations as `GstIdStr` and uses the same threshold to trigger heap allocation. See also: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7432 [KString]: https://crates.io/crates/kstring Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1531>
This commit is contained in:
parent
bad44ef436
commit
c2cc048803
7 changed files with 1587 additions and 0 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -884,6 +884,7 @@ dependencies = [
|
|||
"glib",
|
||||
"gstreamer-sys",
|
||||
"itertools",
|
||||
"kstring",
|
||||
"libc",
|
||||
"log",
|
||||
"muldiv",
|
||||
|
@ -1705,6 +1706,15 @@ version = "3.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
||||
|
||||
[[package]]
|
||||
name = "kstring"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "558bf9508a558512042d3095138b1f7b8fe90c5467d94f9f1da28b3731c5dbd1"
|
||||
dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.161"
|
||||
|
@ -2293,6 +2303,12 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.87"
|
||||
|
|
|
@ -23,6 +23,7 @@ num-rational = { version = "0.4", default-features = false, features = [] }
|
|||
futures-core = "0.3"
|
||||
futures-channel = "0.3"
|
||||
futures-util = { version = "0.3", default-features = false }
|
||||
kstring = "2.0"
|
||||
log = { version = "0.4", optional = true }
|
||||
muldiv = "1"
|
||||
opt-ops = { package = "option-operations", version = "0.5" }
|
||||
|
|
551
gstreamer/src/id_str/bindings.rs
Normal file
551
gstreamer/src/id_str/bindings.rs
Normal file
|
@ -0,0 +1,551 @@
|
|||
// Take a look at the license at the top of the repository in the LICENSE file.
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
//! The `IdStr` bindings of the C type `GstIdStr`.
|
||||
//!
|
||||
//! See the higher level module documentation for details.
|
||||
|
||||
use crate::ffi;
|
||||
use glib::{translate::*, GStr, GString};
|
||||
use std::{
|
||||
cmp,
|
||||
ffi::{c_char, CStr},
|
||||
fmt,
|
||||
hash::{Hash, Hasher},
|
||||
mem,
|
||||
ops::Deref,
|
||||
ptr::NonNull,
|
||||
};
|
||||
|
||||
glib::wrapper! {
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// An UTF-8 immutable string type with optimizations for short values (len < 16).
|
||||
#[derive(Debug)]
|
||||
#[doc(alias = "GstIdStr")]
|
||||
pub struct IdStr(BoxedInline<ffi::GstIdStr>);
|
||||
|
||||
match fn {
|
||||
copy => |ptr| ffi::gst_id_str_copy(ptr),
|
||||
free => |ptr| ffi::gst_id_str_free(ptr),
|
||||
init => |ptr| ffi::gst_id_str_init(ptr),
|
||||
copy_into => |dest, src| ffi::gst_id_str_copy_into(dest, src),
|
||||
clear => |ptr| ffi::gst_id_str_clear(ptr),
|
||||
}
|
||||
}
|
||||
|
||||
impl IdStr {
|
||||
#[doc(alias = "gst_id_str_new")]
|
||||
#[inline]
|
||||
pub const fn new() -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
unsafe {
|
||||
// Safety: empty inlined string consists in the type being all zeroed
|
||||
IdStr {
|
||||
inner: mem::zeroed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Builds an `IdStr` from the given static `GStr`.
|
||||
///
|
||||
/// This constructor performs optimizations which other constructors can't rely on.
|
||||
///
|
||||
/// To build an `IdStr` from a string literal, use the [`idstr`](crate::idstr) macro.
|
||||
#[inline]
|
||||
pub fn from_static<T: AsRef<GStr> + ?Sized>(value: &'static T) -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
let mut ret = IdStr::new();
|
||||
ret.set_static(value);
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_id_str_new")]
|
||||
#[inline]
|
||||
pub fn from<T: AsRef<str>>(value: T) -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
let mut id = IdStr::new();
|
||||
id.set(value);
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_id_str_get_len")]
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
unsafe { ffi::gst_id_str_get_len(self.to_glib_none().0) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Returns the pointer to the nul terminated string `value` represented by this `IdStr`.
|
||||
#[inline]
|
||||
fn as_char_ptr(&self) -> NonNull<c_char> {
|
||||
unsafe {
|
||||
let ptr = ffi::gst_id_str_as_str(self.to_glib_none().0);
|
||||
debug_assert!(!ptr.is_null());
|
||||
let nn = NonNull::<c_char>::new_unchecked(ptr as *mut _);
|
||||
|
||||
debug_assert_eq!(*nn.as_ptr().add(self.len()), 0, "expecting nul terminator");
|
||||
|
||||
nn
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
unsafe {
|
||||
// Safety: `as_char_ptr()` returns a non-null pointer to a nul terminated string.
|
||||
std::slice::from_raw_parts(self.as_char_ptr().as_ptr() as *const _, self.len())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_bytes_with_nul(&self) -> &[u8] {
|
||||
unsafe {
|
||||
// Safety: `as_char_ptr()` returns a non-null pointer to a nul terminated string.
|
||||
std::slice::from_raw_parts(self.as_char_ptr().as_ptr() as *const _, self.len() + 1)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_str(&self) -> &str {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(debug_assertions)] {
|
||||
std::str::from_utf8(self.as_bytes()).unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
std::str::from_utf8_unchecked(self.as_bytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_id_str_as_str")]
|
||||
#[inline]
|
||||
pub fn as_gstr(&self) -> &GStr {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(debug_assertions)] {
|
||||
GStr::from_utf8_with_nul(self.as_bytes_with_nul()).unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
GStr::from_utf8_with_nul_unchecked(self.as_bytes_with_nul())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_cstr(&self) -> &CStr {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(debug_assertions)] {
|
||||
CStr::from_bytes_with_nul(self.as_bytes_with_nul()).unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_id_str_is_equal")]
|
||||
#[inline]
|
||||
fn is_equal(&self, s2: &IdStr) -> bool {
|
||||
unsafe {
|
||||
from_glib(ffi::gst_id_str_is_equal(
|
||||
self.to_glib_none().0,
|
||||
s2.to_glib_none().0,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_id_str_is_equal_to_str_with_len")]
|
||||
#[inline]
|
||||
fn is_equal_to_str(&self, s2: impl AsRef<str>) -> bool {
|
||||
unsafe {
|
||||
let s2 = s2.as_ref();
|
||||
from_glib(ffi::gst_id_str_is_equal_to_str_with_len(
|
||||
self.to_glib_none().0,
|
||||
s2.as_ptr() as *const c_char,
|
||||
s2.len(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Sets `self` to the static string `value`.
|
||||
///
|
||||
/// This function performs optimizations which [IdStr::set] can't rely on.
|
||||
///
|
||||
/// To build an `IdStr` from a string literal, use the [`idstr`](crate::idstr) macro.
|
||||
#[doc(alias = "gst_id_str_set_static_str")]
|
||||
#[doc(alias = "gst_id_str_set_static_str_with_len")]
|
||||
#[inline]
|
||||
pub fn set_static<T: AsRef<GStr> + ?Sized>(&mut self, value: &'static T) {
|
||||
unsafe {
|
||||
let v = value.as_ref();
|
||||
ffi::gst_id_str_set_static_str_with_len(
|
||||
self.to_glib_none_mut().0,
|
||||
v.to_glib_none().0,
|
||||
v.len(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Sets `self` to the string `value`.
|
||||
///
|
||||
/// For a static value, use [IdStr::set_static] which can perform optimizations.
|
||||
///
|
||||
/// To build an `IdStr` from a string literal, use the [`idstr`](crate::idstr) macro.
|
||||
#[doc(alias = "gst_id_str_set")]
|
||||
#[doc(alias = "gst_id_str_set_with_len")]
|
||||
#[inline]
|
||||
pub fn set(&mut self, value: impl AsRef<str>) {
|
||||
unsafe {
|
||||
let v = value.as_ref();
|
||||
ffi::gst_id_str_set_with_len(
|
||||
self.to_glib_none_mut().0,
|
||||
v.as_ptr() as *const c_char,
|
||||
v.len(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for IdStr {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for IdStr {
|
||||
type Target = GStr;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.as_gstr()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for IdStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<IdStr> for IdStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &IdStr {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<GStr> for IdStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &GStr {
|
||||
self.as_gstr()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<CStr> for IdStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &CStr {
|
||||
self.as_cstr()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for IdStr {
|
||||
#[inline]
|
||||
fn from(value: &str) -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
let mut ret = IdStr::new();
|
||||
ret.set(value);
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&String> for IdStr {
|
||||
#[inline]
|
||||
fn from(value: &String) -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
let mut ret = IdStr::new();
|
||||
ret.set(value);
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for IdStr {
|
||||
#[inline]
|
||||
fn from(value: String) -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
let mut ret = IdStr::new();
|
||||
ret.set(&value);
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&GStr> for IdStr {
|
||||
#[inline]
|
||||
fn from(value: &GStr) -> IdStr {
|
||||
// assert checked in new()
|
||||
skip_assert_initialized!();
|
||||
let mut ret = IdStr::new();
|
||||
ret.set(value);
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&GString> for IdStr {
|
||||
#[inline]
|
||||
fn from(value: &GString) -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
let mut ret = IdStr::new();
|
||||
ret.set(value);
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GString> for IdStr {
|
||||
#[inline]
|
||||
fn from(value: GString) -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
let mut ret = IdStr::new();
|
||||
ret.set(&value);
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for IdStr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(self.as_gstr())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.is_equal(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<&IdStr> for IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &&IdStr) -> Option<cmp::Ordering> {
|
||||
Some(self.cmp(*other))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&IdStr> for IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&IdStr) -> bool {
|
||||
self.is_equal(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for IdStr {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
||||
self.as_cstr().cmp(other.as_cstr())
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for IdStr {}
|
||||
|
||||
impl PartialOrd<&GStr> for IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &&GStr) -> Option<cmp::Ordering> {
|
||||
self.as_str().partial_cmp(*other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&GStr> for IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&GStr) -> bool {
|
||||
self.is_equal_to_str(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<GStr> for IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &GStr) -> Option<cmp::Ordering> {
|
||||
self.as_str().partial_cmp(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<GStr> for IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &GStr) -> bool {
|
||||
self.is_equal_to_str(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<IdStr> for &GStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
|
||||
(*self).partial_cmp(other.as_gstr())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<IdStr> for &GStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &IdStr) -> bool {
|
||||
other.is_equal_to_str(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<IdStr> for GStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
|
||||
self.partial_cmp(other.as_gstr())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<IdStr> for GStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &IdStr) -> bool {
|
||||
other.is_equal_to_str(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<&str> for IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &&str) -> Option<cmp::Ordering> {
|
||||
self.as_gstr().partial_cmp(*other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&str> for IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
self.is_equal_to_str(*other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<str> for IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
|
||||
self.as_gstr().partial_cmp(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
self.is_equal_to_str(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<IdStr> for &str {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
|
||||
(*self).partial_cmp(other.as_gstr())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<IdStr> for &str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &IdStr) -> bool {
|
||||
other.is_equal_to_str(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<IdStr> for str {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
|
||||
self.partial_cmp(other.as_gstr())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<IdStr> for str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &IdStr) -> bool {
|
||||
other.is_equal_to_str(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<GString> for IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &GString) -> Option<cmp::Ordering> {
|
||||
self.as_gstr().partial_cmp(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<GString> for IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &GString) -> bool {
|
||||
self.is_equal_to_str(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<IdStr> for GString {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
|
||||
self.partial_cmp(other.as_gstr())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<IdStr> for GString {
|
||||
#[inline]
|
||||
fn eq(&self, other: &IdStr) -> bool {
|
||||
other.is_equal_to_str(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<String> for IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
|
||||
self.as_gstr().partial_cmp(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<String> for IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &String) -> bool {
|
||||
self.is_equal_to_str(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<IdStr> for String {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
|
||||
self.partial_cmp(other.as_gstr())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<IdStr> for String {
|
||||
#[inline]
|
||||
fn eq(&self, other: &IdStr) -> bool {
|
||||
other.is_equal_to_str(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for IdStr {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.as_gstr().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for IdStr {}
|
||||
unsafe impl Sync for IdStr {}
|
||||
|
||||
// Tests are mutualised between this implementation and the one in id_str_compat
|
||||
// See gstreamer/id_str/mod.rs
|
543
gstreamer/src/id_str/compat.rs
Normal file
543
gstreamer/src/id_str/compat.rs
Normal file
|
@ -0,0 +1,543 @@
|
|||
// Take a look at the license at the top of the repository in the LICENSE file.
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
//! The `IdStr` compatibility implementation.
|
||||
//!
|
||||
//! See the higher level module documentation for details.
|
||||
|
||||
use glib::{GStr, GString, IntoGStr};
|
||||
use std::{
|
||||
cmp,
|
||||
ffi::CStr,
|
||||
fmt,
|
||||
hash::{Hash, Hasher},
|
||||
ops::Deref,
|
||||
};
|
||||
|
||||
use kstring::KString;
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// An UTF-8 immutable string type with optimizations for short values (len < 16).
|
||||
#[derive(Clone, Debug)]
|
||||
#[doc(alias = "GstIdStr")]
|
||||
pub struct IdStr(KString);
|
||||
|
||||
impl IdStr {
|
||||
// In order to keep the same API and usability as `id_str_bindings::IdStr` regarding
|
||||
// the ability to efficiently deref to `&GStr`, the internal `KString` is always built
|
||||
// from a string with a nul terminator.
|
||||
|
||||
#[doc(alias = "gst_id_str_new")]
|
||||
#[inline]
|
||||
pub const fn new() -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
// Always include the nul terminator in the internal string
|
||||
IdStr(KString::from_static("\0"))
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Builds an `IdStr` from the given static `GStr`.
|
||||
///
|
||||
/// This constructor performs optimizations which other constructors can't rely on.
|
||||
///
|
||||
/// To build an `IdStr` from a string literal, use the [`idstr`](crate::idstr) macro.
|
||||
#[inline]
|
||||
pub fn from_static<T: AsRef<GStr> + ?Sized>(value: &'static T) -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
let gstr = value.as_ref();
|
||||
unsafe {
|
||||
let str_with_nul = std::str::from_utf8_unchecked(std::slice::from_raw_parts(
|
||||
gstr.as_ptr() as *const _,
|
||||
gstr.as_bytes_with_nul().len(),
|
||||
));
|
||||
|
||||
IdStr(KString::from_static(str_with_nul))
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_id_str_new")]
|
||||
#[inline]
|
||||
pub fn from(value: impl AsRef<str>) -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
let mut id = IdStr::new();
|
||||
id.set(value);
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_id_str_get_len")]
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
// The internal string ends with a nul terminator
|
||||
self.0.len() - 1
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
// The internal string ends with a nul terminator
|
||||
self.0.len() == 1
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
// The internal string ends with a nul terminator
|
||||
&self.0.as_bytes()[..IdStr::len(self)]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_bytes_with_nul(&self) -> &[u8] {
|
||||
// The internal string ends with a nul terminator
|
||||
self.0.as_bytes()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_str(&self) -> &str {
|
||||
unsafe {
|
||||
// Safety: the internal value is guaranteed to be an utf-8 string.
|
||||
std::str::from_utf8_unchecked(self.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_id_str_as_str")]
|
||||
#[inline]
|
||||
pub fn as_gstr(&self) -> &GStr {
|
||||
unsafe {
|
||||
// Safety: the internal value is guaranteed to be an utf-8 string.
|
||||
GStr::from_utf8_with_nul_unchecked(self.as_bytes_with_nul())
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_id_str_as_str")]
|
||||
#[inline]
|
||||
pub fn as_cstr(&self) -> &CStr {
|
||||
unsafe {
|
||||
// Safety: the internal value is guaranteed to be an utf-8 string
|
||||
// thus to not contain any nul bytes except for the terminator.
|
||||
CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul())
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Sets `self` to the static string `value`.
|
||||
///
|
||||
/// This function performs optimizations which [IdStr::set] can't rely on.
|
||||
///
|
||||
/// To build an `IdStr` from a string literal, use the [`idstr`](crate::idstr) macro.
|
||||
#[doc(alias = "gst_id_str_set_static_str")]
|
||||
#[doc(alias = "gst_id_str_set_static_str_with_len")]
|
||||
#[inline]
|
||||
pub fn set_static<T: AsRef<GStr> + ?Sized>(&mut self, value: &'static T) {
|
||||
unsafe {
|
||||
let gstr = value.as_ref();
|
||||
// Safety: the `GStr` value is guaranteed to be an utf-8 string
|
||||
// ending with a nul terminator.
|
||||
let str_with_nul = std::str::from_utf8_unchecked(std::slice::from_raw_parts(
|
||||
gstr.as_ptr() as *const _,
|
||||
gstr.as_bytes_with_nul().len(),
|
||||
));
|
||||
|
||||
self.0 = KString::from_static(str_with_nul);
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Sets `self` to the string `value`.
|
||||
///
|
||||
/// For a static value, use [IdStr::set_static] which can perform optimizations.
|
||||
///
|
||||
/// To build an `IdStr` from a string literal, use the [`idstr`](crate::idstr) macro.
|
||||
#[doc(alias = "gst_id_str_set")]
|
||||
#[doc(alias = "gst_id_str_set_with_len")]
|
||||
#[inline]
|
||||
pub fn set(&mut self, value: impl AsRef<str>) {
|
||||
self.0 = value.as_ref().run_with_gstr(|gstr| unsafe {
|
||||
let str_with_nul = std::str::from_utf8_unchecked(std::slice::from_raw_parts(
|
||||
gstr.as_ptr() as *const _,
|
||||
gstr.as_bytes_with_nul().len(),
|
||||
));
|
||||
|
||||
KString::from_ref(str_with_nul)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for IdStr {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for IdStr {
|
||||
type Target = GStr;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.as_gstr()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<IdStr> for IdStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &IdStr {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for IdStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<GStr> for IdStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &GStr {
|
||||
self.as_gstr()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<CStr> for IdStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &CStr {
|
||||
self.as_cstr()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for IdStr {
|
||||
#[inline]
|
||||
fn from(value: &str) -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
value.run_with_gstr(|gstr| unsafe {
|
||||
// Safety: the `GStr` value is guaranteed to be an utf-8 string
|
||||
// ending with a nul terminator.
|
||||
let str_with_nul = std::str::from_utf8_unchecked(std::slice::from_raw_parts(
|
||||
gstr.as_ptr() as *const _,
|
||||
gstr.as_bytes_with_nul().len(),
|
||||
));
|
||||
|
||||
IdStr(KString::from_ref(str_with_nul))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&String> for IdStr {
|
||||
#[inline]
|
||||
fn from(value: &String) -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
value.run_with_gstr(|gstr| unsafe {
|
||||
// Safety: the `GStr` value is guaranteed to be an utf-8 string
|
||||
// ending with a nul terminator.
|
||||
let str_with_nul = std::str::from_utf8_unchecked(std::slice::from_raw_parts(
|
||||
gstr.as_ptr() as *const _,
|
||||
gstr.as_bytes_with_nul().len(),
|
||||
));
|
||||
|
||||
IdStr(KString::from_ref(str_with_nul))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for IdStr {
|
||||
#[inline]
|
||||
fn from(value: String) -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
value.run_with_gstr(|gstr| unsafe {
|
||||
// Safety: the `GStr` value is guaranteed to be an utf-8 string
|
||||
// ending with a nul terminator.
|
||||
let str_with_nul = std::str::from_utf8_unchecked(std::slice::from_raw_parts(
|
||||
gstr.as_ptr() as *const _,
|
||||
gstr.as_bytes_with_nul().len(),
|
||||
));
|
||||
|
||||
IdStr(KString::from_ref(str_with_nul))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&GStr> for IdStr {
|
||||
#[inline]
|
||||
fn from(value: &GStr) -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
unsafe {
|
||||
// Safety: the `GStr` value is guaranteed to be an utf-8 string
|
||||
// ending with a nul terminator.
|
||||
let str_with_nul = std::str::from_utf8_unchecked(std::slice::from_raw_parts(
|
||||
value.as_ptr() as *const _,
|
||||
value.as_bytes_with_nul().len(),
|
||||
));
|
||||
|
||||
IdStr(KString::from_ref(str_with_nul))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&GString> for IdStr {
|
||||
#[inline]
|
||||
fn from(value: &GString) -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
unsafe {
|
||||
// Safety: the `GString` value is guaranteed to be an utf-8 string
|
||||
// ending with a nul terminator.
|
||||
let str_with_nul = std::str::from_utf8_unchecked(std::slice::from_raw_parts(
|
||||
value.as_ptr() as *const _,
|
||||
value.len() + 1,
|
||||
));
|
||||
|
||||
IdStr(KString::from_ref(str_with_nul))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GString> for IdStr {
|
||||
#[inline]
|
||||
fn from(value: GString) -> IdStr {
|
||||
skip_assert_initialized!();
|
||||
unsafe {
|
||||
// Safety: the `GString` value is guaranteed to be an utf-8 string
|
||||
// ending with a nul terminator.
|
||||
let str_with_nul = std::str::from_utf8_unchecked(std::slice::from_raw_parts(
|
||||
value.as_ptr() as *const _,
|
||||
value.len() + 1,
|
||||
));
|
||||
|
||||
IdStr(KString::from_ref(str_with_nul))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for IdStr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(self.as_gstr())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<&IdStr> for IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &&IdStr) -> Option<cmp::Ordering> {
|
||||
Some(self.0.cmp(&other.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&IdStr> for IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&IdStr) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<IdStr> for &IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
|
||||
Some(self.0.cmp(&other.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<IdStr> for &IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &IdStr) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for IdStr {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
||||
self.0.cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for IdStr {}
|
||||
|
||||
impl PartialOrd<&GStr> for IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &&GStr) -> Option<cmp::Ordering> {
|
||||
self.as_gstr().partial_cmp(*other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&GStr> for IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&GStr) -> bool {
|
||||
self.as_gstr() == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<GStr> for IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &GStr) -> Option<cmp::Ordering> {
|
||||
self.as_gstr().partial_cmp(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<GStr> for IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &GStr) -> bool {
|
||||
self.as_gstr() == other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<IdStr> for &GStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
|
||||
(*self).partial_cmp(other.as_gstr())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<IdStr> for &GStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &IdStr) -> bool {
|
||||
(*self) == other.as_gstr()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<IdStr> for GStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
|
||||
self.partial_cmp(other.as_gstr())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<IdStr> for GStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &IdStr) -> bool {
|
||||
self == other.as_gstr()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<&str> for IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &&str) -> Option<cmp::Ordering> {
|
||||
self.as_gstr().partial_cmp(*other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&str> for IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
self.as_gstr() == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<str> for IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
|
||||
self.as_gstr().partial_cmp(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
self.as_gstr() == other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<IdStr> for &str {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
|
||||
(*self).partial_cmp(other.as_gstr())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<IdStr> for &str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &IdStr) -> bool {
|
||||
(*self) == other.as_gstr()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<IdStr> for str {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
|
||||
self.partial_cmp(other.as_gstr())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<IdStr> for str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &IdStr) -> bool {
|
||||
self == other.as_gstr()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<GString> for IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &GString) -> Option<cmp::Ordering> {
|
||||
self.as_gstr().partial_cmp(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<GString> for IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &GString) -> bool {
|
||||
self.as_gstr() == other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<IdStr> for GString {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
|
||||
self.partial_cmp(other.as_gstr())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<IdStr> for GString {
|
||||
#[inline]
|
||||
fn eq(&self, other: &IdStr) -> bool {
|
||||
self == other.as_gstr()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<String> for IdStr {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
|
||||
self.as_gstr().partial_cmp(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<String> for IdStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &String) -> bool {
|
||||
self.as_gstr() == other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<IdStr> for String {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
|
||||
self.partial_cmp(other.as_gstr())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<IdStr> for String {
|
||||
#[inline]
|
||||
fn eq(&self, other: &IdStr) -> bool {
|
||||
self == other.as_gstr()
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for IdStr {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.as_gstr().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for IdStr {}
|
||||
unsafe impl Sync for IdStr {}
|
||||
|
||||
// Tests are mutualised between this implementation and the one in id_str_bindings
|
||||
// See gstreamer/id_str/mod.rs
|
435
gstreamer/src/id_str/mod.rs
Normal file
435
gstreamer/src/id_str/mod.rs
Normal file
|
@ -0,0 +1,435 @@
|
|||
// Take a look at the license at the top of the repository in the LICENSE file.
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
//! This module selects one of the two `IdStr` implementations:
|
||||
//!
|
||||
//! * When feature `v1_26` (or later) is activated, `IdStr` implements the bindings
|
||||
//! for the C type `GstIdStr`.
|
||||
//! * For earlier feature versions, a compatibility implementation is used.
|
||||
//!
|
||||
//! See also: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7432>
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "v1_26")] {
|
||||
mod bindings;
|
||||
pub use self::bindings::IdStr;
|
||||
} else {
|
||||
mod compat;
|
||||
pub use self::compat::IdStr;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
mod serde;
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Builds an [`IdStr`] from a string literal.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() {
|
||||
/// use gstreamer::{idstr, IdStr};
|
||||
/// use std::sync::LazyLock;
|
||||
///
|
||||
/// static MY_ID_STR: LazyLock<IdStr> = LazyLock::new(|| idstr!("static id"));
|
||||
/// assert_eq!(*MY_ID_STR, "static id");
|
||||
///
|
||||
/// let my_id_str: IdStr = idstr!("local id");
|
||||
/// assert_eq!(my_id_str, "local id");
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`IdStr`]: crate::IdStr
|
||||
#[macro_export]
|
||||
macro_rules! idstr {
|
||||
($s:literal) => {
|
||||
IdStr::from_static($crate::glib::gstr!($s))
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use glib::{gstr, GStr, GString};
|
||||
use std::{ffi::CStr, sync::LazyLock};
|
||||
|
||||
use super::IdStr;
|
||||
|
||||
const STR: &str = "STR";
|
||||
static IDSTR: LazyLock<IdStr> = LazyLock::new(|| idstr!("IDSTR"));
|
||||
static GSTR: &GStr = gstr!("GSTR");
|
||||
static GSTRING: LazyLock<GString> = LazyLock::new(|| GString::from("GSTRING"));
|
||||
|
||||
const LONG_STR: &str = "An STR longer than 15 bytes";
|
||||
static LONG_IDSTR: LazyLock<IdStr> = LazyLock::new(|| idstr!("An IdStr longer than 15 bytes"));
|
||||
static LONG_GSTR: &GStr = gstr!("A GSTR longer than 15 bytes");
|
||||
static LONG_GSTRING: LazyLock<GString> =
|
||||
LazyLock::new(|| GString::from("A GSTRING longer than 15 bytes"));
|
||||
|
||||
#[test]
|
||||
fn new_set_static() {
|
||||
assert!(!IDSTR.is_empty());
|
||||
assert_eq!(IDSTR.len(), "IDSTR".len());
|
||||
assert_eq!(IDSTR.as_str().len(), "IDSTR".len());
|
||||
assert_eq!(*IDSTR, "IDSTR");
|
||||
// Display impl
|
||||
assert_eq!(IDSTR.to_string(), "IDSTR");
|
||||
assert_eq!(IDSTR.as_str(), "IDSTR");
|
||||
assert_eq!(IDSTR.as_gstr().len(), "IDSTR".len());
|
||||
assert_eq!(IDSTR.as_gstr(), "IDSTR");
|
||||
|
||||
let id_str: IdStr = idstr!("id_str");
|
||||
assert!(!id_str.is_empty());
|
||||
assert_eq!(id_str.len(), "id_str".len());
|
||||
assert_eq!(id_str.as_str().len(), "id_str".len());
|
||||
assert_eq!(id_str, "id_str");
|
||||
|
||||
let mut s = IdStr::new();
|
||||
assert!(s.is_empty());
|
||||
assert_eq!(s.len(), 0);
|
||||
assert_eq!(s.as_str(), "");
|
||||
assert_eq!(s.as_gstr(), "");
|
||||
|
||||
s.set_static(gstr!("str"));
|
||||
assert!(!s.is_empty());
|
||||
assert_eq!(s.len(), "str".len());
|
||||
assert_eq!(s.as_str().len(), "str".len());
|
||||
assert_eq!(s, "str");
|
||||
// Display impl
|
||||
assert_eq!(s.to_string(), "str");
|
||||
assert_eq!(s.as_str(), "str");
|
||||
assert_eq!(s.as_gstr().len(), "str".len());
|
||||
assert_eq!(s.as_gstr(), "str");
|
||||
|
||||
s.set_static(GSTR);
|
||||
assert_eq!(s.as_str(), "GSTR");
|
||||
|
||||
s.set_static(&*GSTRING);
|
||||
assert_eq!(s.as_str(), "GSTRING");
|
||||
|
||||
assert!(!LONG_IDSTR.is_empty());
|
||||
assert_eq!(LONG_IDSTR.len(), "An IdStr longer than 15 bytes".len());
|
||||
assert_eq!(*LONG_IDSTR, "An IdStr longer than 15 bytes");
|
||||
// Display impl
|
||||
assert_eq!(LONG_IDSTR.to_string(), "An IdStr longer than 15 bytes");
|
||||
assert_eq!(
|
||||
LONG_IDSTR.as_str().len(),
|
||||
"An IdStr longer than 15 bytes".len()
|
||||
);
|
||||
assert_eq!(LONG_IDSTR.as_str(), "An IdStr longer than 15 bytes");
|
||||
assert_eq!(
|
||||
LONG_IDSTR.as_gstr().len(),
|
||||
"An IdStr longer than 15 bytes".len()
|
||||
);
|
||||
assert_eq!(LONG_IDSTR.as_gstr(), "An IdStr longer than 15 bytes");
|
||||
|
||||
let ls = idstr!("An IdStr longer than 15 bytes");
|
||||
assert!(!ls.is_empty());
|
||||
assert_eq!(ls.len(), "An IdStr longer than 15 bytes".len());
|
||||
assert_eq!(ls, "An IdStr longer than 15 bytes");
|
||||
|
||||
let mut ls = IdStr::new();
|
||||
|
||||
ls.set_static(gstr!("An str longer than 15 bytes"));
|
||||
assert!(!ls.is_empty());
|
||||
assert_eq!(ls.len(), "An str longer than 15 bytes".len());
|
||||
assert_eq!(ls, "An str longer than 15 bytes");
|
||||
|
||||
ls.set_static(LONG_GSTR);
|
||||
assert_eq!(ls.as_str(), "A GSTR longer than 15 bytes");
|
||||
|
||||
ls.set_static(&*LONG_GSTRING);
|
||||
assert_eq!(ls.as_str(), "A GSTRING longer than 15 bytes");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_static() {
|
||||
let s = IdStr::from_static(gstr!("str"));
|
||||
assert!(!s.is_empty());
|
||||
assert_eq!(s.len(), "str".len());
|
||||
assert_eq!(s.as_str().len(), "str".len());
|
||||
assert_eq!(s, "str");
|
||||
// Display impl
|
||||
assert_eq!(s.to_string(), "str");
|
||||
assert_eq!(s.as_str(), "str");
|
||||
assert_eq!(s.as_gstr().len(), "str".len());
|
||||
assert_eq!(s.as_gstr(), "str");
|
||||
|
||||
let s = idstr!("str");
|
||||
assert!(!s.is_empty());
|
||||
assert_eq!(s.len(), "str".len());
|
||||
assert_eq!(s.as_str().len(), "str".len());
|
||||
assert_eq!(s, "str");
|
||||
|
||||
let s = IdStr::from_static(GSTR);
|
||||
assert_eq!(s.as_str(), "GSTR");
|
||||
|
||||
let s = IdStr::from_static(&*GSTRING);
|
||||
assert_eq!(s.as_str(), "GSTRING");
|
||||
|
||||
let ls = IdStr::from_static(gstr!("An str longer than 15 bytes"));
|
||||
assert!(!ls.is_empty());
|
||||
assert_eq!(ls.len(), "An str longer than 15 bytes".len());
|
||||
assert_eq!(ls, "An str longer than 15 bytes");
|
||||
// Display impl
|
||||
assert_eq!(ls.to_string(), "An str longer than 15 bytes");
|
||||
assert_eq!(ls.as_str().len(), "An str longer than 15 bytes".len());
|
||||
assert_eq!(ls.as_str(), "An str longer than 15 bytes");
|
||||
assert_eq!(ls.as_gstr().len(), "An str longer than 15 bytes".len());
|
||||
assert_eq!(ls.as_gstr(), "An str longer than 15 bytes");
|
||||
|
||||
let ls = idstr!("An str longer than 15 bytes");
|
||||
assert!(!ls.is_empty());
|
||||
assert_eq!(ls.len(), "An str longer than 15 bytes".len());
|
||||
assert_eq!(ls, "An str longer than 15 bytes");
|
||||
|
||||
let ls = IdStr::from_static(LONG_GSTR);
|
||||
assert_eq!(ls.as_str(), "A GSTR longer than 15 bytes");
|
||||
|
||||
let ls = IdStr::from_static(&*LONG_GSTRING);
|
||||
assert_eq!(ls.as_str(), "A GSTRING longer than 15 bytes");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_set() {
|
||||
let d = IdStr::default();
|
||||
assert!(d.is_empty());
|
||||
assert_eq!(d.len(), 0);
|
||||
assert_eq!(d.as_str(), "");
|
||||
assert_eq!(d.as_gstr(), "");
|
||||
|
||||
let mut s = IdStr::new();
|
||||
assert!(s.is_empty());
|
||||
assert_eq!(s.len(), 0);
|
||||
assert_eq!(s.as_str(), "");
|
||||
assert_eq!(s.as_gstr(), "");
|
||||
|
||||
s.set("str");
|
||||
assert!(!s.is_empty());
|
||||
assert_eq!(s.len(), "str".len());
|
||||
assert_eq!(s.as_str().len(), "str".len());
|
||||
assert_eq!(s.as_str(), "str");
|
||||
assert_eq!(AsRef::<str>::as_ref(&s), "str");
|
||||
// Display impl
|
||||
assert_eq!(s.to_string(), "str");
|
||||
assert_eq!(s.as_gstr().len(), "str".len());
|
||||
assert_eq!(s.as_gstr(), "str");
|
||||
assert_eq!(AsRef::<GStr>::as_ref(&s), "str");
|
||||
assert_eq!(s.as_cstr().to_bytes(), b"str");
|
||||
assert_eq!(AsRef::<CStr>::as_ref(&s).to_bytes(), b"str");
|
||||
assert_eq!(s.as_bytes(), b"str");
|
||||
|
||||
let string = String::from("String");
|
||||
s.set(string.as_str());
|
||||
assert_eq!(s.as_str(), "String");
|
||||
s.set(&string);
|
||||
assert_eq!(s.as_str(), "String");
|
||||
|
||||
s.set(gstr!("gstr"));
|
||||
assert_eq!(s.as_str(), "gstr");
|
||||
|
||||
let gstring = GString::from("GString");
|
||||
s.set(gstring.as_gstr());
|
||||
assert_eq!(s.as_str(), "GString");
|
||||
s.set(&gstring);
|
||||
assert_eq!(s.as_str(), "GString");
|
||||
s.set(gstring.as_str());
|
||||
assert_eq!(s.as_str(), "GString");
|
||||
|
||||
let mut ls = IdStr::new();
|
||||
|
||||
ls.set("An str longer than 15 bytes");
|
||||
assert!(!ls.is_empty());
|
||||
assert_eq!(ls.len(), "An str longer than 15 bytes".len());
|
||||
assert_eq!(ls, "An str longer than 15 bytes");
|
||||
// Display impl
|
||||
assert_eq!(ls.to_string(), "An str longer than 15 bytes");
|
||||
assert_eq!(ls.as_str().len(), "An str longer than 15 bytes".len());
|
||||
assert_eq!(ls.as_str(), "An str longer than 15 bytes");
|
||||
assert_eq!(ls.as_gstr().len(), "An str longer than 15 bytes".len());
|
||||
assert_eq!(ls.as_gstr(), "An str longer than 15 bytes");
|
||||
assert_eq!(ls.as_cstr().to_bytes(), b"An str longer than 15 bytes");
|
||||
assert_eq!(
|
||||
AsRef::<CStr>::as_ref(&ls).to_bytes(),
|
||||
b"An str longer than 15 bytes"
|
||||
);
|
||||
assert_eq!(ls.as_bytes(), b"An str longer than 15 bytes");
|
||||
|
||||
ls.set(gstr!("A gstr longer than 15 bytes"));
|
||||
assert_eq!(ls.as_str(), "A gstr longer than 15 bytes");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from() {
|
||||
let s = IdStr::from("str");
|
||||
assert_eq!(s.len(), "str".len());
|
||||
assert_eq!(s.as_str().len(), "str".len());
|
||||
assert_eq!(s.as_str(), "str");
|
||||
// Display impl
|
||||
assert_eq!(s.to_string(), "str");
|
||||
assert_eq!(s.as_gstr().len(), "str".len());
|
||||
assert_eq!(s.as_gstr(), "str");
|
||||
|
||||
let string = String::from("String");
|
||||
let s = IdStr::from(string.as_str());
|
||||
assert_eq!(s.as_str(), "String");
|
||||
let s: IdStr = string.as_str().into();
|
||||
assert_eq!(s.as_str(), "String");
|
||||
let s: IdStr = (&string).into();
|
||||
assert_eq!(s.as_str(), "String");
|
||||
let s: IdStr = string.into();
|
||||
assert_eq!(s.as_str(), "String");
|
||||
|
||||
let s = IdStr::from(gstr!("str"));
|
||||
assert_eq!(s.as_str(), "str");
|
||||
|
||||
let gstring = GString::from("GString");
|
||||
let s = IdStr::from(gstring.as_gstr());
|
||||
assert_eq!(s.as_str(), "GString");
|
||||
let s: IdStr = (&gstring).into();
|
||||
assert_eq!(s.as_str(), "GString");
|
||||
let s: IdStr = gstring.into();
|
||||
assert_eq!(s.as_str(), "GString");
|
||||
|
||||
let ls = IdStr::from("An str longer than 15 bytes");
|
||||
assert!(!ls.is_empty());
|
||||
assert_eq!(ls.len(), "An str longer than 15 bytes".len());
|
||||
assert_eq!(ls, "An str longer than 15 bytes");
|
||||
// Display impl
|
||||
assert_eq!(ls.to_string(), "An str longer than 15 bytes");
|
||||
assert_eq!(ls.as_str().len(), "An str longer than 15 bytes".len());
|
||||
assert_eq!(ls.as_str(), "An str longer than 15 bytes");
|
||||
assert_eq!(ls.as_gstr().len(), "An str longer than 15 bytes".len());
|
||||
assert_eq!(ls.as_gstr(), "An str longer than 15 bytes");
|
||||
|
||||
let ls = IdStr::from(gstr!("A gstr longer than 15 bytes"));
|
||||
assert_eq!(ls.as_str(), "A gstr longer than 15 bytes");
|
||||
assert_eq!(ls.as_gstr(), "A gstr longer than 15 bytes");
|
||||
|
||||
let lstring = String::from("A String longer than 15 bytes");
|
||||
let ls = IdStr::from(lstring.as_str());
|
||||
assert_eq!(ls.as_str(), "A String longer than 15 bytes");
|
||||
let ls = IdStr::from(&lstring);
|
||||
assert_eq!(ls.as_str(), "A String longer than 15 bytes");
|
||||
|
||||
let lgstring = String::from("A GString longer than 15 bytes");
|
||||
let ls = IdStr::from(lgstring.as_str());
|
||||
assert_eq!(ls.as_str(), "A GString longer than 15 bytes");
|
||||
let ls = IdStr::from(&lgstring);
|
||||
assert_eq!(ls.as_str(), "A GString longer than 15 bytes");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::cmp_owned)]
|
||||
fn eq_cmp() {
|
||||
let s1 = IdStr::from(STR);
|
||||
let s12: IdStr = STR.into();
|
||||
assert_eq!(s1, s12);
|
||||
let s2 = IdStr::from(String::from(STR));
|
||||
let s22: IdStr = String::from(STR).into();
|
||||
assert_eq!(s2, s22);
|
||||
let s3 = IdStr::from_static(gstr!("STR"));
|
||||
assert_eq!(s1, s2);
|
||||
assert_eq!(s1, s3);
|
||||
assert_eq!(s2, s3);
|
||||
|
||||
assert!(s1 == gstr!("STR"));
|
||||
assert_eq!(s1, gstr!("STR"));
|
||||
assert_eq!(s1, GString::from("STR"));
|
||||
assert!(s1 == "STR");
|
||||
assert_eq!(s1, "STR");
|
||||
assert!("STR" == s1);
|
||||
assert_eq!("STR", s1);
|
||||
assert_eq!(s1, String::from("STR"));
|
||||
|
||||
assert_eq!(gstr!("STR"), s1);
|
||||
assert_eq!(GString::from("STR"), s1);
|
||||
assert_eq!("STR", s1);
|
||||
assert_eq!(String::from("STR"), s1);
|
||||
|
||||
let ls1 = IdStr::from(LONG_STR);
|
||||
let ls2: IdStr = String::from(LONG_STR).into();
|
||||
let ls3 = IdStr::from_static(gstr!("An STR longer than 15 bytes"));
|
||||
assert_eq!(ls1, ls2);
|
||||
assert_eq!(ls1, ls3);
|
||||
assert_eq!(ls2, ls3);
|
||||
|
||||
assert!(ls1 == gstr!("An STR longer than 15 bytes"));
|
||||
assert_eq!(ls1, gstr!("An STR longer than 15 bytes"));
|
||||
assert_eq!(ls1, GString::from(LONG_STR));
|
||||
assert_eq!(ls1, LONG_STR);
|
||||
assert!(ls1 == "An STR longer than 15 bytes");
|
||||
assert_eq!(ls1, "An STR longer than 15 bytes");
|
||||
assert_eq!(ls1, String::from(LONG_STR));
|
||||
|
||||
assert_eq!(gstr!("An STR longer than 15 bytes"), ls1);
|
||||
assert_eq!(GString::from(LONG_STR), ls1);
|
||||
assert_eq!(LONG_STR, ls1);
|
||||
assert_eq!("An STR longer than 15 bytes", ls1);
|
||||
assert_eq!(String::from(LONG_STR), ls1);
|
||||
|
||||
assert_ne!(s1, ls1);
|
||||
assert_ne!(ls1, s1);
|
||||
|
||||
let s4 = IdStr::from("STR4");
|
||||
assert_ne!(s1, s4);
|
||||
assert!(s1 < s4);
|
||||
assert!(s4 > s1);
|
||||
|
||||
assert!(s1 < gstr!("STR4"));
|
||||
assert!(s1 < GString::from("STR4"));
|
||||
assert!(s1 < "STR4");
|
||||
assert!("STR4" > s1);
|
||||
assert!(s1 < String::from("STR4"));
|
||||
|
||||
assert!(gstr!("STR4") > s1);
|
||||
assert!(GString::from("STR4") > s1);
|
||||
assert!("STR4" > s1);
|
||||
assert!(String::from("STR4") > s1);
|
||||
|
||||
// ls1 starts with an 'A', s4 with an 'S'
|
||||
assert_ne!(ls1, s4);
|
||||
assert!(ls1 < s4);
|
||||
assert!(s4 > s1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn as_ref_idstr() {
|
||||
#[allow(clippy::nonminimal_bool)]
|
||||
fn check(c: &str, v: impl AsRef<IdStr>) {
|
||||
let v = v.as_ref();
|
||||
|
||||
assert_eq!(c, v);
|
||||
assert_eq!(v, c);
|
||||
|
||||
assert!(!(c > v));
|
||||
assert!(!(v > c));
|
||||
|
||||
let i = IdStr::from(c);
|
||||
assert_eq!(i, v);
|
||||
assert_eq!(i, IdStr::from(c));
|
||||
|
||||
assert!(!(c > i));
|
||||
assert!(!(i > c));
|
||||
}
|
||||
|
||||
let v = IdStr::from(STR);
|
||||
check(STR, &v);
|
||||
check(STR, v);
|
||||
|
||||
#[allow(clippy::nonminimal_bool)]
|
||||
fn check_gstr(c: &GStr, v: impl AsRef<IdStr>) {
|
||||
let v = v.as_ref();
|
||||
|
||||
assert_eq!(c, v);
|
||||
assert_eq!(v, c);
|
||||
|
||||
assert!(!(c > v));
|
||||
assert!(!(v > c));
|
||||
}
|
||||
|
||||
let v = IdStr::from(GSTR);
|
||||
check_gstr(GSTR, &v);
|
||||
check_gstr(GSTR, v);
|
||||
}
|
||||
}
|
37
gstreamer/src/id_str/serde.rs
Normal file
37
gstreamer/src/id_str/serde.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Take a look at the license at the top of the repository in the LICENSE file.
|
||||
|
||||
use serde::{
|
||||
de::{Deserialize, Deserializer},
|
||||
ser::{Serialize, Serializer},
|
||||
};
|
||||
|
||||
use crate::IdStr;
|
||||
|
||||
impl Serialize for IdStr {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
self.as_str().serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for IdStr {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
skip_assert_initialized!();
|
||||
<&str>::deserialize(deserializer).map(IdStr::from)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::idstr;
|
||||
|
||||
#[test]
|
||||
fn ser_de() {
|
||||
assert_eq!(
|
||||
ron::ser::to_string(&idstr!("my IdStr")),
|
||||
Ok("\"my IdStr\"".to_owned())
|
||||
);
|
||||
|
||||
assert_eq!(ron::de::from_str("\"my IdStr\""), Ok(idstr!("my IdStr")));
|
||||
}
|
||||
}
|
|
@ -82,6 +82,10 @@ pub use crate::value::{
|
|||
#[macro_use]
|
||||
mod value_serde;
|
||||
|
||||
#[macro_use]
|
||||
mod id_str;
|
||||
pub use crate::id_str::IdStr;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
mod flag_serde;
|
||||
|
||||
|
|
Loading…
Reference in a new issue