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