gstreamer/id_str/
bindings.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3// rustdoc-stripper-ignore-next
4//! The `IdStr` bindings of the C type `GstIdStr`.
5//!
6//! See the higher level module documentation for details.
7
8use crate::ffi;
9use glib::{translate::*, GStr, GString};
10use std::{
11    cmp,
12    ffi::{c_char, CStr},
13    fmt,
14    hash::{Hash, Hasher},
15    mem,
16    ops::Deref,
17    ptr::NonNull,
18};
19
20glib::wrapper! {
21    // rustdoc-stripper-ignore-next
22    /// An UTF-8 immutable string type with optimizations for short values (len < 16).
23    // rustdoc-stripper-ignore-next-stop
24    /// A [`IdStr`][crate::IdStr] is string type optimized for short strings and used for structure
25    /// names, structure field names and in other places.
26    ///
27    /// Strings up to 16 bytes (including NUL terminator) are stored inline, other
28    /// strings are stored on the heap.
29    ///
30    /// **⚠️ The following code is in cpp ⚠️**
31    ///
32    /// ```cpp
33    /// GstIdStr s = GST_ID_STR_INIT;
34    ///
35    /// gst_id_str_set (&s, "Hello, World!");
36    /// g_print ("%s\n", gst_id_str_as_str (&s));
37    ///
38    /// gst_id_str_clear (&s);
39    /// ```
40    #[derive(Debug)]
41    #[doc(alias = "GstIdStr")]
42    pub struct IdStr(BoxedInline<ffi::GstIdStr>);
43
44    match fn {
45        copy => |ptr| ffi::gst_id_str_copy(ptr),
46        free => |ptr| ffi::gst_id_str_free(ptr),
47        init => |ptr| ffi::gst_id_str_init(ptr),
48        copy_into => |dest, src| ffi::gst_id_str_copy_into(dest, src),
49        clear => |ptr| ffi::gst_id_str_clear(ptr),
50    }
51}
52
53impl IdStr {
54    #[doc(alias = "gst_id_str_new")]
55    #[inline]
56    pub const fn new() -> IdStr {
57        skip_assert_initialized!();
58        unsafe {
59            // Safety: empty inlined string consists in the type being all zeroed
60            IdStr {
61                inner: mem::zeroed(),
62            }
63        }
64    }
65
66    // rustdoc-stripper-ignore-next
67    /// Builds an `IdStr` from the given static `GStr`.
68    ///
69    /// This constructor performs optimizations which other constructors can't rely on.
70    ///
71    /// To build an `IdStr` from a string literal, use the [`idstr`](crate::idstr) macro.
72    #[inline]
73    pub fn from_static<T: AsRef<GStr> + ?Sized>(value: &'static T) -> IdStr {
74        skip_assert_initialized!();
75        let mut ret = IdStr::new();
76        ret.set_static(value);
77
78        ret
79    }
80
81    #[doc(alias = "gst_id_str_new")]
82    #[inline]
83    pub fn from<T: AsRef<str>>(value: T) -> IdStr {
84        skip_assert_initialized!();
85        let mut id = IdStr::new();
86        id.set(value);
87
88        id
89    }
90
91    /// Returns the length of `self`, exluding the NUL-terminator. This is equivalent to
92    /// calling ``strcmp()`` but potentially faster.
93    #[doc(alias = "gst_id_str_get_len")]
94    #[inline]
95    pub fn len(&self) -> usize {
96        unsafe { ffi::gst_id_str_get_len(self.to_glib_none().0) }
97    }
98
99    #[inline]
100    pub fn is_empty(&self) -> bool {
101        self.len() == 0
102    }
103
104    // rustdoc-stripper-ignore-next
105    /// Returns the pointer to the nul terminated string `value` represented by this `IdStr`.
106    #[inline]
107    fn as_char_ptr(&self) -> NonNull<c_char> {
108        unsafe {
109            let ptr = ffi::gst_id_str_as_str(self.to_glib_none().0);
110            debug_assert!(!ptr.is_null());
111            let nn = NonNull::<c_char>::new_unchecked(ptr as *mut _);
112
113            debug_assert_eq!(*nn.as_ptr().add(self.len()), 0, "expecting nul terminator");
114
115            nn
116        }
117    }
118
119    #[inline]
120    pub fn as_bytes(&self) -> &[u8] {
121        unsafe {
122            // Safety: `as_char_ptr()` returns a non-null pointer to a nul terminated string.
123            std::slice::from_raw_parts(self.as_char_ptr().as_ptr() as *const _, self.len())
124        }
125    }
126
127    #[inline]
128    fn as_bytes_with_nul(&self) -> &[u8] {
129        unsafe {
130            // Safety: `as_char_ptr()` returns a non-null pointer to a nul terminated string.
131            std::slice::from_raw_parts(self.as_char_ptr().as_ptr() as *const _, self.len() + 1)
132        }
133    }
134
135    ///
136    /// # Returns
137    ///
138    /// the NUL-terminated string representation of `self`.
139    #[inline]
140    pub fn as_str(&self) -> &str {
141        cfg_if::cfg_if! {
142            if #[cfg(debug_assertions)] {
143                std::str::from_utf8(self.as_bytes()).unwrap()
144            } else {
145                unsafe {
146                    std::str::from_utf8_unchecked(self.as_bytes())
147                }
148            }
149        }
150    }
151
152    #[doc(alias = "gst_id_str_as_str")]
153    #[inline]
154    pub fn as_gstr(&self) -> &GStr {
155        cfg_if::cfg_if! {
156            if #[cfg(debug_assertions)] {
157                GStr::from_utf8_with_nul(self.as_bytes_with_nul()).unwrap()
158            } else {
159                unsafe {
160                    GStr::from_utf8_with_nul_unchecked(self.as_bytes_with_nul())
161                }
162            }
163        }
164    }
165
166    #[inline]
167    pub fn as_cstr(&self) -> &CStr {
168        cfg_if::cfg_if! {
169            if #[cfg(debug_assertions)] {
170                CStr::from_bytes_with_nul(self.as_bytes_with_nul()).unwrap()
171            } else {
172                unsafe {
173                    CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul())
174                }
175            }
176        }
177    }
178
179    #[doc(alias = "gst_id_str_is_equal")]
180    #[inline]
181    fn is_equal(&self, s2: &IdStr) -> bool {
182        unsafe {
183            from_glib(ffi::gst_id_str_is_equal(
184                self.to_glib_none().0,
185                s2.to_glib_none().0,
186            ))
187        }
188    }
189
190    /// Compares `self` and `s2` for equality.
191    /// ## `s2`
192    /// A string
193    ///
194    /// # Returns
195    ///
196    /// [`true`] if `self` and `s2` are equal.
197    #[doc(alias = "gst_id_str_is_equal_to_str_with_len")]
198    #[inline]
199    fn is_equal_to_str(&self, s2: impl AsRef<str>) -> bool {
200        unsafe {
201            let s2 = s2.as_ref();
202            from_glib(ffi::gst_id_str_is_equal_to_str_with_len(
203                self.to_glib_none().0,
204                s2.as_ptr() as *const c_char,
205                s2.len(),
206            ))
207        }
208    }
209
210    // rustdoc-stripper-ignore-next
211    /// Sets `self` to the static string `value`.
212    ///
213    /// This function performs optimizations which [IdStr::set] can't rely on.
214    ///
215    /// To build an `IdStr` from a string literal, use the [`idstr`](crate::idstr) macro.
216    #[doc(alias = "gst_id_str_set_static_str")]
217    #[doc(alias = "gst_id_str_set_static_str_with_len")]
218    #[inline]
219    pub fn set_static<T: AsRef<GStr> + ?Sized>(&mut self, value: &'static T) {
220        unsafe {
221            let v = value.as_ref();
222            ffi::gst_id_str_set_static_str_with_len(
223                self.to_glib_none_mut().0,
224                v.to_glib_none().0,
225                v.len(),
226            );
227        }
228    }
229
230    // rustdoc-stripper-ignore-next
231    /// Sets `self` to the string `value`.
232    ///
233    /// For a static value, use [IdStr::set_static] which can perform optimizations.
234    ///
235    /// To build an `IdStr` from a string literal, use the [`idstr`](crate::idstr) macro.
236    // rustdoc-stripper-ignore-next-stop
237    /// Sets `self` to the string `value`.
238    /// ## `value`
239    /// A NUL-terminated string
240    #[doc(alias = "gst_id_str_set")]
241    #[doc(alias = "gst_id_str_set_with_len")]
242    #[inline]
243    pub fn set(&mut self, value: impl AsRef<str>) {
244        unsafe {
245            let v = value.as_ref();
246            ffi::gst_id_str_set_with_len(
247                self.to_glib_none_mut().0,
248                v.as_ptr() as *const c_char,
249                v.len(),
250            );
251        }
252    }
253}
254
255impl Default for IdStr {
256    fn default() -> Self {
257        Self::new()
258    }
259}
260
261impl Deref for IdStr {
262    type Target = GStr;
263
264    fn deref(&self) -> &Self::Target {
265        self.as_gstr()
266    }
267}
268
269impl AsRef<str> for IdStr {
270    #[inline]
271    fn as_ref(&self) -> &str {
272        self.as_str()
273    }
274}
275
276impl AsRef<IdStr> for IdStr {
277    #[inline]
278    fn as_ref(&self) -> &IdStr {
279        self
280    }
281}
282
283impl AsRef<GStr> for IdStr {
284    #[inline]
285    fn as_ref(&self) -> &GStr {
286        self.as_gstr()
287    }
288}
289
290impl AsRef<CStr> for IdStr {
291    #[inline]
292    fn as_ref(&self) -> &CStr {
293        self.as_cstr()
294    }
295}
296
297impl From<&str> for IdStr {
298    #[inline]
299    fn from(value: &str) -> IdStr {
300        skip_assert_initialized!();
301        let mut ret = IdStr::new();
302        ret.set(value);
303
304        ret
305    }
306}
307
308impl From<&String> for IdStr {
309    #[inline]
310    fn from(value: &String) -> IdStr {
311        skip_assert_initialized!();
312        let mut ret = IdStr::new();
313        ret.set(value);
314
315        ret
316    }
317}
318
319impl From<String> for IdStr {
320    #[inline]
321    fn from(value: String) -> IdStr {
322        skip_assert_initialized!();
323        let mut ret = IdStr::new();
324        ret.set(&value);
325
326        ret
327    }
328}
329
330impl From<&GStr> for IdStr {
331    #[inline]
332    fn from(value: &GStr) -> IdStr {
333        // assert checked in new()
334        skip_assert_initialized!();
335        let mut ret = IdStr::new();
336        ret.set(value);
337
338        ret
339    }
340}
341
342impl From<&GString> for IdStr {
343    #[inline]
344    fn from(value: &GString) -> IdStr {
345        skip_assert_initialized!();
346        let mut ret = IdStr::new();
347        ret.set(value);
348
349        ret
350    }
351}
352
353impl From<GString> for IdStr {
354    #[inline]
355    fn from(value: GString) -> IdStr {
356        skip_assert_initialized!();
357        let mut ret = IdStr::new();
358        ret.set(&value);
359
360        ret
361    }
362}
363
364impl fmt::Display for IdStr {
365    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366        f.write_str(self.as_gstr())
367    }
368}
369
370impl PartialOrd for IdStr {
371    #[inline]
372    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
373        Some(self.cmp(other))
374    }
375}
376
377impl PartialEq for IdStr {
378    #[inline]
379    fn eq(&self, other: &Self) -> bool {
380        self.is_equal(other)
381    }
382}
383
384impl PartialOrd<&IdStr> for IdStr {
385    #[inline]
386    fn partial_cmp(&self, other: &&IdStr) -> Option<cmp::Ordering> {
387        Some(self.cmp(*other))
388    }
389}
390
391impl PartialEq<&IdStr> for IdStr {
392    #[inline]
393    fn eq(&self, other: &&IdStr) -> bool {
394        self.is_equal(other)
395    }
396}
397
398impl Ord for IdStr {
399    #[inline]
400    fn cmp(&self, other: &Self) -> cmp::Ordering {
401        self.as_cstr().cmp(other.as_cstr())
402    }
403}
404
405impl Eq for IdStr {}
406
407impl PartialOrd<&GStr> for IdStr {
408    #[inline]
409    fn partial_cmp(&self, other: &&GStr) -> Option<cmp::Ordering> {
410        self.as_str().partial_cmp(*other)
411    }
412}
413
414impl PartialEq<&GStr> for IdStr {
415    #[inline]
416    fn eq(&self, other: &&GStr) -> bool {
417        self.is_equal_to_str(other)
418    }
419}
420
421impl PartialOrd<GStr> for IdStr {
422    #[inline]
423    fn partial_cmp(&self, other: &GStr) -> Option<cmp::Ordering> {
424        self.as_str().partial_cmp(other)
425    }
426}
427
428impl PartialEq<GStr> for IdStr {
429    #[inline]
430    fn eq(&self, other: &GStr) -> bool {
431        self.is_equal_to_str(other)
432    }
433}
434
435impl PartialOrd<IdStr> for &GStr {
436    #[inline]
437    fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
438        (*self).partial_cmp(other.as_gstr())
439    }
440}
441
442impl PartialEq<IdStr> for &GStr {
443    #[inline]
444    fn eq(&self, other: &IdStr) -> bool {
445        other.is_equal_to_str(self)
446    }
447}
448
449impl PartialOrd<IdStr> for GStr {
450    #[inline]
451    fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
452        self.partial_cmp(other.as_gstr())
453    }
454}
455
456impl PartialEq<IdStr> for GStr {
457    #[inline]
458    fn eq(&self, other: &IdStr) -> bool {
459        other.is_equal_to_str(self)
460    }
461}
462
463impl PartialOrd<&str> for IdStr {
464    #[inline]
465    fn partial_cmp(&self, other: &&str) -> Option<cmp::Ordering> {
466        self.as_gstr().partial_cmp(*other)
467    }
468}
469
470impl PartialEq<&str> for IdStr {
471    #[inline]
472    fn eq(&self, other: &&str) -> bool {
473        self.is_equal_to_str(*other)
474    }
475}
476
477impl PartialOrd<str> for IdStr {
478    #[inline]
479    fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
480        self.as_gstr().partial_cmp(other)
481    }
482}
483
484impl PartialEq<str> for IdStr {
485    #[inline]
486    fn eq(&self, other: &str) -> bool {
487        self.is_equal_to_str(other)
488    }
489}
490
491impl PartialOrd<IdStr> for &str {
492    #[inline]
493    fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
494        (*self).partial_cmp(other.as_gstr())
495    }
496}
497
498impl PartialEq<IdStr> for &str {
499    #[inline]
500    fn eq(&self, other: &IdStr) -> bool {
501        other.is_equal_to_str(self)
502    }
503}
504
505impl PartialOrd<IdStr> for str {
506    #[inline]
507    fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
508        self.partial_cmp(other.as_gstr())
509    }
510}
511
512impl PartialEq<IdStr> for str {
513    #[inline]
514    fn eq(&self, other: &IdStr) -> bool {
515        other.is_equal_to_str(self)
516    }
517}
518
519impl PartialOrd<GString> for IdStr {
520    #[inline]
521    fn partial_cmp(&self, other: &GString) -> Option<cmp::Ordering> {
522        self.as_gstr().partial_cmp(other)
523    }
524}
525
526impl PartialEq<GString> for IdStr {
527    #[inline]
528    fn eq(&self, other: &GString) -> bool {
529        self.is_equal_to_str(other)
530    }
531}
532
533impl PartialOrd<IdStr> for GString {
534    #[inline]
535    fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
536        self.partial_cmp(other.as_gstr())
537    }
538}
539
540impl PartialEq<IdStr> for GString {
541    #[inline]
542    fn eq(&self, other: &IdStr) -> bool {
543        other.is_equal_to_str(self)
544    }
545}
546
547impl PartialOrd<String> for IdStr {
548    #[inline]
549    fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
550        self.as_gstr().partial_cmp(other)
551    }
552}
553
554impl PartialEq<String> for IdStr {
555    #[inline]
556    fn eq(&self, other: &String) -> bool {
557        self.is_equal_to_str(other)
558    }
559}
560
561impl PartialOrd<IdStr> for String {
562    #[inline]
563    fn partial_cmp(&self, other: &IdStr) -> Option<cmp::Ordering> {
564        self.partial_cmp(other.as_gstr())
565    }
566}
567
568impl PartialEq<IdStr> for String {
569    #[inline]
570    fn eq(&self, other: &IdStr) -> bool {
571        other.is_equal_to_str(self)
572    }
573}
574
575impl Hash for IdStr {
576    fn hash<H: Hasher>(&self, state: &mut H) {
577        self.as_gstr().hash(state)
578    }
579}
580
581unsafe impl Send for IdStr {}
582unsafe impl Sync for IdStr {}
583
584// Tests are mutualised between this implementation and the one in id_str_compat
585// See gstreamer/id_str/mod.rs