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