gstreamer/
structure.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{
4    borrow::{Borrow, BorrowMut, ToOwned},
5    fmt,
6    marker::PhantomData,
7    mem,
8    ops::{Deref, DerefMut},
9    ptr, str,
10};
11
12use glib::{
13    prelude::*,
14    translate::*,
15    value::{FromValue, SendValue, Value},
16    IntoGStr,
17};
18
19use crate::{ffi, Fraction};
20
21#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
22pub enum GetError<E: std::error::Error> {
23    #[error("GetError: Structure field with name {name} not found")]
24    FieldNotFound { name: &'static str },
25    #[error("GetError: Structure field with name {name} not retrieved")]
26    ValueGetError {
27        name: &'static str,
28        #[source]
29        error: E,
30    },
31}
32
33impl<E: std::error::Error> GetError<E> {
34    fn new_field_not_found(name: &'static str) -> Self {
35        skip_assert_initialized!();
36        GetError::FieldNotFound { name }
37    }
38
39    fn from_value_get_error(name: &'static str, error: E) -> Self {
40        skip_assert_initialized!();
41        GetError::ValueGetError { name, error }
42    }
43}
44
45#[doc(alias = "GstStructure")]
46#[repr(transparent)]
47pub struct Structure(ptr::NonNull<ffi::GstStructure>);
48unsafe impl Send for Structure {}
49unsafe impl Sync for Structure {}
50
51impl Structure {
52    #[doc(alias = "gst_structure_new")]
53    pub fn builder(name: impl IntoGStr) -> Builder {
54        skip_assert_initialized!();
55        Builder::new(name)
56    }
57
58    #[doc(alias = "gst_structure_new_empty")]
59    pub fn new_empty(name: impl IntoGStr) -> Structure {
60        assert_initialized_main_thread!();
61        unsafe {
62            let ptr = name.run_with_gstr(|name| ffi::gst_structure_new_empty(name.as_ptr()));
63            debug_assert!(!ptr.is_null());
64            Structure(ptr::NonNull::new_unchecked(ptr))
65        }
66    }
67
68    #[allow(clippy::should_implement_trait)]
69    pub fn from_iter(
70        name: impl IntoGStr,
71        iter: impl IntoIterator<Item = (impl IntoGStr, SendValue)>,
72    ) -> Structure {
73        skip_assert_initialized!();
74        let mut structure = Structure::new_empty(name);
75
76        iter.into_iter()
77            .for_each(|(f, v)| structure.set_value(f, v));
78
79        structure
80    }
81}
82
83impl IntoGlibPtr<*mut ffi::GstStructure> for Structure {
84    #[inline]
85    unsafe fn into_glib_ptr(self) -> *mut ffi::GstStructure {
86        let s = mem::ManuallyDrop::new(self);
87        s.0.as_ptr()
88    }
89}
90
91impl Deref for Structure {
92    type Target = StructureRef;
93
94    #[inline]
95    fn deref(&self) -> &StructureRef {
96        unsafe { &*(self.0.as_ptr() as *const StructureRef) }
97    }
98}
99
100impl DerefMut for Structure {
101    #[inline]
102    fn deref_mut(&mut self) -> &mut StructureRef {
103        unsafe { &mut *(self.0.as_ptr() as *mut StructureRef) }
104    }
105}
106
107impl AsRef<StructureRef> for Structure {
108    #[inline]
109    fn as_ref(&self) -> &StructureRef {
110        self.deref()
111    }
112}
113
114impl AsMut<StructureRef> for Structure {
115    #[inline]
116    fn as_mut(&mut self) -> &mut StructureRef {
117        self.deref_mut()
118    }
119}
120
121impl Clone for Structure {
122    #[inline]
123    fn clone(&self) -> Self {
124        unsafe {
125            let ptr = ffi::gst_structure_copy(self.0.as_ref());
126            debug_assert!(!ptr.is_null());
127            Structure(ptr::NonNull::new_unchecked(ptr))
128        }
129    }
130}
131
132impl Drop for Structure {
133    #[inline]
134    fn drop(&mut self) {
135        unsafe { ffi::gst_structure_free(self.0.as_mut()) }
136    }
137}
138
139impl fmt::Debug for Structure {
140    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
141        f.debug_tuple("Structure").field(self.as_ref()).finish()
142    }
143}
144
145impl fmt::Display for Structure {
146    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
147        // Need to make sure to not call ToString::to_string() here, which
148        // we have because of the Display impl. We need StructureRef::to_string()
149        f.write_str(&StructureRef::to_string(self.as_ref()))
150    }
151}
152
153impl PartialEq for Structure {
154    fn eq(&self, other: &Structure) -> bool {
155        StructureRef::eq(self, other)
156    }
157}
158
159impl Eq for Structure {}
160
161impl PartialEq<StructureRef> for Structure {
162    fn eq(&self, other: &StructureRef) -> bool {
163        StructureRef::eq(self, other)
164    }
165}
166
167impl PartialEq<Structure> for StructureRef {
168    fn eq(&self, other: &Structure) -> bool {
169        StructureRef::eq(other, self)
170    }
171}
172
173impl str::FromStr for Structure {
174    type Err = glib::BoolError;
175
176    #[doc(alias = "gst_structure_from_string")]
177    fn from_str(s: &str) -> Result<Self, Self::Err> {
178        assert_initialized_main_thread!();
179        unsafe {
180            let structure =
181                s.run_with_gstr(|s| ffi::gst_structure_from_string(s.as_ptr(), ptr::null_mut()));
182            if structure.is_null() {
183                Err(glib::bool_error!("Failed to parse structure from string"))
184            } else {
185                Ok(Self(ptr::NonNull::new_unchecked(structure)))
186            }
187        }
188    }
189}
190
191impl Borrow<StructureRef> for Structure {
192    #[inline]
193    fn borrow(&self) -> &StructureRef {
194        self.as_ref()
195    }
196}
197
198impl BorrowMut<StructureRef> for Structure {
199    #[inline]
200    fn borrow_mut(&mut self) -> &mut StructureRef {
201        self.as_mut()
202    }
203}
204
205impl ToOwned for StructureRef {
206    type Owned = Structure;
207
208    fn to_owned(&self) -> Structure {
209        unsafe {
210            let ptr = ffi::gst_structure_copy(&self.0);
211            debug_assert!(!ptr.is_null());
212            Structure(ptr::NonNull::new_unchecked(ptr))
213        }
214    }
215}
216
217impl glib::types::StaticType for Structure {
218    #[inline]
219    fn static_type() -> glib::types::Type {
220        unsafe { from_glib(ffi::gst_structure_get_type()) }
221    }
222}
223
224impl<'a> ToGlibPtr<'a, *const ffi::GstStructure> for Structure {
225    type Storage = PhantomData<&'a Self>;
226
227    #[inline]
228    fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GstStructure, Self> {
229        unsafe { Stash(self.0.as_ref(), PhantomData) }
230    }
231
232    #[inline]
233    fn to_glib_full(&self) -> *const ffi::GstStructure {
234        unsafe { ffi::gst_structure_copy(self.0.as_ref()) }
235    }
236}
237
238impl<'a> ToGlibPtr<'a, *mut ffi::GstStructure> for Structure {
239    type Storage = PhantomData<&'a Self>;
240
241    #[inline]
242    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GstStructure, Self> {
243        unsafe {
244            Stash(
245                self.0.as_ref() as *const ffi::GstStructure as *mut ffi::GstStructure,
246                PhantomData,
247            )
248        }
249    }
250
251    #[inline]
252    fn to_glib_full(&self) -> *mut ffi::GstStructure {
253        unsafe { ffi::gst_structure_copy(self.0.as_ref()) }
254    }
255}
256
257impl<'a> ToGlibPtrMut<'a, *mut ffi::GstStructure> for Structure {
258    type Storage = PhantomData<&'a mut Self>;
259
260    #[inline]
261    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GstStructure, Self> {
262        unsafe { StashMut(self.0.as_mut(), PhantomData) }
263    }
264}
265
266impl FromGlibPtrNone<*const ffi::GstStructure> for Structure {
267    #[inline]
268    unsafe fn from_glib_none(ptr: *const ffi::GstStructure) -> Self {
269        debug_assert!(!ptr.is_null());
270        let ptr = ffi::gst_structure_copy(ptr);
271        debug_assert!(!ptr.is_null());
272        Structure(ptr::NonNull::new_unchecked(ptr))
273    }
274}
275
276impl FromGlibPtrNone<*mut ffi::GstStructure> for Structure {
277    #[inline]
278    unsafe fn from_glib_none(ptr: *mut ffi::GstStructure) -> Self {
279        debug_assert!(!ptr.is_null());
280        let ptr = ffi::gst_structure_copy(ptr);
281        debug_assert!(!ptr.is_null());
282        Structure(ptr::NonNull::new_unchecked(ptr))
283    }
284}
285
286impl FromGlibPtrFull<*const ffi::GstStructure> for Structure {
287    #[inline]
288    unsafe fn from_glib_full(ptr: *const ffi::GstStructure) -> Self {
289        debug_assert!(!ptr.is_null());
290        Structure(ptr::NonNull::new_unchecked(ptr as *mut ffi::GstStructure))
291    }
292}
293
294impl FromGlibPtrFull<*mut ffi::GstStructure> for Structure {
295    #[inline]
296    unsafe fn from_glib_full(ptr: *mut ffi::GstStructure) -> Self {
297        debug_assert!(!ptr.is_null());
298        Structure(ptr::NonNull::new_unchecked(ptr))
299    }
300}
301
302impl FromGlibPtrBorrow<*const ffi::GstStructure> for Structure {
303    #[inline]
304    unsafe fn from_glib_borrow(ptr: *const ffi::GstStructure) -> Borrowed<Self> {
305        Borrowed::new(from_glib_full(ptr))
306    }
307}
308
309impl FromGlibPtrBorrow<*mut ffi::GstStructure> for Structure {
310    #[inline]
311    unsafe fn from_glib_borrow(ptr: *mut ffi::GstStructure) -> Borrowed<Self> {
312        Borrowed::new(from_glib_full(ptr))
313    }
314}
315
316impl glib::value::ValueType for Structure {
317    type Type = Self;
318}
319
320impl glib::value::ValueTypeOptional for Structure {}
321
322unsafe impl<'a> glib::value::FromValue<'a> for Structure {
323    type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
324
325    unsafe fn from_value(value: &'a glib::Value) -> Self {
326        skip_assert_initialized!();
327        from_glib_none(
328            glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *mut ffi::GstStructure
329        )
330    }
331}
332
333impl glib::value::ToValue for Structure {
334    fn to_value(&self) -> glib::Value {
335        let mut value = glib::Value::for_value_type::<Self>();
336        unsafe {
337            glib::gobject_ffi::g_value_set_boxed(
338                value.to_glib_none_mut().0,
339                glib::translate::ToGlibPtr::<*const ffi::GstStructure>::to_glib_none(self).0
340                    as *mut _,
341            )
342        }
343        value
344    }
345
346    fn value_type(&self) -> glib::Type {
347        Self::static_type()
348    }
349}
350
351impl glib::value::ToValueOptional for Structure {
352    fn to_value_optional(s: Option<&Self>) -> glib::Value {
353        skip_assert_initialized!();
354        let mut value = glib::Value::for_value_type::<Self>();
355        unsafe {
356            glib::gobject_ffi::g_value_set_boxed(
357                value.to_glib_none_mut().0,
358                glib::translate::ToGlibPtr::<*const ffi::GstStructure>::to_glib_none(&s).0
359                    as *mut _,
360            )
361        }
362        value
363    }
364}
365
366impl From<Structure> for glib::Value {
367    fn from(v: Structure) -> glib::Value {
368        skip_assert_initialized!();
369        let mut value = glib::Value::for_value_type::<Structure>();
370        unsafe {
371            glib::gobject_ffi::g_value_take_boxed(
372                value.to_glib_none_mut().0,
373                glib::translate::IntoGlibPtr::<*mut ffi::GstStructure>::into_glib_ptr(v) as *mut _,
374            )
375        }
376        value
377    }
378}
379
380impl GlibPtrDefault for Structure {
381    type GlibType = *mut ffi::GstStructure;
382}
383
384unsafe impl TransparentPtrType for Structure {}
385
386#[repr(transparent)]
387#[doc(alias = "GstStructure")]
388pub struct StructureRef(ffi::GstStructure);
389
390unsafe impl Send for StructureRef {}
391unsafe impl Sync for StructureRef {}
392
393impl StructureRef {
394    #[inline]
395    pub unsafe fn from_glib_borrow<'a>(ptr: *const ffi::GstStructure) -> &'a StructureRef {
396        debug_assert!(!ptr.is_null());
397
398        &*(ptr as *mut StructureRef)
399    }
400
401    #[inline]
402    pub unsafe fn from_glib_borrow_mut<'a>(ptr: *mut ffi::GstStructure) -> &'a mut StructureRef {
403        debug_assert!(!ptr.is_null());
404
405        &mut *(ptr as *mut StructureRef)
406    }
407
408    #[inline]
409    pub fn as_ptr(&self) -> *const ffi::GstStructure {
410        self as *const Self as *const ffi::GstStructure
411    }
412
413    #[inline]
414    pub fn as_mut_ptr(&self) -> *mut ffi::GstStructure {
415        self as *const Self as *mut ffi::GstStructure
416    }
417
418    #[doc(alias = "gst_structure_get")]
419    pub fn get<'a, T: FromValue<'a>>(
420        &'a self,
421        name: impl IntoGStr,
422    ) -> Result<T, GetError<<<T as FromValue<'a>>::Checker as glib::value::ValueTypeChecker>::Error>>
423    {
424        let name = glib::Quark::from_str(name);
425        self.get_by_quark(name)
426    }
427
428    #[doc(alias = "gst_structure_get")]
429    pub fn get_optional<'a, T: FromValue<'a>>(
430        &'a self,
431        name: impl IntoGStr,
432    ) -> Result<
433        Option<T>,
434        GetError<<<T as FromValue<'a>>::Checker as glib::value::ValueTypeChecker>::Error>,
435    > {
436        let name = glib::Quark::from_str(name);
437        self.get_optional_by_quark(name)
438    }
439
440    #[doc(alias = "get_value")]
441    #[doc(alias = "gst_structure_get_value")]
442    pub fn value(
443        &self,
444        name: impl IntoGStr,
445    ) -> Result<&SendValue, GetError<std::convert::Infallible>> {
446        let name = glib::Quark::from_str(name);
447        self.value_by_quark(name)
448    }
449
450    #[doc(alias = "gst_structure_id_get")]
451    pub fn get_by_quark<'a, T: FromValue<'a>>(
452        &'a self,
453        name: glib::Quark,
454    ) -> Result<T, GetError<<<T as FromValue<'a>>::Checker as glib::value::ValueTypeChecker>::Error>>
455    {
456        self.value_by_quark(name)
457            .map_err(|err| match err {
458                GetError::FieldNotFound { name } => GetError::FieldNotFound { name },
459                _ => unreachable!(),
460            })?
461            .get()
462            .map_err(|err| GetError::from_value_get_error(name.as_str(), err))
463    }
464
465    #[doc(alias = "gst_structure_id_get")]
466    pub fn get_optional_by_quark<'a, T: FromValue<'a>>(
467        &'a self,
468        name: glib::Quark,
469    ) -> Result<
470        Option<T>,
471        GetError<<<T as FromValue<'a>>::Checker as glib::value::ValueTypeChecker>::Error>,
472    > {
473        self.value_by_quark(name)
474            .ok()
475            .map(|v| v.get())
476            .transpose()
477            .map_err(|err| GetError::from_value_get_error(name.as_str(), err))
478    }
479
480    #[doc(alias = "gst_structure_id_get_value")]
481    pub fn value_by_quark(
482        &self,
483        name: glib::Quark,
484    ) -> Result<&SendValue, GetError<std::convert::Infallible>> {
485        unsafe {
486            let value = ffi::gst_structure_id_get_value(&self.0, name.into_glib());
487
488            if value.is_null() {
489                return Err(GetError::new_field_not_found(name.as_str()));
490            }
491
492            Ok(&*(value as *const SendValue))
493        }
494    }
495
496    // rustdoc-stripper-ignore-next
497    /// Sets field `name` to the given value `value`.
498    ///
499    /// Overrides any default or previously defined value for `name`.
500    #[doc(alias = "gst_structure_set")]
501    pub fn set(&mut self, name: impl IntoGStr, value: impl Into<glib::Value> + Send) {
502        let value = glib::SendValue::from_owned(value);
503        self.set_value(name, value);
504    }
505
506    // rustdoc-stripper-ignore-next
507    /// Sets field `name` to the given `value` if the `predicate` evaluates to `true`.
508    ///
509    /// This has no effect if the `predicate` evaluates to `false`,
510    /// i.e. default or previous value for `name` is kept.
511    #[doc(alias = "gst_structure_set")]
512    pub fn set_if(
513        &mut self,
514        name: impl IntoGStr,
515        value: impl Into<glib::Value> + Send,
516        predicate: bool,
517    ) {
518        if predicate {
519            self.set(name, value);
520        }
521    }
522
523    // rustdoc-stripper-ignore-next
524    /// Sets field `name` to the given inner value if `value` is `Some`.
525    ///
526    /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept.
527    #[doc(alias = "gst_structure_set")]
528    pub fn set_if_some(
529        &mut self,
530        name: impl IntoGStr,
531        value: Option<impl Into<glib::Value> + Send>,
532    ) {
533        if let Some(value) = value {
534            self.set(name, value);
535        }
536    }
537
538    // rustdoc-stripper-ignore-next
539    /// Sets field `name` using the given `ValueType` `V` built from `iter`'s the `Item`s.
540    ///
541    /// Overrides any default or previously defined value for `name`.
542    #[inline]
543    pub fn set_from_iter<V: ValueType + Into<Value> + FromIterator<SendValue> + Send>(
544        &mut self,
545        name: impl IntoGStr,
546        iter: impl IntoIterator<Item = impl ToSendValue>,
547    ) {
548        let iter = iter.into_iter().map(|item| item.to_send_value());
549        self.set(name, V::from_iter(iter));
550    }
551
552    // rustdoc-stripper-ignore-next
553    /// Sets field `name` using the given `ValueType` `V` built from `iter`'s Item`s,
554    /// if `iter` is not empty.
555    ///
556    /// This has no effect if `iter` is empty, i.e. previous value for `name` is unchanged.
557    #[inline]
558    pub fn set_if_not_empty<V: ValueType + Into<Value> + FromIterator<SendValue> + Send>(
559        &mut self,
560        name: impl IntoGStr,
561        iter: impl IntoIterator<Item = impl ToSendValue>,
562    ) {
563        let mut iter = iter.into_iter().peekable();
564        if iter.peek().is_some() {
565            let iter = iter.map(|item| item.to_send_value());
566            self.set(name, V::from_iter(iter));
567        }
568    }
569
570    // rustdoc-stripper-ignore-next
571    /// Sets field `name` to the given value `value`.
572    ///
573    /// Overrides any default or previously defined value for `name`.
574    #[doc(alias = "gst_structure_set_value")]
575    pub fn set_value(&mut self, name: impl IntoGStr, value: SendValue) {
576        unsafe {
577            name.run_with_gstr(|name| {
578                ffi::gst_structure_take_value(&mut self.0, name.as_ptr(), &mut value.into_raw())
579            });
580        }
581    }
582
583    // rustdoc-stripper-ignore-next
584    /// Sets field `name` to the given `value` if the `predicate` evaluates to `true`.
585    ///
586    /// This has no effect if the `predicate` evaluates to `false`,
587    /// i.e. default or previous value for `name` is kept.
588    #[doc(alias = "gst_structure_set_value")]
589    pub fn set_value_if(&mut self, name: impl IntoGStr, value: SendValue, predicate: bool) {
590        if predicate {
591            self.set_value(name, value);
592        }
593    }
594
595    // rustdoc-stripper-ignore-next
596    /// Sets field `name` to the given inner value if `value` is `Some`.
597    ///
598    /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept.
599    #[doc(alias = "gst_structure_set_value")]
600    pub fn set_value_if_some(&mut self, name: impl IntoGStr, value: Option<SendValue>) {
601        if let Some(value) = value {
602            self.set_value(name, value);
603        }
604    }
605
606    #[doc(alias = "gst_structure_id_set")]
607    pub fn set_by_quark(&mut self, name: glib::Quark, value: impl Into<glib::Value> + Send) {
608        let value = glib::SendValue::from_owned(value);
609        self.set_value_by_quark(name, value);
610    }
611
612    #[doc(alias = "gst_structure_id_set")]
613    pub fn set_by_quark_if_some(
614        &mut self,
615        name: glib::Quark,
616        value: Option<impl Into<glib::Value> + Send>,
617    ) {
618        if let Some(value) = value {
619            self.set_by_quark(name, value);
620        }
621    }
622
623    #[doc(alias = "gst_structure_id_set_value")]
624    pub fn set_value_by_quark(&mut self, name: glib::Quark, value: SendValue) {
625        unsafe {
626            ffi::gst_structure_id_take_value(&mut self.0, name.into_glib(), &mut value.into_raw());
627        }
628    }
629
630    #[doc(alias = "gst_structure_id_set_value")]
631    pub fn set_value_by_quark_if_some(&mut self, name: glib::Quark, value: Option<SendValue>) {
632        if let Some(value) = value {
633            self.set_value_by_quark(name, value);
634        }
635    }
636
637    #[doc(alias = "get_name")]
638    #[doc(alias = "gst_structure_get_name")]
639    pub fn name<'a>(&self) -> &'a glib::GStr {
640        unsafe {
641            let name = ffi::gst_structure_get_name(&self.0);
642            // Ensure the name is static whatever the GStreamer version being used.
643            glib::GStr::from_ptr(glib::ffi::g_intern_string(name))
644        }
645    }
646
647    #[doc(alias = "gst_structure_get_name_id")]
648    pub fn name_quark(&self) -> glib::Quark {
649        unsafe { from_glib(ffi::gst_structure_get_name_id(&self.0)) }
650    }
651
652    #[doc(alias = "gst_structure_set_name")]
653    pub fn set_name(&mut self, name: impl IntoGStr) {
654        unsafe {
655            name.run_with_gstr(|name| ffi::gst_structure_set_name(&mut self.0, name.as_ptr()))
656        }
657    }
658
659    #[doc(alias = "gst_structure_set_name")]
660    pub fn set_name_if_some(&mut self, name: Option<impl IntoGStr>) {
661        if let Some(name) = name {
662            self.set_name(name);
663        }
664    }
665
666    #[doc(alias = "gst_structure_has_name")]
667    pub fn has_name(&self, name: &str) -> bool {
668        self.name() == name
669    }
670
671    #[doc(alias = "gst_structure_has_field")]
672    pub fn has_field(&self, field: impl IntoGStr) -> bool {
673        unsafe {
674            field.run_with_gstr(|field| {
675                from_glib(ffi::gst_structure_has_field(&self.0, field.as_ptr()))
676            })
677        }
678    }
679
680    #[doc(alias = "gst_structure_has_field_typed")]
681    pub fn has_field_with_type(&self, field: impl IntoGStr, type_: glib::Type) -> bool {
682        unsafe {
683            field.run_with_gstr(|field| {
684                from_glib(ffi::gst_structure_has_field_typed(
685                    &self.0,
686                    field.as_ptr(),
687                    type_.into_glib(),
688                ))
689            })
690        }
691    }
692
693    #[doc(alias = "gst_structure_id_has_field")]
694    pub fn has_field_by_quark(&self, field: glib::Quark) -> bool {
695        unsafe { from_glib(ffi::gst_structure_id_has_field(&self.0, field.into_glib())) }
696    }
697
698    #[doc(alias = "gst_structure_id_has_field_typed")]
699    pub fn has_field_with_type_by_quark(&self, field: glib::Quark, type_: glib::Type) -> bool {
700        unsafe {
701            from_glib(ffi::gst_structure_id_has_field_typed(
702                &self.0,
703                field.into_glib(),
704                type_.into_glib(),
705            ))
706        }
707    }
708
709    #[doc(alias = "gst_structure_remove_field")]
710    pub fn remove_field(&mut self, field: impl IntoGStr) {
711        unsafe {
712            field.run_with_gstr(|field| {
713                ffi::gst_structure_remove_field(&mut self.0, field.as_ptr())
714            });
715        }
716    }
717
718    #[doc(alias = "gst_structure_remove_fields")]
719    pub fn remove_fields(&mut self, fields: impl IntoIterator<Item = impl IntoGStr>) {
720        for f in fields.into_iter() {
721            self.remove_field(f)
722        }
723    }
724
725    #[doc(alias = "gst_structure_remove_all_fields")]
726    pub fn remove_all_fields(&mut self) {
727        unsafe {
728            ffi::gst_structure_remove_all_fields(&mut self.0);
729        }
730    }
731
732    pub fn fields(&self) -> FieldIterator {
733        FieldIterator::new(self)
734    }
735
736    pub fn iter(&self) -> Iter {
737        Iter::new(self)
738    }
739
740    #[doc(alias = "get_nth_field_name")]
741    #[doc(alias = "gst_structure_nth_field_name")]
742    pub fn nth_field_name<'a>(&self, idx: usize) -> Option<&'a glib::GStr> {
743        if idx >= self.n_fields() {
744            return None;
745        }
746
747        unsafe {
748            let field_name = ffi::gst_structure_nth_field_name(&self.0, idx as u32);
749            debug_assert!(!field_name.is_null());
750
751            // Ensure the name is static whatever the GStreamer version being used.
752            Some(glib::GStr::from_ptr(glib::ffi::g_intern_string(field_name)))
753        }
754    }
755
756    #[doc(alias = "gst_structure_n_fields")]
757    pub fn n_fields(&self) -> usize {
758        unsafe { ffi::gst_structure_n_fields(&self.0) as usize }
759    }
760
761    pub fn len(&self) -> usize {
762        self.n_fields()
763    }
764
765    pub fn is_empty(&self) -> bool {
766        self.n_fields() == 0
767    }
768
769    #[doc(alias = "gst_structure_can_intersect")]
770    pub fn can_intersect(&self, other: &StructureRef) -> bool {
771        unsafe { from_glib(ffi::gst_structure_can_intersect(&self.0, &other.0)) }
772    }
773
774    #[doc(alias = "gst_structure_intersect")]
775    pub fn intersect(&self, other: &StructureRef) -> Option<Structure> {
776        unsafe { from_glib_full(ffi::gst_structure_intersect(&self.0, &other.0)) }
777    }
778
779    #[doc(alias = "gst_structure_is_subset")]
780    pub fn is_subset(&self, superset: &StructureRef) -> bool {
781        unsafe { from_glib(ffi::gst_structure_is_subset(&self.0, &superset.0)) }
782    }
783
784    #[doc(alias = "gst_structure_fixate")]
785    pub fn fixate(&mut self) {
786        unsafe { ffi::gst_structure_fixate(&mut self.0) }
787    }
788
789    #[doc(alias = "gst_structure_fixate_field")]
790    pub fn fixate_field(&mut self, name: impl IntoGStr) -> bool {
791        unsafe {
792            name.run_with_gstr(|name| {
793                from_glib(ffi::gst_structure_fixate_field(&mut self.0, name.as_ptr()))
794            })
795        }
796    }
797
798    #[doc(alias = "gst_structure_fixate_field_boolean")]
799    pub fn fixate_field_bool(&mut self, name: impl IntoGStr, target: bool) -> bool {
800        unsafe {
801            name.run_with_gstr(|name| {
802                from_glib(ffi::gst_structure_fixate_field_boolean(
803                    &mut self.0,
804                    name.as_ptr(),
805                    target.into_glib(),
806                ))
807            })
808        }
809    }
810
811    #[doc(alias = "gst_structure_fixate_field_string")]
812    pub fn fixate_field_str(&mut self, name: impl IntoGStr, target: impl IntoGStr) -> bool {
813        unsafe {
814            name.run_with_gstr(|name| {
815                target.run_with_gstr(|target| {
816                    from_glib(ffi::gst_structure_fixate_field_string(
817                        &mut self.0,
818                        name.as_ptr(),
819                        target.as_ptr(),
820                    ))
821                })
822            })
823        }
824    }
825
826    #[doc(alias = "gst_structure_fixate_field_nearest_double")]
827    pub fn fixate_field_nearest_double(&mut self, name: impl IntoGStr, target: f64) -> bool {
828        unsafe {
829            name.run_with_gstr(|name| {
830                from_glib(ffi::gst_structure_fixate_field_nearest_double(
831                    &mut self.0,
832                    name.as_ptr(),
833                    target,
834                ))
835            })
836        }
837    }
838
839    #[doc(alias = "gst_structure_fixate_field_nearest_fraction")]
840    pub fn fixate_field_nearest_fraction(
841        &mut self,
842        name: impl IntoGStr,
843        target: impl Into<Fraction>,
844    ) -> bool {
845        skip_assert_initialized!();
846
847        let target = target.into();
848        unsafe {
849            name.run_with_gstr(|name| {
850                from_glib(ffi::gst_structure_fixate_field_nearest_fraction(
851                    &mut self.0,
852                    name.as_ptr(),
853                    target.numer(),
854                    target.denom(),
855                ))
856            })
857        }
858    }
859
860    #[doc(alias = "gst_structure_fixate_field_nearest_int")]
861    pub fn fixate_field_nearest_int(&mut self, name: impl IntoGStr, target: i32) -> bool {
862        unsafe {
863            name.run_with_gstr(|name| {
864                from_glib(ffi::gst_structure_fixate_field_nearest_int(
865                    &mut self.0,
866                    name.as_ptr(),
867                    target,
868                ))
869            })
870        }
871    }
872
873    #[cfg(feature = "v1_20")]
874    #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
875    #[doc(alias = "gst_structure_serialize")]
876    pub fn serialize(&self, flags: crate::SerializeFlags) -> glib::GString {
877        unsafe { from_glib_full(ffi::gst_structure_serialize(&self.0, flags.into_glib())) }
878    }
879
880    #[cfg(feature = "v1_24")]
881    #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
882    #[doc(alias = "gst_structure_serialize")]
883    #[doc(alias = "gst_structure_serialize_full")]
884    pub fn serialize_strict(
885        &self,
886        flags: crate::SerializeFlags,
887    ) -> Result<glib::GString, glib::BoolError> {
888        unsafe {
889            let res = ffi::gst_structure_serialize_full(
890                &self.0,
891                flags.into_glib() | ffi::GST_SERIALIZE_FLAG_STRICT,
892            );
893            if res.is_null() {
894                Err(glib::bool_error!("Failed to serialize structure to string"))
895            } else {
896                Ok(from_glib_full(res))
897            }
898        }
899    }
900
901    #[doc(alias = "gst_structure_foreach")]
902    pub fn foreach<F: FnMut(glib::Quark, &glib::Value) -> std::ops::ControlFlow<()>>(
903        &self,
904        mut func: F,
905    ) -> bool {
906        unsafe {
907            unsafe extern "C" fn trampoline<
908                F: FnMut(glib::Quark, &glib::Value) -> std::ops::ControlFlow<()>,
909            >(
910                quark: glib::ffi::GQuark,
911                value: *const glib::gobject_ffi::GValue,
912                user_data: glib::ffi::gpointer,
913            ) -> glib::ffi::gboolean {
914                let func = &mut *(user_data as *mut F);
915                let res = func(from_glib(quark), &*(value as *const glib::Value));
916
917                matches!(res, std::ops::ControlFlow::Continue(_)).into_glib()
918            }
919            let func = &mut func as *mut F;
920            from_glib(ffi::gst_structure_foreach(
921                self.as_ptr(),
922                Some(trampoline::<F>),
923                func as glib::ffi::gpointer,
924            ))
925        }
926    }
927
928    #[doc(alias = "gst_structure_map_in_place")]
929    pub fn map_in_place<F: FnMut(glib::Quark, &mut glib::Value) -> std::ops::ControlFlow<()>>(
930        &mut self,
931        mut func: F,
932    ) -> bool {
933        unsafe {
934            unsafe extern "C" fn trampoline<
935                F: FnMut(glib::Quark, &mut glib::Value) -> std::ops::ControlFlow<()>,
936            >(
937                quark: glib::ffi::GQuark,
938                value: *mut glib::gobject_ffi::GValue,
939                user_data: glib::ffi::gpointer,
940            ) -> glib::ffi::gboolean {
941                let func = &mut *(user_data as *mut F);
942                let res = func(from_glib(quark), &mut *(value as *mut glib::Value));
943
944                matches!(res, std::ops::ControlFlow::Continue(_)).into_glib()
945            }
946            let func = &mut func as *mut F;
947            from_glib(ffi::gst_structure_map_in_place(
948                self.as_mut_ptr(),
949                Some(trampoline::<F>),
950                func as glib::ffi::gpointer,
951            ))
952        }
953    }
954
955    #[doc(alias = "gst_structure_filter_and_map_in_place")]
956    pub fn filter_map_in_place<F: FnMut(glib::Quark, glib::Value) -> Option<glib::Value>>(
957        &mut self,
958        mut func: F,
959    ) {
960        unsafe {
961            unsafe extern "C" fn trampoline<
962                F: FnMut(glib::Quark, glib::Value) -> Option<glib::Value>,
963            >(
964                quark: glib::ffi::GQuark,
965                value: *mut glib::gobject_ffi::GValue,
966                user_data: glib::ffi::gpointer,
967            ) -> glib::ffi::gboolean {
968                let func = &mut *(user_data as *mut F);
969
970                let v = mem::replace(
971                    &mut *(value as *mut glib::Value),
972                    glib::Value::uninitialized(),
973                );
974                match func(from_glib(quark), v) {
975                    None => glib::ffi::GFALSE,
976                    Some(v) => {
977                        *value = v.into_raw();
978                        glib::ffi::GTRUE
979                    }
980                }
981            }
982
983            let func = &mut func as *mut F;
984            ffi::gst_structure_filter_and_map_in_place(
985                self.as_mut_ptr(),
986                Some(trampoline::<F>),
987                func as glib::ffi::gpointer,
988            );
989        }
990    }
991}
992
993impl fmt::Display for StructureRef {
994    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
995        let s = unsafe { glib::GString::from_glib_full(ffi::gst_structure_to_string(&self.0)) };
996        f.write_str(&s)
997    }
998}
999
1000impl fmt::Debug for StructureRef {
1001    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1002        let mut debug = f.debug_struct(self.name());
1003
1004        for (id, field) in self.iter() {
1005            if field.type_() == Structure::static_type() {
1006                let s = field.get::<Structure>().unwrap();
1007                debug.field(id, &s);
1008            } else if field.type_() == crate::Array::static_type() {
1009                let arr = field.get::<crate::Array>().unwrap();
1010                debug.field(id, &arr);
1011            } else if field.type_() == crate::List::static_type() {
1012                let list = field.get::<crate::List>().unwrap();
1013                debug.field(id, &list);
1014            } else {
1015                debug.field(id, &field);
1016            }
1017        }
1018
1019        debug.finish()
1020    }
1021}
1022
1023impl PartialEq for StructureRef {
1024    #[doc(alias = "gst_structure_is_equal")]
1025    fn eq(&self, other: &StructureRef) -> bool {
1026        unsafe { from_glib(ffi::gst_structure_is_equal(&self.0, &other.0)) }
1027    }
1028}
1029
1030impl Eq for StructureRef {}
1031
1032impl glib::types::StaticType for StructureRef {
1033    #[inline]
1034    fn static_type() -> glib::types::Type {
1035        unsafe { from_glib(ffi::gst_structure_get_type()) }
1036    }
1037}
1038
1039unsafe impl<'a> glib::value::FromValue<'a> for &'a StructureRef {
1040    type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
1041
1042    unsafe fn from_value(value: &'a glib::Value) -> Self {
1043        skip_assert_initialized!();
1044        &*(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const StructureRef)
1045    }
1046}
1047
1048impl glib::value::ToValue for StructureRef {
1049    fn to_value(&self) -> glib::Value {
1050        let mut value = glib::Value::for_value_type::<Structure>();
1051        unsafe {
1052            glib::gobject_ffi::g_value_set_boxed(
1053                value.to_glib_none_mut().0,
1054                self.as_ptr() as *mut _,
1055            )
1056        }
1057        value
1058    }
1059
1060    fn value_type(&self) -> glib::Type {
1061        Self::static_type()
1062    }
1063}
1064
1065impl glib::value::ToValueOptional for StructureRef {
1066    fn to_value_optional(s: Option<&Self>) -> glib::Value {
1067        skip_assert_initialized!();
1068        let mut value = glib::Value::for_value_type::<Structure>();
1069        unsafe {
1070            glib::gobject_ffi::g_value_set_boxed(
1071                value.to_glib_none_mut().0,
1072                s.map(|s| s.as_ptr()).unwrap_or(ptr::null()) as *mut _,
1073            )
1074        }
1075        value
1076    }
1077}
1078
1079#[derive(Debug)]
1080pub struct FieldIterator<'a> {
1081    structure: &'a StructureRef,
1082    idx: usize,
1083    n_fields: usize,
1084}
1085
1086impl<'a> FieldIterator<'a> {
1087    fn new(structure: &'a StructureRef) -> FieldIterator<'a> {
1088        skip_assert_initialized!();
1089        let n_fields = structure.n_fields();
1090
1091        FieldIterator {
1092            structure,
1093            idx: 0,
1094            n_fields,
1095        }
1096    }
1097}
1098
1099impl Iterator for FieldIterator<'_> {
1100    type Item = &'static glib::GStr;
1101
1102    fn next(&mut self) -> Option<Self::Item> {
1103        if self.idx >= self.n_fields {
1104            return None;
1105        }
1106
1107        // Safety: nth_field_name() ensures static lifetime for the returned string,
1108        // whatever the GStreamer version being used.
1109        let field_name = self.structure.nth_field_name(self.idx).unwrap();
1110        self.idx += 1;
1111
1112        Some(field_name)
1113    }
1114
1115    fn size_hint(&self) -> (usize, Option<usize>) {
1116        let remaining = self.n_fields - self.idx;
1117
1118        (remaining, Some(remaining))
1119    }
1120}
1121
1122impl DoubleEndedIterator for FieldIterator<'_> {
1123    fn next_back(&mut self) -> Option<Self::Item> {
1124        if self.idx == self.n_fields {
1125            return None;
1126        }
1127
1128        self.n_fields -= 1;
1129        // Safety: nth_field_name() ensures static lifetime for the returned string,
1130        // whatever the GStreamer version being used.
1131        Some(self.structure.nth_field_name(self.n_fields).unwrap())
1132    }
1133}
1134
1135impl ExactSizeIterator for FieldIterator<'_> {}
1136
1137impl std::iter::FusedIterator for FieldIterator<'_> {}
1138
1139#[derive(Debug)]
1140pub struct Iter<'a> {
1141    // Safety: FieldIterator ensures static lifetime for the returned Item,
1142    // whatever the GStreamer version being used.
1143    iter: FieldIterator<'a>,
1144}
1145
1146impl<'a> Iter<'a> {
1147    fn new(structure: &'a StructureRef) -> Iter<'a> {
1148        skip_assert_initialized!();
1149        Iter {
1150            iter: FieldIterator::new(structure),
1151        }
1152    }
1153}
1154
1155impl<'a> Iterator for Iter<'a> {
1156    type Item = (&'static glib::GStr, &'a SendValue);
1157
1158    fn next(&mut self) -> Option<Self::Item> {
1159        let f = self.iter.next()?;
1160        let v = self.iter.structure.value(f);
1161        Some((f, v.unwrap()))
1162    }
1163
1164    fn size_hint(&self) -> (usize, Option<usize>) {
1165        self.iter.size_hint()
1166    }
1167
1168    fn count(self) -> usize {
1169        self.iter.count()
1170    }
1171
1172    fn nth(&mut self, n: usize) -> Option<Self::Item> {
1173        let f = self.iter.nth(n)?;
1174        let v = self.iter.structure.value(f);
1175        Some((f, v.unwrap()))
1176    }
1177
1178    fn last(mut self) -> Option<Self::Item> {
1179        let structure = self.iter.structure;
1180        let f = self.iter.next_back()?;
1181        let v = structure.value(f);
1182        Some((f, v.unwrap()))
1183    }
1184}
1185
1186impl DoubleEndedIterator for Iter<'_> {
1187    fn next_back(&mut self) -> Option<Self::Item> {
1188        let f = self.iter.next_back()?;
1189        let v = self.iter.structure.value(f);
1190        Some((f, v.unwrap()))
1191    }
1192
1193    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
1194        let f = self.iter.nth_back(n)?;
1195        let v = self.iter.structure.value(f);
1196        Some((f, v.unwrap()))
1197    }
1198}
1199
1200impl ExactSizeIterator for Iter<'_> {}
1201
1202impl std::iter::FusedIterator for Iter<'_> {}
1203
1204impl<'a> IntoIterator for &'a StructureRef {
1205    type IntoIter = Iter<'a>;
1206    type Item = (&'static glib::GStr, &'a SendValue);
1207
1208    fn into_iter(self) -> Self::IntoIter {
1209        self.iter()
1210    }
1211}
1212
1213impl<'a> std::iter::Extend<(&'a str, SendValue)> for StructureRef {
1214    fn extend<T: IntoIterator<Item = (&'a str, SendValue)>>(&mut self, iter: T) {
1215        iter.into_iter().for_each(|(f, v)| self.set_value(f, v));
1216    }
1217}
1218
1219impl<'a> std::iter::Extend<(&'a glib::GStr, SendValue)> for StructureRef {
1220    fn extend<T: IntoIterator<Item = (&'a glib::GStr, SendValue)>>(&mut self, iter: T) {
1221        iter.into_iter().for_each(|(f, v)| self.set_value(f, v));
1222    }
1223}
1224
1225impl std::iter::Extend<(String, SendValue)> for StructureRef {
1226    fn extend<T: IntoIterator<Item = (String, SendValue)>>(&mut self, iter: T) {
1227        iter.into_iter().for_each(|(f, v)| self.set_value(&f, v));
1228    }
1229}
1230
1231impl std::iter::Extend<(glib::GString, SendValue)> for StructureRef {
1232    fn extend<T: IntoIterator<Item = (glib::GString, SendValue)>>(&mut self, iter: T) {
1233        iter.into_iter().for_each(|(f, v)| self.set_value(&f, v));
1234    }
1235}
1236
1237impl std::iter::Extend<(glib::Quark, SendValue)> for StructureRef {
1238    fn extend<T: IntoIterator<Item = (glib::Quark, SendValue)>>(&mut self, iter: T) {
1239        iter.into_iter()
1240            .for_each(|(f, v)| self.set_value_by_quark(f, v));
1241    }
1242}
1243
1244#[derive(Debug)]
1245#[must_use = "The builder must be built to be used"]
1246pub struct Builder {
1247    s: Structure,
1248}
1249
1250impl Builder {
1251    fn new(name: impl IntoGStr) -> Self {
1252        skip_assert_initialized!();
1253        Builder {
1254            s: Structure::new_empty(name),
1255        }
1256    }
1257
1258    // rustdoc-stripper-ignore-next
1259    /// Sets field `name` to the given value `value`.
1260    ///
1261    /// Overrides any default or previously defined value for `name`.
1262    #[inline]
1263    pub fn field(mut self, name: impl IntoGStr, value: impl Into<glib::Value> + Send) -> Self {
1264        self.s.set(name, value);
1265        self
1266    }
1267
1268    impl_builder_gvalue_extra_setters!(field);
1269
1270    #[must_use = "Building the structure without using it has no effect"]
1271    pub fn build(self) -> Structure {
1272        self.s
1273    }
1274}
1275
1276#[cfg(test)]
1277mod tests {
1278    use super::*;
1279
1280    #[test]
1281    fn new_set_get() {
1282        use glib::{value, Type};
1283
1284        crate::init().unwrap();
1285
1286        let mut s = Structure::new_empty("test");
1287        assert_eq!(s.name(), "test");
1288
1289        s.set("f1", "abc");
1290        s.set("f2", String::from("bcd"));
1291        s.set("f3", 123i32);
1292        s.set("f5", Some("efg"));
1293        s.set("f7", 42i32);
1294
1295        assert_eq!(s.get::<&str>("f1"), Ok("abc"));
1296        assert_eq!(s.get::<Option<&str>>("f2"), Ok(Some("bcd")));
1297        assert_eq!(s.get::<i32>("f3"), Ok(123i32));
1298        assert_eq!(s.get_optional::<&str>("f1"), Ok(Some("abc")));
1299        assert_eq!(s.get_optional::<&str>("f4"), Ok(None));
1300        assert_eq!(s.get_optional::<i32>("f3"), Ok(Some(123i32)));
1301        assert_eq!(s.get_optional::<i32>("f4"), Ok(None));
1302        assert_eq!(s.get::<&str>("f5"), Ok("efg"));
1303        assert_eq!(s.get::<i32>("f7"), Ok(42i32));
1304
1305        assert_eq!(
1306            s.get::<i32>("f2"),
1307            Err(GetError::from_value_get_error(
1308                "f2",
1309                value::ValueTypeMismatchError::new(Type::STRING, Type::I32),
1310            ))
1311        );
1312        assert_eq!(
1313            s.get::<bool>("f3"),
1314            Err(GetError::from_value_get_error(
1315                "f3",
1316                value::ValueTypeMismatchError::new(Type::I32, Type::BOOL),
1317            ))
1318        );
1319        assert_eq!(
1320            s.get::<&str>("f4"),
1321            Err(GetError::new_field_not_found("f4"))
1322        );
1323        assert_eq!(s.get::<i32>("f4"), Err(GetError::new_field_not_found("f4")));
1324
1325        assert_eq!(
1326            s.fields().collect::<Vec<_>>(),
1327            vec!["f1", "f2", "f3", "f5", "f7"]
1328        );
1329
1330        let v = s.iter().map(|(f, v)| (f, v.clone())).collect::<Vec<_>>();
1331        assert_eq!(v.len(), 5);
1332        assert_eq!(v[0].0, "f1");
1333        assert_eq!(v[0].1.get::<&str>(), Ok("abc"));
1334        assert_eq!(v[1].0, "f2");
1335        assert_eq!(v[1].1.get::<&str>(), Ok("bcd"));
1336        assert_eq!(v[2].0, "f3");
1337        assert_eq!(v[2].1.get::<i32>(), Ok(123i32));
1338        assert_eq!(v[3].0, "f5");
1339        assert_eq!(v[3].1.get::<&str>(), Ok("efg"));
1340        assert_eq!(v[4].0, "f7");
1341        assert_eq!(v[4].1.get::<i32>(), Ok(42i32));
1342
1343        let s2 = Structure::builder("test")
1344            .field("f1", "abc")
1345            .field("f2", String::from("bcd"))
1346            .field("f3", 123i32)
1347            .field_if_some("f4", Option::<i32>::None)
1348            .field_if_some("f5", Some("efg"))
1349            .field_if_some("f6", Option::<&str>::None)
1350            .field_if("f7", 42i32, true)
1351            .field_if("f8", 21i32, false)
1352            .build();
1353        assert_eq!(s, s2);
1354
1355        let mut s3 = Structure::new_empty("test");
1356
1357        s3.set_if_some("f1", Some("abc"));
1358        s3.set_if_some("f2", Some(String::from("bcd")));
1359        s3.set_if_some("f3", Some(123i32));
1360        s3.set_if_some("f4", Option::<i32>::None);
1361        s3.set_if_some("f5", Some("efg"));
1362        s3.set_if_some("f6", Option::<&str>::None);
1363        s3.set_if("f7", 42i32, true);
1364        s3.set_if("f8", 21i32, false);
1365        assert_eq!(s, s3);
1366    }
1367
1368    #[test]
1369    fn test_string_conversion() {
1370        crate::init().unwrap();
1371
1372        let a = "Test, f1=(string)abc, f2=(uint)123;";
1373
1374        let s = a.parse::<Structure>().unwrap();
1375        assert_eq!(s.get::<&str>("f1"), Ok("abc"));
1376        assert_eq!(s.get::<u32>("f2"), Ok(123));
1377
1378        assert_eq!(a, s.to_string());
1379    }
1380
1381    #[test]
1382    fn test_from_value_optional() {
1383        use glib::value::ToValue;
1384
1385        crate::init().unwrap();
1386
1387        let a = None::<&Structure>.to_value();
1388        assert!(a.get::<Option<Structure>>().unwrap().is_none());
1389        let b = "foo".parse::<Structure>().unwrap().to_value();
1390        assert!(b.get::<Option<Structure>>().unwrap().is_some());
1391    }
1392
1393    #[test]
1394    fn test_new_from_iter() {
1395        crate::init().unwrap();
1396
1397        let s = Structure::builder("test")
1398            .field("f1", "abc")
1399            .field("f2", String::from("bcd"))
1400            .field("f3", 123i32)
1401            .build();
1402
1403        let s2 = Structure::from_iter(
1404            s.name(),
1405            s.iter()
1406                .filter(|(f, _)| *f == "f1")
1407                .map(|(f, v)| (f, v.clone())),
1408        );
1409
1410        assert_eq!(s2.name(), "test");
1411        assert_eq!(s2.get::<&str>("f1"), Ok("abc"));
1412        assert!(s2.get::<&str>("f2").is_err());
1413        assert!(s2.get::<&str>("f3").is_err());
1414    }
1415
1416    #[test]
1417    fn test_debug() {
1418        crate::init().unwrap();
1419
1420        let s = Structure::builder("test")
1421            .field("f1", "abc")
1422            .field("f2", String::from("bcd"))
1423            .field("f3", 123i32)
1424            .field(
1425                "f4",
1426                Structure::builder("nested").field("badger", true).build(),
1427            )
1428            .field("f5", crate::Array::new(["a", "b", "c"]))
1429            .field("f6", crate::List::new(["d", "e", "f"]))
1430            .build();
1431
1432        assert_eq!(format!("{s:?}"), "Structure(test { f1: (gchararray) \"abc\", f2: (gchararray) \"bcd\", f3: (gint) 123, f4: Structure(nested { badger: (gboolean) TRUE }), f5: Array([(gchararray) \"a\", (gchararray) \"b\", (gchararray) \"c\"]), f6: List([(gchararray) \"d\", (gchararray) \"e\", (gchararray) \"f\"]) })");
1433    }
1434
1435    #[test]
1436    fn builder_field_from_iter() {
1437        crate::init().unwrap();
1438
1439        let s = Structure::builder("test")
1440            .field_from_iter::<crate::Array>("array", [&1, &2, &3])
1441            .field_from_iter::<crate::List>("list", [&4, &5, &6])
1442            .build();
1443        assert!(s
1444            .get::<crate::Array>("array")
1445            .unwrap()
1446            .iter()
1447            .map(|val| val.get::<i32>().unwrap())
1448            .eq([1, 2, 3]));
1449        assert!(s
1450            .get::<crate::List>("list")
1451            .unwrap()
1452            .iter()
1453            .map(|val| val.get::<i32>().unwrap())
1454            .eq([4, 5, 6]));
1455
1456        let array = Vec::<i32>::new();
1457        let s = Structure::builder("test")
1458            .field_from_iter::<crate::Array>("array", &array)
1459            .field_from_iter::<crate::List>("list", &array)
1460            .build();
1461        assert!(s.get::<crate::Array>("array").unwrap().as_ref().is_empty());
1462        assert!(s.get::<crate::List>("list").unwrap().as_ref().is_empty());
1463    }
1464
1465    #[test]
1466    fn builder_field_if_not_empty() {
1467        crate::init().unwrap();
1468
1469        let s = Structure::builder("test")
1470            .field_if_not_empty::<crate::Array>("array", [&1, &2, &3])
1471            .field_if_not_empty::<crate::List>("list", [&4, &5, &6])
1472            .build();
1473        assert!(s
1474            .get::<crate::Array>("array")
1475            .unwrap()
1476            .iter()
1477            .map(|val| val.get::<i32>().unwrap())
1478            .eq([1, 2, 3]));
1479        assert!(s
1480            .get::<crate::List>("list")
1481            .unwrap()
1482            .iter()
1483            .map(|val| val.get::<i32>().unwrap())
1484            .eq([4, 5, 6]));
1485
1486        let array = Vec::<i32>::new();
1487        let s = Structure::builder("test")
1488            .field_if_not_empty::<crate::Array>("array", &array)
1489            .field_if_not_empty::<crate::List>("list", &array)
1490            .build();
1491        assert!(!s.has_field("array"));
1492        assert!(!s.has_field("list"));
1493    }
1494
1495    #[test]
1496    fn test_name_and_field_name_lt() {
1497        crate::init().unwrap();
1498
1499        let (name, field_name) = {
1500            let s = Structure::builder("name")
1501                .field("field0", "val0")
1502                .field("field1", "val1")
1503                .build();
1504
1505            (s.name(), s.nth_field_name(0).unwrap())
1506        };
1507
1508        assert_eq!(name, "name");
1509        assert_eq!(field_name, "field0");
1510    }
1511}