Skip to main content

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 cfg_if::cfg_if;
13use glib::{
14    GStr, IntoGStr,
15    prelude::*,
16    translate::*,
17    value::{FromValue, SendValue, Value},
18};
19
20use crate::{Fraction, IdStr, ffi};
21
22#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
23pub enum GetError<E: std::error::Error> {
24    #[error("GetError: Structure field with name {name} not found")]
25    FieldNotFound { name: IdStr },
26    #[error("GetError: Structure field with name {name} not retrieved")]
27    ValueGetError {
28        name: IdStr,
29        #[source]
30        error: E,
31    },
32}
33
34impl<E: std::error::Error> GetError<E> {
35    #[inline]
36    fn new_field_not_found(name: impl AsRef<IdStr>) -> Self {
37        skip_assert_initialized!();
38        GetError::FieldNotFound {
39            name: name.as_ref().clone(),
40        }
41    }
42
43    #[inline]
44    fn from_value_get_error(name: impl AsRef<IdStr>, error: E) -> Self {
45        skip_assert_initialized!();
46        GetError::ValueGetError {
47            name: name.as_ref().clone(),
48            error,
49        }
50    }
51}
52
53/// A [`Structure`][crate::Structure] is a collection of key/value pairs. The keys are expressed as
54/// GQuarks and the values can be of any GType.
55///
56/// In addition to the key/value pairs, a [`Structure`][crate::Structure] also has a name. The name
57/// starts with a letter and can be filled by letters, numbers and any of
58/// "/-_.:".
59///
60/// [`Structure`][crate::Structure] is used by various GStreamer subsystems to store information in
61/// a flexible and extensible way. A [`Structure`][crate::Structure] does not have a refcount
62/// because it usually is part of a higher level object such as [`Caps`][crate::Caps],
63/// [`Message`][crate::Message], [`Event`][crate::Event], [`Query`][crate::Query]. It provides a means to enforce mutability
64/// using the refcount of the parent with the `gst_structure_set_parent_refcount()`
65/// method.
66///
67/// A [`Structure`][crate::Structure] can be created with [`new_empty()`][Self::new_empty()] or
68/// [`new()`][Self::new()], which both take a name and an optional set of key/value
69/// pairs along with the types of the values.
70///
71/// Field values can be changed with `gst_structure_set_value()` or
72/// `gst_structure_set()`.
73///
74/// Field values can be retrieved with `gst_structure_get_value()` or the more
75/// convenient gst_structure_get_*() functions.
76///
77/// Fields can be removed with `gst_structure_remove_field()` or
78/// `gst_structure_remove_fields()`.
79///
80/// Strings in structures must be ASCII or UTF-8 encoded. Other encodings are not
81/// allowed. Strings may be [`None`] however.
82///
83/// ## The serialization format
84///
85/// GstStructure serialization format serialize the GstStructure name,
86/// keys/GType/values in a comma separated list with the structure name as first
87/// field without value followed by separated key/value pairs in the form
88/// `key=value`, for example:
89///
90/// ```text
91/// a-structure, key=value
92/// ````
93///
94/// The values type will be inferred if not explicitly specified with the
95/// `(GTypeName)value` syntax, for example the following struct will have one
96/// field called 'is-string' which has the string 'true' as a value:
97///
98/// ```text
99/// a-struct, field-is-string=(string)true, field-is-boolean=true
100/// ```
101///
102/// *Note*: without specifying `(string), `field-is-string` type would have been
103/// inferred as boolean.
104///
105/// *Note*: we specified `(string)` as a type even if `gchararray` is the actual
106/// GType name as for convenience some well known types have been aliased or
107/// abbreviated.
108///
109/// To avoid specifying the type, you can give some hints to the "type system".
110/// For example to specify a value as a double, you should add a decimal (ie. `1`
111/// is an `int` while `1.0` is a `double`).
112///
113/// *Note*: when a structure is serialized with `gst_structure_to_string`, all
114/// values are explicitly typed.
115///
116/// Some types have special delimiters:
117///
118/// - [GstValueArray](GST_TYPE_ARRAY) are inside "less and greater than" (`<` and
119///  `>`). For example `a-structure, array=<1, 2, 3>
120/// - Ranges are inside brackets (`[` and `]`). For example `a-structure,
121///  range=[1, 6, 2]` 1 being the min value, 6 the maximum and 2 the step. To
122///  specify a `GST_TYPE_INT64_RANGE` you need to explicitly specify it like:
123///  `a-structure, a-int64-range=(gint64) [1, 5]`
124/// - [GstValueList](GST_TYPE_LIST) are inside curly brackets (`{` and `}`).
125///  For example `a-structure, list={1, 2, 3}`
126/// - [GStrv](G_TYPE_STRV) are inside "less and greater than" (`<` and
127///  `>`) and each string is double-quoted.
128///  For example `a-structure, strv=(GStrv)<"foo", "bar">`. Since 1.26.0.
129///
130/// Structures are delimited either by a null character `\0` or a semicolon `;`
131/// the latter allowing to store multiple structures in the same string (see
132/// [`Caps`][crate::Caps]).
133///
134/// Quotes are used as "default" delimiters and can be used around any types that
135/// don't use other delimiters (for example `a-struct, i=(int)"1"`). They are use
136/// to allow adding spaces or special characters (such as delimiters,
137/// semicolumns, etc..) inside strings and you can use backslashes `\` to escape
138/// characters inside them, for example:
139///
140/// ```text
141/// a-struct, special="\"{[(;)]}\" can be used inside quotes"
142/// ```
143///
144/// They also allow for nested structure, such as:
145///
146/// ```text
147/// a-struct, nested=(GstStructure)"nested-struct, nested=true"
148/// ```
149///
150/// Since 1.20, nested structures and caps can be specified using brackets (`[`
151/// and `]`), for example:
152///
153/// ```text
154/// a-struct, nested=[nested-struct, nested=true]
155/// ```
156///
157/// > *note*: [`to_str()`][Self::to_str()] won't use that syntax for backward
158/// > compatibility reason, [`serialize_full()`][Self::serialize_full()] has been added for
159/// > that purpose.
160#[doc(alias = "GstStructure")]
161#[repr(transparent)]
162pub struct Structure(ptr::NonNull<ffi::GstStructure>);
163unsafe impl Send for Structure {}
164unsafe impl Sync for Structure {}
165
166impl Structure {
167    #[doc(alias = "gst_structure_new")]
168    pub fn builder(name: impl IntoGStr) -> Builder {
169        skip_assert_initialized!();
170        Builder::new(name)
171    }
172
173    #[doc(alias = "gst_structure_new_static_str_empty")]
174    pub fn builder_static(name: impl AsRef<GStr> + 'static) -> Builder {
175        skip_assert_initialized!();
176        Builder::from_static(name)
177    }
178
179    #[doc(alias = "gst_structure_new_id_str")]
180    pub fn builder_from_id(name: impl AsRef<IdStr>) -> Builder {
181        skip_assert_initialized!();
182        Builder::from_id(name)
183    }
184
185    /// Creates a new, empty [`Structure`][crate::Structure] with the given `name`.
186    ///
187    /// See `gst_structure_set_name()` for constraints on the `name` parameter.
188    ///
189    /// Free-function: gst_structure_free
190    /// ## `name`
191    /// name of new structure
192    ///
193    /// # Returns
194    ///
195    /// a new, empty [`Structure`][crate::Structure]
196    #[doc(alias = "gst_structure_new_empty")]
197    pub fn new_empty(name: impl IntoGStr) -> Structure {
198        assert_initialized_main_thread!();
199        unsafe {
200            let ptr = name.run_with_gstr(|name| ffi::gst_structure_new_empty(name.as_ptr()));
201            debug_assert!(!ptr.is_null());
202            Structure(ptr::NonNull::new_unchecked(ptr))
203        }
204    }
205
206    #[doc(alias = "gst_structure_new_static_str_empty")]
207    pub fn new_empty_from_static(name: impl AsRef<GStr> + 'static) -> Structure {
208        assert_initialized_main_thread!();
209        unsafe {
210            cfg_if! {
211                if #[cfg(feature = "v1_26")] {
212                    let ptr =
213                        ffi::gst_structure_new_static_str_empty(name.as_ref().as_ptr());
214                } else {
215                    let ptr = ffi::gst_structure_new_empty(name.as_ref().as_ptr());
216                }
217            }
218            debug_assert!(!ptr.is_null());
219            Structure(ptr::NonNull::new_unchecked(ptr))
220        }
221    }
222
223    #[doc(alias = "gst_structure_new_id_str_empty")]
224    pub fn new_empty_from_id(name: impl AsRef<IdStr>) -> Structure {
225        assert_initialized_main_thread!();
226        unsafe {
227            cfg_if! {
228                if #[cfg(feature = "v1_26")] {
229                    let ptr = ffi::gst_structure_new_id_str_empty(name.as_ref().as_ptr());
230                } else {
231                    let ptr = ffi::gst_structure_new_empty(name.as_ref().as_gstr().as_ptr());
232                }
233            }
234
235            debug_assert!(!ptr.is_null());
236            Structure(ptr::NonNull::new_unchecked(ptr))
237        }
238    }
239
240    #[allow(clippy::should_implement_trait)]
241    pub fn from_iter<S: IntoGStr>(
242        name: impl IntoGStr,
243        iter: impl IntoIterator<Item = (S, SendValue)>,
244    ) -> Structure {
245        skip_assert_initialized!();
246        let mut structure = Structure::new_empty(name);
247
248        iter.into_iter()
249            .for_each(|(f, v)| structure.set_value(f, v));
250
251        structure
252    }
253
254    #[allow(clippy::should_implement_trait)]
255    pub fn from_iter_with_static<S: AsRef<GStr> + 'static>(
256        name: impl AsRef<GStr> + 'static,
257        iter: impl IntoIterator<Item = (S, SendValue)>,
258    ) -> Structure {
259        skip_assert_initialized!();
260        let mut structure = Structure::new_empty_from_static(name);
261
262        iter.into_iter()
263            .for_each(|(f, v)| structure.set_value_with_static(f, v));
264
265        structure
266    }
267
268    #[allow(clippy::should_implement_trait)]
269    pub fn from_iter_with_id<S: AsRef<IdStr>>(
270        name: impl AsRef<IdStr>,
271        iter: impl IntoIterator<Item = (S, SendValue)>,
272    ) -> Structure {
273        skip_assert_initialized!();
274        let mut structure = Structure::new_empty_from_id(name);
275
276        iter.into_iter()
277            .for_each(|(f, v)| structure.set_value_with_id(f, v));
278
279        structure
280    }
281}
282
283impl IntoGlibPtr<*mut ffi::GstStructure> for Structure {
284    #[inline]
285    fn into_glib_ptr(self) -> *mut ffi::GstStructure {
286        let s = mem::ManuallyDrop::new(self);
287        s.0.as_ptr()
288    }
289}
290
291impl Deref for Structure {
292    type Target = StructureRef;
293
294    #[inline]
295    fn deref(&self) -> &StructureRef {
296        unsafe { &*(self.0.as_ptr() as *const StructureRef) }
297    }
298}
299
300impl DerefMut for Structure {
301    #[inline]
302    fn deref_mut(&mut self) -> &mut StructureRef {
303        unsafe { &mut *(self.0.as_ptr() as *mut StructureRef) }
304    }
305}
306
307impl AsRef<StructureRef> for Structure {
308    #[inline]
309    fn as_ref(&self) -> &StructureRef {
310        self.deref()
311    }
312}
313
314impl AsMut<StructureRef> for Structure {
315    #[inline]
316    fn as_mut(&mut self) -> &mut StructureRef {
317        self.deref_mut()
318    }
319}
320
321impl Clone for Structure {
322    #[inline]
323    fn clone(&self) -> Self {
324        unsafe {
325            let ptr = ffi::gst_structure_copy(self.0.as_ref());
326            debug_assert!(!ptr.is_null());
327            Structure(ptr::NonNull::new_unchecked(ptr))
328        }
329    }
330}
331
332impl Drop for Structure {
333    #[inline]
334    fn drop(&mut self) {
335        unsafe { ffi::gst_structure_free(self.0.as_mut()) }
336    }
337}
338
339impl fmt::Debug for Structure {
340    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
341        f.debug_tuple("Structure").field(self.as_ref()).finish()
342    }
343}
344
345impl fmt::Display for Structure {
346    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
347        // Need to make sure to not call ToString::to_string() here, which
348        // we have because of the Display impl. We need StructureRef::to_string()
349        f.write_str(&StructureRef::to_string(self.as_ref()))
350    }
351}
352
353impl PartialEq for Structure {
354    fn eq(&self, other: &Structure) -> bool {
355        StructureRef::eq(self, other)
356    }
357}
358
359impl Eq for Structure {}
360
361impl PartialEq<StructureRef> for Structure {
362    fn eq(&self, other: &StructureRef) -> bool {
363        StructureRef::eq(self, other)
364    }
365}
366
367impl PartialEq<Structure> for StructureRef {
368    fn eq(&self, other: &Structure) -> bool {
369        StructureRef::eq(other, self)
370    }
371}
372
373impl str::FromStr for Structure {
374    type Err = glib::BoolError;
375
376    #[doc(alias = "gst_structure_from_string")]
377    fn from_str(s: &str) -> Result<Self, Self::Err> {
378        assert_initialized_main_thread!();
379        unsafe {
380            let structure =
381                s.run_with_gstr(|s| ffi::gst_structure_from_string(s.as_ptr(), ptr::null_mut()));
382            if structure.is_null() {
383                Err(glib::bool_error!("Failed to parse structure from string"))
384            } else {
385                Ok(Self(ptr::NonNull::new_unchecked(structure)))
386            }
387        }
388    }
389}
390
391impl Borrow<StructureRef> for Structure {
392    #[inline]
393    fn borrow(&self) -> &StructureRef {
394        self.as_ref()
395    }
396}
397
398impl BorrowMut<StructureRef> for Structure {
399    #[inline]
400    fn borrow_mut(&mut self) -> &mut StructureRef {
401        self.as_mut()
402    }
403}
404
405impl ToOwned for StructureRef {
406    type Owned = Structure;
407
408    fn to_owned(&self) -> Structure {
409        unsafe {
410            let ptr = ffi::gst_structure_copy(&self.0);
411            debug_assert!(!ptr.is_null());
412            Structure(ptr::NonNull::new_unchecked(ptr))
413        }
414    }
415}
416
417impl glib::types::StaticType for Structure {
418    #[inline]
419    fn static_type() -> glib::types::Type {
420        unsafe { from_glib(ffi::gst_structure_get_type()) }
421    }
422}
423
424impl<'a> ToGlibPtr<'a, *const ffi::GstStructure> for Structure {
425    type Storage = PhantomData<&'a Self>;
426
427    #[inline]
428    fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GstStructure, Self> {
429        unsafe { Stash(self.0.as_ref(), PhantomData) }
430    }
431
432    #[inline]
433    fn to_glib_full(&self) -> *const ffi::GstStructure {
434        unsafe { ffi::gst_structure_copy(self.0.as_ref()) }
435    }
436}
437
438impl<'a> ToGlibPtr<'a, *mut ffi::GstStructure> for Structure {
439    type Storage = PhantomData<&'a Self>;
440
441    #[inline]
442    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GstStructure, Self> {
443        unsafe {
444            Stash(
445                self.0.as_ref() as *const ffi::GstStructure as *mut ffi::GstStructure,
446                PhantomData,
447            )
448        }
449    }
450
451    #[inline]
452    fn to_glib_full(&self) -> *mut ffi::GstStructure {
453        unsafe { ffi::gst_structure_copy(self.0.as_ref()) }
454    }
455}
456
457impl<'a> ToGlibPtrMut<'a, *mut ffi::GstStructure> for Structure {
458    type Storage = PhantomData<&'a mut Self>;
459
460    #[inline]
461    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GstStructure, Self> {
462        unsafe { StashMut(self.0.as_mut(), PhantomData) }
463    }
464}
465
466impl FromGlibPtrNone<*const ffi::GstStructure> for Structure {
467    #[inline]
468    unsafe fn from_glib_none(ptr: *const ffi::GstStructure) -> Self {
469        unsafe {
470            debug_assert!(!ptr.is_null());
471            let ptr = ffi::gst_structure_copy(ptr);
472            debug_assert!(!ptr.is_null());
473            Structure(ptr::NonNull::new_unchecked(ptr))
474        }
475    }
476}
477
478impl FromGlibPtrNone<*mut ffi::GstStructure> for Structure {
479    #[inline]
480    unsafe fn from_glib_none(ptr: *mut ffi::GstStructure) -> Self {
481        unsafe {
482            debug_assert!(!ptr.is_null());
483            let ptr = ffi::gst_structure_copy(ptr);
484            debug_assert!(!ptr.is_null());
485            Structure(ptr::NonNull::new_unchecked(ptr))
486        }
487    }
488}
489
490impl FromGlibPtrFull<*const ffi::GstStructure> for Structure {
491    #[inline]
492    unsafe fn from_glib_full(ptr: *const ffi::GstStructure) -> Self {
493        unsafe {
494            debug_assert!(!ptr.is_null());
495            Structure(ptr::NonNull::new_unchecked(ptr as *mut ffi::GstStructure))
496        }
497    }
498}
499
500impl FromGlibPtrFull<*mut ffi::GstStructure> for Structure {
501    #[inline]
502    unsafe fn from_glib_full(ptr: *mut ffi::GstStructure) -> Self {
503        unsafe {
504            debug_assert!(!ptr.is_null());
505            Structure(ptr::NonNull::new_unchecked(ptr))
506        }
507    }
508}
509
510impl FromGlibPtrBorrow<*const ffi::GstStructure> for Structure {
511    #[inline]
512    unsafe fn from_glib_borrow(ptr: *const ffi::GstStructure) -> Borrowed<Self> {
513        unsafe { Borrowed::new(from_glib_full(ptr)) }
514    }
515}
516
517impl FromGlibPtrBorrow<*mut ffi::GstStructure> for Structure {
518    #[inline]
519    unsafe fn from_glib_borrow(ptr: *mut ffi::GstStructure) -> Borrowed<Self> {
520        unsafe { Borrowed::new(from_glib_full(ptr)) }
521    }
522}
523
524impl glib::value::ValueType for Structure {
525    type Type = Self;
526}
527
528impl glib::value::ValueTypeOptional for Structure {}
529
530unsafe impl<'a> glib::value::FromValue<'a> for Structure {
531    type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
532
533    unsafe fn from_value(value: &'a glib::Value) -> Self {
534        unsafe {
535            skip_assert_initialized!();
536            from_glib_none(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0)
537                as *mut ffi::GstStructure)
538        }
539    }
540}
541
542impl glib::value::ToValue for Structure {
543    fn to_value(&self) -> glib::Value {
544        let mut value = glib::Value::for_value_type::<Self>();
545        unsafe {
546            glib::gobject_ffi::g_value_set_boxed(
547                value.to_glib_none_mut().0,
548                glib::translate::ToGlibPtr::<*const ffi::GstStructure>::to_glib_none(self).0
549                    as *mut _,
550            )
551        }
552        value
553    }
554
555    fn value_type(&self) -> glib::Type {
556        Self::static_type()
557    }
558}
559
560impl glib::value::ToValueOptional for Structure {
561    fn to_value_optional(s: Option<&Self>) -> glib::Value {
562        skip_assert_initialized!();
563        let mut value = glib::Value::for_value_type::<Self>();
564        unsafe {
565            glib::gobject_ffi::g_value_set_boxed(
566                value.to_glib_none_mut().0,
567                glib::translate::ToGlibPtr::<*const ffi::GstStructure>::to_glib_none(&s).0
568                    as *mut _,
569            )
570        }
571        value
572    }
573}
574
575impl From<Structure> for glib::Value {
576    fn from(v: Structure) -> glib::Value {
577        skip_assert_initialized!();
578        let mut value = glib::Value::for_value_type::<Structure>();
579        unsafe {
580            glib::gobject_ffi::g_value_take_boxed(
581                value.to_glib_none_mut().0,
582                glib::translate::IntoGlibPtr::<*mut ffi::GstStructure>::into_glib_ptr(v) as *mut _,
583            )
584        }
585        value
586    }
587}
588
589impl GlibPtrDefault for Structure {
590    type GlibType = *mut ffi::GstStructure;
591}
592
593unsafe impl TransparentPtrType for Structure {}
594
595#[repr(transparent)]
596#[doc(alias = "GstStructure")]
597pub struct StructureRef(ffi::GstStructure);
598
599unsafe impl Send for StructureRef {}
600unsafe impl Sync for StructureRef {}
601
602impl StructureRef {
603    #[inline]
604    pub unsafe fn from_glib_borrow<'a>(ptr: *const ffi::GstStructure) -> &'a StructureRef {
605        unsafe {
606            debug_assert!(!ptr.is_null());
607
608            &*(ptr as *mut StructureRef)
609        }
610    }
611
612    #[inline]
613    pub unsafe fn from_glib_borrow_mut<'a>(ptr: *mut ffi::GstStructure) -> &'a mut StructureRef {
614        unsafe {
615            debug_assert!(!ptr.is_null());
616            #[cfg(feature = "v1_28")]
617            debug_assert_ne!(ffi::gst_structure_is_writable(ptr), glib::ffi::GFALSE,);
618
619            &mut *(ptr as *mut StructureRef)
620        }
621    }
622
623    #[inline]
624    pub fn as_ptr(&self) -> *const ffi::GstStructure {
625        self as *const Self as *const ffi::GstStructure
626    }
627
628    #[inline]
629    pub fn as_mut_ptr(&self) -> *mut ffi::GstStructure {
630        self as *const Self as *mut ffi::GstStructure
631    }
632
633    #[doc(alias = "gst_structure_get")]
634    pub fn get<'a, T: FromValue<'a>>(
635        &'a self,
636        name: impl IntoGStr,
637    ) -> Result<T, GetError<<<T as FromValue<'a>>::Checker as glib::value::ValueTypeChecker>::Error>>
638    {
639        name.run_with_gstr(|name| {
640            self.value(name)
641                .map_err(|err| match err {
642                    GetError::FieldNotFound { name } => GetError::FieldNotFound { name },
643                    _ => unreachable!(),
644                })?
645                .get()
646                .map_err(|err| GetError::from_value_get_error(IdStr::from(name), err))
647        })
648    }
649
650    #[doc(alias = "gst_structure_id_str_get")]
651    #[inline]
652    pub fn get_by_id<'a, T: FromValue<'a>>(
653        &'a self,
654        name: impl AsRef<IdStr>,
655    ) -> Result<T, GetError<<<T as FromValue<'a>>::Checker as glib::value::ValueTypeChecker>::Error>>
656    {
657        self.value_by_id(name.as_ref())
658            .map_err(|err| match err {
659                GetError::FieldNotFound { name } => GetError::FieldNotFound { name },
660                _ => unreachable!(),
661            })?
662            .get()
663            .map_err(|err| GetError::from_value_get_error(name, err))
664    }
665
666    #[doc(alias = "gst_structure_get")]
667    pub fn get_optional<'a, T: FromValue<'a>>(
668        &'a self,
669        name: impl IntoGStr,
670    ) -> Result<
671        Option<T>,
672        GetError<<<T as FromValue<'a>>::Checker as glib::value::ValueTypeChecker>::Error>,
673    > {
674        name.run_with_gstr(|name| {
675            self.value(name)
676                .ok()
677                .map(|v| v.get())
678                .transpose()
679                .map_err(|err| GetError::from_value_get_error(IdStr::from(name), err))
680        })
681    }
682
683    #[doc(alias = "gst_structure_id_str_get")]
684    pub fn get_optional_by_id<'a, T: FromValue<'a>>(
685        &'a self,
686        name: impl AsRef<IdStr>,
687    ) -> Result<
688        Option<T>,
689        GetError<<<T as FromValue<'a>>::Checker as glib::value::ValueTypeChecker>::Error>,
690    > {
691        self.value_by_id(name.as_ref())
692            .ok()
693            .map(|v| v.get())
694            .transpose()
695            .map_err(|err| GetError::from_value_get_error(name, err))
696    }
697
698    #[doc(alias = "get_value")]
699    #[doc(alias = "gst_structure_get_value")]
700    pub fn value(
701        &self,
702        name: impl IntoGStr,
703    ) -> Result<&SendValue, GetError<std::convert::Infallible>> {
704        unsafe {
705            name.run_with_gstr(|name| {
706                let value = ffi::gst_structure_get_value(&self.0, name.as_ptr());
707
708                if value.is_null() {
709                    return Err(GetError::new_field_not_found(IdStr::from(name)));
710                }
711
712                Ok(&*(value as *const SendValue))
713            })
714        }
715    }
716
717    #[doc(alias = "gst_structure_id_str_get_value")]
718    pub fn value_by_id(
719        &self,
720        name: impl AsRef<IdStr>,
721    ) -> Result<&SendValue, GetError<std::convert::Infallible>> {
722        unsafe {
723            cfg_if! {
724                if #[cfg(feature = "v1_26")] {
725                    let value = ffi::gst_structure_id_str_get_value(&self.0, name.as_ref().as_ptr());
726                } else {
727                    let value = ffi::gst_structure_get_value(&self.0, name.as_ref().as_gstr().as_ptr());
728                }
729            }
730
731            if value.is_null() {
732                return Err(GetError::new_field_not_found(name));
733            }
734
735            Ok(&*(value as *const SendValue))
736        }
737    }
738
739    #[deprecated = "use `get_by_id()` instead"]
740    #[allow(deprecated)]
741    #[doc(alias = "gst_structure_id_get")]
742    pub fn get_by_quark<'a, T: FromValue<'a>>(
743        &'a self,
744        name: glib::Quark,
745    ) -> Result<T, GetError<<<T as FromValue<'a>>::Checker as glib::value::ValueTypeChecker>::Error>>
746    {
747        self.value_by_quark(name)
748            .map_err(|err| match err {
749                GetError::FieldNotFound { name } => GetError::FieldNotFound { name },
750                _ => unreachable!(),
751            })?
752            .get()
753            .map_err(|err| GetError::from_value_get_error(IdStr::from(name.as_str()), err))
754    }
755
756    #[deprecated = "use `get_optional_by_id()` instead"]
757    #[allow(deprecated)]
758    #[doc(alias = "gst_structure_id_get")]
759    pub fn get_optional_by_quark<'a, T: FromValue<'a>>(
760        &'a self,
761        name: glib::Quark,
762    ) -> Result<
763        Option<T>,
764        GetError<<<T as FromValue<'a>>::Checker as glib::value::ValueTypeChecker>::Error>,
765    > {
766        self.value_by_quark(name)
767            .ok()
768            .map(|v| v.get())
769            .transpose()
770            .map_err(|err| GetError::from_value_get_error(IdStr::from(name.as_str()), err))
771    }
772
773    #[deprecated = "use `value_by_id()` instead"]
774    #[doc(alias = "gst_structure_id_get_value")]
775    pub fn value_by_quark(
776        &self,
777        name: glib::Quark,
778    ) -> Result<&SendValue, GetError<std::convert::Infallible>> {
779        unsafe {
780            let value = ffi::gst_structure_id_get_value(&self.0, name.into_glib());
781
782            if value.is_null() {
783                return Err(GetError::new_field_not_found(IdStr::from(name.as_str())));
784            }
785
786            Ok(&*(value as *const SendValue))
787        }
788    }
789
790    // rustdoc-stripper-ignore-next
791    /// Sets field `name` to the given value `value`.
792    ///
793    /// Overrides any default or previously defined value for `name`.
794    #[doc(alias = "gst_structure_set")]
795    pub fn set(&mut self, name: impl IntoGStr, value: impl Into<glib::Value> + Send) {
796        let value = glib::SendValue::from_owned(value);
797        self.set_value(name, value);
798    }
799
800    // rustdoc-stripper-ignore-next
801    /// Sets field `name` to the given value `value`.
802    ///
803    /// Overrides any default or previously defined value for `name`.
804    #[doc(alias = "gst_structure_set_static_str")]
805    pub fn set_with_static(
806        &mut self,
807        name: impl AsRef<GStr> + 'static,
808        value: impl Into<glib::Value> + Send,
809    ) {
810        let value = glib::SendValue::from_owned(value);
811        self.set_value_with_static(name, value);
812    }
813
814    // rustdoc-stripper-ignore-next
815    /// Sets field `name` to the given value `value`.
816    ///
817    /// Overrides any default or previously defined value for `name`.
818    #[doc(alias = "gst_structure_id_str_set")]
819    pub fn set_with_id(&mut self, name: impl AsRef<IdStr>, value: impl Into<glib::Value> + Send) {
820        let value = glib::SendValue::from_owned(value);
821        self.set_value_with_id(name, value);
822    }
823
824    // rustdoc-stripper-ignore-next
825    /// Sets field `name` to the given `value` if the `predicate` evaluates to `true`.
826    ///
827    /// This has no effect if the `predicate` evaluates to `false`,
828    /// i.e. default or previous value for `name` is kept.
829    #[doc(alias = "gst_structure_set")]
830    pub fn set_if(
831        &mut self,
832        name: impl IntoGStr,
833        value: impl Into<glib::Value> + Send,
834        predicate: bool,
835    ) {
836        if predicate {
837            self.set(name, value);
838        }
839    }
840
841    // rustdoc-stripper-ignore-next
842    /// Sets field `name` to the given `value` if the `predicate` evaluates to `true`.
843    ///
844    /// This has no effect if the `predicate` evaluates to `false`,
845    /// i.e. default or previous value for `name` is kept.
846    #[doc(alias = "gst_structure_set_static_str")]
847    pub fn set_with_static_if(
848        &mut self,
849        name: impl AsRef<GStr> + 'static,
850        value: impl Into<glib::Value> + Send,
851        predicate: bool,
852    ) {
853        if predicate {
854            self.set_with_static(name, value);
855        }
856    }
857
858    // rustdoc-stripper-ignore-next
859    /// Sets field `name` to the given `value` if the `predicate` evaluates to `true`.
860    ///
861    /// This has no effect if the `predicate` evaluates to `false`,
862    /// i.e. default or previous value for `name` is kept.
863    #[doc(alias = "gst_structure_id_str_set")]
864    pub fn set_with_id_if(
865        &mut self,
866        name: impl AsRef<IdStr>,
867        value: impl Into<glib::Value> + Send,
868        predicate: bool,
869    ) {
870        if predicate {
871            self.set_with_id(name, value);
872        }
873    }
874
875    // rustdoc-stripper-ignore-next
876    /// Sets field `name` to the given inner value if `value` is `Some`.
877    ///
878    /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept.
879    #[doc(alias = "gst_structure_set")]
880    pub fn set_if_some(
881        &mut self,
882        name: impl IntoGStr,
883        value: Option<impl Into<glib::Value> + Send>,
884    ) {
885        if let Some(value) = value {
886            self.set(name, value);
887        }
888    }
889
890    // rustdoc-stripper-ignore-next
891    /// Sets field `name` to the given inner value if `value` is `Some`.
892    ///
893    /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept.
894    #[doc(alias = "gst_structure_set_static_str")]
895    pub fn set_with_static_if_some(
896        &mut self,
897        name: impl AsRef<GStr> + 'static,
898        value: Option<impl Into<glib::Value> + Send>,
899    ) {
900        if let Some(value) = value {
901            self.set_with_static(name, value);
902        }
903    }
904
905    // rustdoc-stripper-ignore-next
906    /// Sets field `name` to the given inner value if `value` is `Some`.
907    ///
908    /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept.
909    #[doc(alias = "gst_structure_id_str_set")]
910    pub fn set_with_id_if_some(
911        &mut self,
912        name: impl AsRef<IdStr>,
913        value: Option<impl Into<glib::Value> + Send>,
914    ) {
915        if let Some(value) = value {
916            self.set_with_id(name, value);
917        }
918    }
919
920    // rustdoc-stripper-ignore-next
921    /// Sets field `name` using the given `ValueType` `V` built from `iter`'s the `Item`s.
922    ///
923    /// Overrides any default or previously defined value for `name`.
924    #[inline]
925    pub fn set_from_iter<
926        V: ValueType + Into<Value> + FromIterator<SendValue> + Send,
927        I: ToSendValue,
928    >(
929        &mut self,
930        name: impl IntoGStr,
931        iter: impl IntoIterator<Item = I>,
932    ) {
933        let iter = iter.into_iter().map(|item| item.to_send_value());
934        self.set(name, V::from_iter(iter));
935    }
936
937    // rustdoc-stripper-ignore-next
938    /// Sets field `name` using the given `ValueType` `V` built from `iter`'s the `Item`s.
939    ///
940    /// Overrides any default or previously defined value for `name`.
941    #[inline]
942    pub fn set_with_static_from_iter<
943        V: ValueType + Into<Value> + FromIterator<SendValue> + Send,
944        I: ToSendValue,
945    >(
946        &mut self,
947        name: impl AsRef<GStr> + 'static,
948        iter: impl IntoIterator<Item = I>,
949    ) {
950        let iter = iter.into_iter().map(|item| item.to_send_value());
951        self.set_with_static(name, V::from_iter(iter));
952    }
953
954    // rustdoc-stripper-ignore-next
955    /// Sets field `name` using the given `ValueType` `V` built from `iter`'s the `Item`s.
956    ///
957    /// Overrides any default or previously defined value for `name`.
958    #[inline]
959    pub fn set_with_id_from_iter<
960        V: ValueType + Into<Value> + FromIterator<SendValue> + Send,
961        I: ToSendValue,
962    >(
963        &mut self,
964        name: impl AsRef<IdStr>,
965        iter: impl IntoIterator<Item = I>,
966    ) {
967        let iter = iter.into_iter().map(|item| item.to_send_value());
968        self.set_with_id(name, V::from_iter(iter));
969    }
970
971    // rustdoc-stripper-ignore-next
972    /// Sets field `name` using the given `ValueType` `V` built from `iter`'s Item`s,
973    /// if `iter` is not empty.
974    ///
975    /// This has no effect if `iter` is empty, i.e. previous value for `name` is unchanged.
976    #[inline]
977    pub fn set_if_not_empty<
978        V: ValueType + Into<Value> + FromIterator<SendValue> + Send,
979        I: ToSendValue,
980    >(
981        &mut self,
982        name: impl IntoGStr,
983        iter: impl IntoIterator<Item = I>,
984    ) {
985        let mut iter = iter.into_iter().peekable();
986        if iter.peek().is_some() {
987            let iter = iter.map(|item| item.to_send_value());
988            self.set(name, V::from_iter(iter));
989        }
990    }
991
992    // rustdoc-stripper-ignore-next
993    /// Sets field `name` using the given `ValueType` `V` built from `iter`'s Item`s,
994    /// if `iter` is not empty.
995    ///
996    /// This has no effect if `iter` is empty, i.e. previous value for `name` is unchanged.
997    #[inline]
998    pub fn set_with_static_if_not_empty<
999        V: ValueType + Into<Value> + FromIterator<SendValue> + Send,
1000        I: ToSendValue,
1001    >(
1002        &mut self,
1003        name: impl AsRef<GStr> + 'static,
1004        iter: impl IntoIterator<Item = I>,
1005    ) {
1006        let mut iter = iter.into_iter().peekable();
1007        if iter.peek().is_some() {
1008            let iter = iter.map(|item| item.to_send_value());
1009            self.set_with_static(name, V::from_iter(iter));
1010        }
1011    }
1012
1013    // rustdoc-stripper-ignore-next
1014    /// Sets field `name` using the given `ValueType` `V` built from `iter`'s Item`s,
1015    /// if `iter` is not empty.
1016    ///
1017    /// This has no effect if `iter` is empty, i.e. previous value for `name` is unchanged.
1018    #[inline]
1019    pub fn set_with_id_if_not_empty<
1020        V: ValueType + Into<Value> + FromIterator<SendValue> + Send,
1021        I: ToSendValue,
1022    >(
1023        &mut self,
1024        name: impl AsRef<IdStr>,
1025        iter: impl IntoIterator<Item = I>,
1026    ) {
1027        let mut iter = iter.into_iter().peekable();
1028        if iter.peek().is_some() {
1029            let iter = iter.map(|item| item.to_send_value());
1030            self.set_with_id(name, V::from_iter(iter));
1031        }
1032    }
1033
1034    // rustdoc-stripper-ignore-next
1035    /// Sets field `name` to the given value `value`.
1036    ///
1037    /// Overrides any default or previously defined value for `name`.
1038    #[doc(alias = "gst_structure_set_value")]
1039    pub fn set_value(&mut self, name: impl IntoGStr, value: SendValue) {
1040        unsafe {
1041            name.run_with_gstr(|name| {
1042                ffi::gst_structure_take_value(&mut self.0, name.as_ptr(), &mut value.into_raw())
1043            });
1044        }
1045    }
1046
1047    // rustdoc-stripper-ignore-next
1048    /// Sets field `name` to the given value `value`.
1049    ///
1050    /// Overrides any default or previously defined value for `name`.
1051    #[doc(alias = "gst_structure_set_value_static_str")]
1052    pub fn set_value_with_static(&mut self, name: impl AsRef<GStr> + 'static, value: SendValue) {
1053        unsafe {
1054            cfg_if! {
1055                if #[cfg(feature = "v1_26")] {
1056                    ffi::gst_structure_take_value_static_str(
1057                        &mut self.0,
1058                        name.as_ref().as_ptr(),
1059                        &mut value.into_raw(),
1060                    )
1061                } else {
1062                    ffi::gst_structure_take_value(
1063                        &mut self.0,
1064                        name.as_ref().as_ptr(),
1065                        &mut value.into_raw(),
1066                    )
1067                }
1068            }
1069        }
1070    }
1071
1072    // rustdoc-stripper-ignore-next
1073    /// Sets field `name` to the given value `value`.
1074    ///
1075    /// Overrides any default or previously defined value for `name`.
1076    #[doc(alias = "gst_structure_id_str_set_value")]
1077    pub fn set_value_with_id(&mut self, name: impl AsRef<IdStr>, value: SendValue) {
1078        unsafe {
1079            cfg_if! {
1080                if #[cfg(feature = "v1_26")] {
1081                    ffi::gst_structure_id_str_take_value(
1082                        &mut self.0,
1083                        name.as_ref().as_ptr(),
1084                        &mut value.into_raw(),
1085                    )
1086                } else {
1087                    ffi::gst_structure_take_value(
1088                        &mut self.0,
1089                        name.as_ref().as_gstr().as_ptr(),
1090                        &mut value.into_raw(),
1091                    )
1092                }
1093            }
1094        }
1095    }
1096
1097    // rustdoc-stripper-ignore-next
1098    /// Sets field `name` to the given `value` if the `predicate` evaluates to `true`.
1099    ///
1100    /// This has no effect if the `predicate` evaluates to `false`,
1101    /// i.e. default or previous value for `name` is kept.
1102    #[doc(alias = "gst_structure_set_value")]
1103    pub fn set_value_if(&mut self, name: impl IntoGStr, value: SendValue, predicate: bool) {
1104        if predicate {
1105            self.set_value(name, value);
1106        }
1107    }
1108
1109    // rustdoc-stripper-ignore-next
1110    /// Sets field `name` to the given `value` if the `predicate` evaluates to `true`.
1111    ///
1112    /// This has no effect if the `predicate` evaluates to `false`,
1113    /// i.e. default or previous value for `name` is kept.
1114    #[doc(alias = "gst_structure_set_value_static_str")]
1115    pub fn set_value_with_static_if(
1116        &mut self,
1117        name: impl AsRef<GStr> + 'static,
1118        value: SendValue,
1119        predicate: bool,
1120    ) {
1121        if predicate {
1122            self.set_value_with_static(name, value);
1123        }
1124    }
1125
1126    // rustdoc-stripper-ignore-next
1127    /// Sets field `name` to the given `value` if the `predicate` evaluates to `true`.
1128    ///
1129    /// This has no effect if the `predicate` evaluates to `false`,
1130    /// i.e. default or previous value for `name` is kept.
1131    #[doc(alias = "gst_structure_id_str_set_value")]
1132    pub fn set_value_with_id_if(
1133        &mut self,
1134        name: impl AsRef<IdStr>,
1135        value: SendValue,
1136        predicate: bool,
1137    ) {
1138        if predicate {
1139            self.set_value_with_id(name, value);
1140        }
1141    }
1142
1143    // rustdoc-stripper-ignore-next
1144    /// Sets field `name` to the given inner value if `value` is `Some`.
1145    ///
1146    /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept.
1147    #[doc(alias = "gst_structure_set_value")]
1148    pub fn set_value_if_some(&mut self, name: impl IntoGStr, value: Option<SendValue>) {
1149        if let Some(value) = value {
1150            self.set_value(name, value);
1151        }
1152    }
1153
1154    // rustdoc-stripper-ignore-next
1155    /// Sets field `name` to the given inner value if `value` is `Some`.
1156    ///
1157    /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept.
1158    #[doc(alias = "gst_structure_set_value_static_str")]
1159    pub fn set_value_with_static_if_some(
1160        &mut self,
1161        name: impl AsRef<GStr> + 'static,
1162        value: Option<SendValue>,
1163    ) {
1164        if let Some(value) = value {
1165            self.set_value_with_static(name, value);
1166        }
1167    }
1168
1169    // rustdoc-stripper-ignore-next
1170    /// Sets field `name` to the given inner value if `value` is `Some`.
1171    ///
1172    /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept.
1173    #[doc(alias = "gst_structure_id_str_set_value")]
1174    pub fn set_value_with_id_if_some(&mut self, name: impl AsRef<IdStr>, value: Option<SendValue>) {
1175        if let Some(value) = value {
1176            self.set_value_with_id(name, value);
1177        }
1178    }
1179
1180    #[deprecated = "use `set_by_id()` instead"]
1181    #[allow(deprecated)]
1182    #[doc(alias = "gst_structure_id_set")]
1183    pub fn set_by_quark(&mut self, name: glib::Quark, value: impl Into<glib::Value> + Send) {
1184        let value = glib::SendValue::from_owned(value);
1185        self.set_value_by_quark(name, value);
1186    }
1187
1188    #[deprecated = "use `set_by_id_if_some()` instead"]
1189    #[allow(deprecated)]
1190    #[doc(alias = "gst_structure_id_set")]
1191    pub fn set_by_quark_if_some(
1192        &mut self,
1193        name: glib::Quark,
1194        value: Option<impl Into<glib::Value> + Send>,
1195    ) {
1196        if let Some(value) = value {
1197            self.set_by_quark(name, value);
1198        }
1199    }
1200
1201    #[deprecated = "use `set_by_id_value()` instead"]
1202    #[doc(alias = "gst_structure_id_set_value")]
1203    pub fn set_value_by_quark(&mut self, name: glib::Quark, value: SendValue) {
1204        unsafe {
1205            ffi::gst_structure_id_take_value(&mut self.0, name.into_glib(), &mut value.into_raw());
1206        }
1207    }
1208
1209    #[deprecated = "use `set_by_id_value_if_some()` instead"]
1210    #[allow(deprecated)]
1211    #[doc(alias = "gst_structure_id_set_value")]
1212    pub fn set_value_by_quark_if_some(&mut self, name: glib::Quark, value: Option<SendValue>) {
1213        if let Some(value) = value {
1214            self.set_value_by_quark(name, value);
1215        }
1216    }
1217
1218    #[doc(alias = "get_name")]
1219    #[doc(alias = "gst_structure_get_name")]
1220    pub fn name(&self) -> &glib::GStr {
1221        unsafe { glib::GStr::from_ptr(ffi::gst_structure_get_name(&self.0)) }
1222    }
1223
1224    #[cfg(feature = "v1_26")]
1225    #[doc(alias = "get_name")]
1226    #[doc(alias = "gst_structure_get_name_id_str")]
1227    pub fn name_id(&self) -> &IdStr {
1228        unsafe { &*(ffi::gst_structure_get_name_id_str(&self.0) as *const crate::IdStr) }
1229    }
1230
1231    #[deprecated = "use `name()` instead, or `name_id()` with feature v1_26"]
1232    #[doc(alias = "gst_structure_get_name_id")]
1233    pub fn name_quark(&self) -> glib::Quark {
1234        unsafe { from_glib(ffi::gst_structure_get_name_id(&self.0)) }
1235    }
1236
1237    #[doc(alias = "gst_structure_set_name")]
1238    pub fn set_name(&mut self, name: impl IntoGStr) {
1239        unsafe {
1240            name.run_with_gstr(|name| ffi::gst_structure_set_name(&mut self.0, name.as_ptr()))
1241        }
1242    }
1243
1244    #[doc(alias = "gst_structure_set_name_static_str")]
1245    pub fn set_name_from_static(&mut self, name: impl AsRef<GStr> + 'static) {
1246        unsafe {
1247            cfg_if! {
1248                if #[cfg(feature = "v1_26")] {
1249                    ffi::gst_structure_set_name_static_str(
1250                        &mut self.0,
1251                        name.as_ref().as_ptr(),
1252                    )
1253                } else {
1254                    ffi::gst_structure_set_name(&mut self.0, name.as_ref().as_ptr())
1255                }
1256            }
1257        }
1258    }
1259
1260    #[doc(alias = "gst_structure_set_name_id_str")]
1261    pub fn set_name_from_id(&mut self, name: impl AsRef<IdStr>) {
1262        unsafe {
1263            cfg_if! {
1264                if #[cfg(feature = "v1_26")] {
1265                    ffi::gst_structure_set_name_id_str(
1266                        &mut self.0,
1267                        name.as_ref().as_ptr(),
1268                    )
1269                } else {
1270                    ffi::gst_structure_set_name(&mut self.0, name.as_ref().as_gstr().as_ptr())
1271                }
1272            }
1273        }
1274    }
1275
1276    #[doc(alias = "gst_structure_set_name")]
1277    pub fn set_name_if_some(&mut self, name: Option<impl IntoGStr>) {
1278        if let Some(name) = name {
1279            self.set_name(name);
1280        }
1281    }
1282
1283    #[doc(alias = "gst_structure_set_name_static_str")]
1284    pub fn set_name_from_static_if_some(&mut self, name: Option<impl AsRef<GStr> + 'static>) {
1285        if let Some(name) = name {
1286            self.set_name_from_static(name);
1287        }
1288    }
1289
1290    #[doc(alias = "gst_structure_set_name_id_str")]
1291    pub fn set_name_from_id_if_some(&mut self, name: Option<impl AsRef<IdStr>>) {
1292        if let Some(name) = name {
1293            self.set_name_from_id(name);
1294        }
1295    }
1296
1297    #[doc(alias = "gst_structure_has_name")]
1298    pub fn has_name(&self, name: &str) -> bool {
1299        self.name() == name
1300    }
1301
1302    #[doc(alias = "gst_structure_has_field")]
1303    pub fn has_field(&self, field: impl IntoGStr) -> bool {
1304        unsafe {
1305            field.run_with_gstr(|field| {
1306                from_glib(ffi::gst_structure_has_field(&self.0, field.as_ptr()))
1307            })
1308        }
1309    }
1310
1311    #[doc(alias = "gst_structure_id_str_has_field")]
1312    pub fn has_field_by_id(&self, field: impl AsRef<IdStr>) -> bool {
1313        unsafe {
1314            cfg_if! {
1315                if #[cfg(feature = "v1_26")] {
1316                    from_glib(ffi::gst_structure_id_str_has_field(
1317                        &self.0,
1318                        field.as_ref().as_ptr(),
1319                    ))
1320                } else {
1321                    from_glib(ffi::gst_structure_has_field(
1322                        &self.0,
1323                        field.as_ref().as_gstr().as_ptr(),
1324                    ))
1325                }
1326            }
1327        }
1328    }
1329
1330    #[doc(alias = "gst_structure_has_field_typed")]
1331    pub fn has_field_with_type(&self, field: impl IntoGStr, type_: glib::Type) -> bool {
1332        unsafe {
1333            field.run_with_gstr(|field| {
1334                from_glib(ffi::gst_structure_has_field_typed(
1335                    &self.0,
1336                    field.as_ptr(),
1337                    type_.into_glib(),
1338                ))
1339            })
1340        }
1341    }
1342
1343    #[doc(alias = "gst_structure_id_str_has_field_typed")]
1344    pub fn has_field_with_type_by_id(&self, field: impl AsRef<IdStr>, type_: glib::Type) -> bool {
1345        unsafe {
1346            cfg_if! {
1347                if #[cfg(feature = "v1_26")] {
1348                    from_glib(ffi::gst_structure_id_str_has_field_typed(
1349                        &self.0,
1350                        field.as_ref().as_ptr(),
1351                        type_.into_glib(),
1352                    ))
1353                } else {
1354                    from_glib(ffi::gst_structure_has_field_typed(
1355                        &self.0,
1356                        field.as_ref().as_gstr().as_ptr(),
1357                        type_.into_glib(),
1358                    ))
1359                }
1360            }
1361        }
1362    }
1363
1364    #[deprecated = "use `has_field_by_id()`"]
1365    #[doc(alias = "gst_structure_id_has_field")]
1366    pub fn has_field_by_quark(&self, field: glib::Quark) -> bool {
1367        unsafe { from_glib(ffi::gst_structure_id_has_field(&self.0, field.into_glib())) }
1368    }
1369
1370    #[deprecated = "use `has_field_with_type_by_id()`"]
1371    #[doc(alias = "gst_structure_id_has_field_typed")]
1372    pub fn has_field_with_type_by_quark(&self, field: glib::Quark, type_: glib::Type) -> bool {
1373        unsafe {
1374            from_glib(ffi::gst_structure_id_has_field_typed(
1375                &self.0,
1376                field.into_glib(),
1377                type_.into_glib(),
1378            ))
1379        }
1380    }
1381
1382    #[doc(alias = "gst_structure_remove_field")]
1383    pub fn remove_field(&mut self, field: impl IntoGStr) {
1384        unsafe {
1385            field.run_with_gstr(|field| {
1386                ffi::gst_structure_remove_field(&mut self.0, field.as_ptr())
1387            });
1388        }
1389    }
1390
1391    #[doc(alias = "gst_structure_remove_fields")]
1392    pub fn remove_fields<S: IntoGStr>(&mut self, fields: impl IntoIterator<Item = S>) {
1393        for f in fields.into_iter() {
1394            self.remove_field(f)
1395        }
1396    }
1397
1398    #[doc(alias = "gst_structure_id_str_remove_field")]
1399    pub fn remove_field_by_id(&mut self, field: impl AsRef<IdStr>) {
1400        unsafe {
1401            cfg_if! {
1402                if #[cfg(feature = "v1_26")] {
1403                    ffi::gst_structure_id_str_remove_field(&mut self.0, field.as_ref().as_ptr())
1404                } else {
1405                    ffi::gst_structure_remove_field(&mut self.0, field.as_ref().as_gstr().as_ptr())
1406                }
1407            }
1408        }
1409    }
1410
1411    #[doc(alias = "gst_structure_id_str_remove_fields")]
1412    pub fn remove_field_by_ids<S: AsRef<IdStr>>(&mut self, fields: impl IntoIterator<Item = S>) {
1413        for f in fields.into_iter() {
1414            self.remove_field_by_id(f)
1415        }
1416    }
1417
1418    #[doc(alias = "gst_structure_remove_all_fields")]
1419    pub fn remove_all_fields(&mut self) {
1420        unsafe {
1421            ffi::gst_structure_remove_all_fields(&mut self.0);
1422        }
1423    }
1424
1425    pub fn fields(&self) -> FieldIterator<'_> {
1426        FieldIterator::new(self)
1427    }
1428
1429    pub fn iter(&self) -> Iter<'_> {
1430        Iter::new(self)
1431    }
1432
1433    #[cfg(feature = "v1_26")]
1434    pub fn field_ids(&self) -> FieldIdIterator<'_> {
1435        FieldIdIterator::new(self)
1436    }
1437
1438    #[cfg(feature = "v1_26")]
1439    pub fn id_iter(&self) -> IdIter<'_> {
1440        IdIter::new(self)
1441    }
1442
1443    #[doc(alias = "get_nth_field_name")]
1444    #[doc(alias = "gst_structure_nth_field_name")]
1445    pub fn nth_field_name(&self, idx: usize) -> Option<&glib::GStr> {
1446        if idx >= self.n_fields() {
1447            return None;
1448        }
1449
1450        unsafe {
1451            let field_name = ffi::gst_structure_nth_field_name(&self.0, idx as u32);
1452            debug_assert!(!field_name.is_null());
1453
1454            Some(glib::GStr::from_ptr(field_name))
1455        }
1456    }
1457
1458    #[cfg(feature = "v1_26")]
1459    #[doc(alias = "get_nth_field_name")]
1460    #[doc(alias = "gst_structure_id_str_nth_field_name")]
1461    pub fn nth_field_by_id(&self, idx: usize) -> Option<&IdStr> {
1462        if idx >= self.n_fields() {
1463            return None;
1464        }
1465
1466        unsafe {
1467            let field_name = ffi::gst_structure_id_str_nth_field_name(&self.0, idx as u32);
1468            debug_assert!(!field_name.is_null());
1469
1470            Some(&*(field_name as *const crate::IdStr))
1471        }
1472    }
1473
1474    #[doc(alias = "gst_structure_n_fields")]
1475    pub fn n_fields(&self) -> usize {
1476        unsafe { ffi::gst_structure_n_fields(&self.0) as usize }
1477    }
1478
1479    pub fn len(&self) -> usize {
1480        self.n_fields()
1481    }
1482
1483    pub fn is_empty(&self) -> bool {
1484        self.n_fields() == 0
1485    }
1486
1487    #[doc(alias = "gst_structure_can_intersect")]
1488    pub fn can_intersect(&self, other: &StructureRef) -> bool {
1489        unsafe { from_glib(ffi::gst_structure_can_intersect(&self.0, &other.0)) }
1490    }
1491
1492    #[doc(alias = "gst_structure_intersect")]
1493    pub fn intersect(&self, other: &StructureRef) -> Option<Structure> {
1494        unsafe { from_glib_full(ffi::gst_structure_intersect(&self.0, &other.0)) }
1495    }
1496
1497    #[doc(alias = "gst_structure_is_subset")]
1498    pub fn is_subset(&self, superset: &StructureRef) -> bool {
1499        unsafe { from_glib(ffi::gst_structure_is_subset(&self.0, &superset.0)) }
1500    }
1501
1502    #[doc(alias = "gst_structure_fixate")]
1503    pub fn fixate(&mut self) {
1504        unsafe { ffi::gst_structure_fixate(&mut self.0) }
1505    }
1506
1507    #[doc(alias = "gst_structure_fixate_field")]
1508    pub fn fixate_field(&mut self, name: impl IntoGStr) -> bool {
1509        unsafe {
1510            name.run_with_gstr(|name| {
1511                from_glib(ffi::gst_structure_fixate_field(&mut self.0, name.as_ptr()))
1512            })
1513        }
1514    }
1515
1516    #[doc(alias = "gst_structure_fixate_field_boolean")]
1517    pub fn fixate_field_bool(&mut self, name: impl IntoGStr, target: bool) -> bool {
1518        unsafe {
1519            name.run_with_gstr(|name| {
1520                from_glib(ffi::gst_structure_fixate_field_boolean(
1521                    &mut self.0,
1522                    name.as_ptr(),
1523                    target.into_glib(),
1524                ))
1525            })
1526        }
1527    }
1528
1529    #[doc(alias = "gst_structure_fixate_field_string")]
1530    pub fn fixate_field_str(&mut self, name: impl IntoGStr, target: impl IntoGStr) -> bool {
1531        unsafe {
1532            name.run_with_gstr(|name| {
1533                target.run_with_gstr(|target| {
1534                    from_glib(ffi::gst_structure_fixate_field_string(
1535                        &mut self.0,
1536                        name.as_ptr(),
1537                        target.as_ptr(),
1538                    ))
1539                })
1540            })
1541        }
1542    }
1543
1544    #[doc(alias = "gst_structure_fixate_field_nearest_double")]
1545    pub fn fixate_field_nearest_double(&mut self, name: impl IntoGStr, target: f64) -> bool {
1546        unsafe {
1547            name.run_with_gstr(|name| {
1548                from_glib(ffi::gst_structure_fixate_field_nearest_double(
1549                    &mut self.0,
1550                    name.as_ptr(),
1551                    target,
1552                ))
1553            })
1554        }
1555    }
1556
1557    #[doc(alias = "gst_structure_fixate_field_nearest_fraction")]
1558    pub fn fixate_field_nearest_fraction(
1559        &mut self,
1560        name: impl IntoGStr,
1561        target: impl Into<Fraction>,
1562    ) -> bool {
1563        skip_assert_initialized!();
1564
1565        let target = target.into();
1566        unsafe {
1567            name.run_with_gstr(|name| {
1568                from_glib(ffi::gst_structure_fixate_field_nearest_fraction(
1569                    &mut self.0,
1570                    name.as_ptr(),
1571                    target.numer(),
1572                    target.denom(),
1573                ))
1574            })
1575        }
1576    }
1577
1578    #[doc(alias = "gst_structure_fixate_field_nearest_int")]
1579    pub fn fixate_field_nearest_int(&mut self, name: impl IntoGStr, target: i32) -> bool {
1580        unsafe {
1581            name.run_with_gstr(|name| {
1582                from_glib(ffi::gst_structure_fixate_field_nearest_int(
1583                    &mut self.0,
1584                    name.as_ptr(),
1585                    target,
1586                ))
1587            })
1588        }
1589    }
1590
1591    #[cfg(feature = "v1_20")]
1592    #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
1593    #[doc(alias = "gst_structure_serialize")]
1594    pub fn serialize(&self, flags: crate::SerializeFlags) -> glib::GString {
1595        unsafe { from_glib_full(ffi::gst_structure_serialize(&self.0, flags.into_glib())) }
1596    }
1597
1598    #[cfg(feature = "v1_24")]
1599    #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1600    #[doc(alias = "gst_structure_serialize")]
1601    #[doc(alias = "gst_structure_serialize_full")]
1602    pub fn serialize_strict(
1603        &self,
1604        flags: crate::SerializeFlags,
1605    ) -> Result<glib::GString, glib::BoolError> {
1606        unsafe {
1607            let res = ffi::gst_structure_serialize_full(
1608                &self.0,
1609                flags.into_glib() | ffi::GST_SERIALIZE_FLAG_STRICT,
1610            );
1611            if res.is_null() {
1612                Err(glib::bool_error!("Failed to serialize structure to string"))
1613            } else {
1614                Ok(from_glib_full(res))
1615            }
1616        }
1617    }
1618
1619    #[deprecated = "Use `iter()` instead, or `id_iter()` with feature v1_26"]
1620    #[doc(alias = "gst_structure_foreach")]
1621    pub fn foreach<F: FnMut(glib::Quark, &glib::Value) -> std::ops::ControlFlow<()>>(
1622        &self,
1623        mut func: F,
1624    ) -> bool {
1625        unsafe {
1626            unsafe extern "C" fn trampoline<
1627                F: FnMut(glib::Quark, &glib::Value) -> std::ops::ControlFlow<()>,
1628            >(
1629                quark: glib::ffi::GQuark,
1630                value: *const glib::gobject_ffi::GValue,
1631                user_data: glib::ffi::gpointer,
1632            ) -> glib::ffi::gboolean {
1633                unsafe {
1634                    let func = &mut *(user_data as *mut F);
1635                    let res = func(from_glib(quark), &*(value as *const glib::Value));
1636
1637                    matches!(res, std::ops::ControlFlow::Continue(_)).into_glib()
1638                }
1639            }
1640            let func = &mut func as *mut F;
1641            from_glib(ffi::gst_structure_foreach(
1642                self.as_ptr(),
1643                Some(trampoline::<F>),
1644                func as glib::ffi::gpointer,
1645            ))
1646        }
1647    }
1648
1649    #[cfg(feature = "v1_26")]
1650    // rustdoc-stripper-ignore-next
1651    /// Executes the provided `func` on each field, possibly modifying the value.
1652    #[doc(alias = "gst_structure_map_in_place_id_str")]
1653    pub fn map_in_place_by_id<F: FnMut(&IdStr, &mut glib::Value) -> std::ops::ControlFlow<()>>(
1654        &mut self,
1655        mut func: F,
1656    ) {
1657        unsafe {
1658            unsafe extern "C" fn trampoline<
1659                F: FnMut(&IdStr, &mut glib::Value) -> std::ops::ControlFlow<()>,
1660            >(
1661                fieldname: *const ffi::GstIdStr,
1662                value: *mut glib::gobject_ffi::GValue,
1663                user_data: glib::ffi::gpointer,
1664            ) -> glib::ffi::gboolean {
1665                unsafe {
1666                    let func = &mut *(user_data as *mut F);
1667                    let res = func(
1668                        &*(fieldname as *const IdStr),
1669                        &mut *(value as *mut glib::Value),
1670                    );
1671
1672                    matches!(res, std::ops::ControlFlow::Continue(_)).into_glib()
1673                }
1674            }
1675            let func = &mut func as *mut F;
1676            let _ = ffi::gst_structure_map_in_place_id_str(
1677                self.as_mut_ptr(),
1678                Some(trampoline::<F>),
1679                func as glib::ffi::gpointer,
1680            );
1681        }
1682    }
1683
1684    #[cfg(feature = "v1_26")]
1685    // rustdoc-stripper-ignore-next
1686    /// Executes the provided `func` on each field with an owned value.
1687    ///
1688    /// * If `func` returns `Some(value)`, the field's value is replaced with
1689    ///   `value`.
1690    /// * If `func` returns `None`, the field is removed.
1691    #[doc(alias = "gst_structure_filter_and_map_in_place_id_str")]
1692    pub fn filter_map_in_place_by_id<F: FnMut(&IdStr, glib::Value) -> Option<glib::Value>>(
1693        &mut self,
1694        mut func: F,
1695    ) {
1696        unsafe {
1697            unsafe extern "C" fn trampoline<
1698                F: FnMut(&IdStr, glib::Value) -> Option<glib::Value>,
1699            >(
1700                fieldname: *const ffi::GstIdStr,
1701                value: *mut glib::gobject_ffi::GValue,
1702                user_data: glib::ffi::gpointer,
1703            ) -> glib::ffi::gboolean {
1704                unsafe {
1705                    let func = &mut *(user_data as *mut F);
1706
1707                    let v = mem::replace(
1708                        &mut *(value as *mut glib::Value),
1709                        glib::Value::uninitialized(),
1710                    );
1711                    match func(&*(fieldname as *const IdStr), v) {
1712                        None => glib::ffi::GFALSE,
1713                        Some(v) => {
1714                            *value = v.into_raw();
1715                            glib::ffi::GTRUE
1716                        }
1717                    }
1718                }
1719            }
1720
1721            let func = &mut func as *mut F;
1722            ffi::gst_structure_filter_and_map_in_place_id_str(
1723                self.as_mut_ptr(),
1724                Some(trampoline::<F>),
1725                func as glib::ffi::gpointer,
1726            );
1727        }
1728    }
1729
1730    // rustdoc-stripper-ignore-next
1731    /// Executes the provided `func` on each field, possibly modifying the value,
1732    /// as long as `ControlFlow::Continue(())` is returned.
1733    ///
1734    /// Using `Quark`s is deprecated, however this method is kept because there
1735    /// are no other means to achieve this pre-GStreamer-1.26. With feature v1_26,
1736    /// use [map_in_place_by_id] instead.
1737    ///
1738    /// # Returns:
1739    ///
1740    /// * `ControlFlow::Continue(())` if `func` returned this for all fields,
1741    /// * `ControlFlow::Break(())` otherwise.
1742    ///
1743    /// [map_in_place_by_id]: crate::StructureRef::map_in_place_by_id
1744    #[doc(alias = "gst_structure_map_in_place")]
1745    pub fn map_in_place<F: FnMut(glib::Quark, &mut glib::Value) -> std::ops::ControlFlow<()>>(
1746        &mut self,
1747        mut func: F,
1748    ) -> std::ops::ControlFlow<()> {
1749        unsafe {
1750            unsafe extern "C" fn trampoline<
1751                F: FnMut(glib::Quark, &mut glib::Value) -> std::ops::ControlFlow<()>,
1752            >(
1753                quark: glib::ffi::GQuark,
1754                value: *mut glib::gobject_ffi::GValue,
1755                user_data: glib::ffi::gpointer,
1756            ) -> glib::ffi::gboolean {
1757                unsafe {
1758                    let func = &mut *(user_data as *mut F);
1759                    let res = func(from_glib(quark), &mut *(value as *mut glib::Value));
1760
1761                    matches!(res, std::ops::ControlFlow::Continue(_)).into_glib()
1762                }
1763            }
1764            let func = &mut func as *mut F;
1765            if from_glib(ffi::gst_structure_map_in_place(
1766                self.as_mut_ptr(),
1767                Some(trampoline::<F>),
1768                func as glib::ffi::gpointer,
1769            )) {
1770                std::ops::ControlFlow::Continue(())
1771            } else {
1772                std::ops::ControlFlow::Break(())
1773            }
1774        }
1775    }
1776
1777    // rustdoc-stripper-ignore-next
1778    /// Executes the provided `func` on each field with an owned value.
1779    ///
1780    /// * If `func` returns `Some(value)`, the field's value is replaced with
1781    ///   `value`.
1782    /// * If `func` returns `None`, the field is removed.
1783    ///
1784    /// Using `Quark`s is deprecated, however this method is kept because there
1785    /// are no other means to achieve this pre-GStreamer-1.26. With feature v1_26,
1786    /// use [filter_map_in_place_by_id] instead.
1787    ///
1788    /// [filter_map_in_place_by_id]: crate::StructureRef::filter_map_in_place_by_id
1789    #[doc(alias = "gst_structure_filter_and_map_in_place")]
1790    pub fn filter_map_in_place<F: FnMut(glib::Quark, glib::Value) -> Option<glib::Value>>(
1791        &mut self,
1792        mut func: F,
1793    ) {
1794        unsafe {
1795            unsafe extern "C" fn trampoline<
1796                F: FnMut(glib::Quark, glib::Value) -> Option<glib::Value>,
1797            >(
1798                quark: glib::ffi::GQuark,
1799                value: *mut glib::gobject_ffi::GValue,
1800                user_data: glib::ffi::gpointer,
1801            ) -> glib::ffi::gboolean {
1802                unsafe {
1803                    let func = &mut *(user_data as *mut F);
1804
1805                    let v = mem::replace(
1806                        &mut *(value as *mut glib::Value),
1807                        glib::Value::uninitialized(),
1808                    );
1809                    match func(from_glib(quark), v) {
1810                        None => glib::ffi::GFALSE,
1811                        Some(v) => {
1812                            *value = v.into_raw();
1813                            glib::ffi::GTRUE
1814                        }
1815                    }
1816                }
1817            }
1818
1819            let func = &mut func as *mut F;
1820            ffi::gst_structure_filter_and_map_in_place(
1821                self.as_mut_ptr(),
1822                Some(trampoline::<F>),
1823                func as glib::ffi::gpointer,
1824            );
1825        }
1826    }
1827}
1828
1829impl fmt::Display for StructureRef {
1830    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1831        let s = unsafe { glib::GString::from_glib_full(ffi::gst_structure_to_string(&self.0)) };
1832        f.write_str(&s)
1833    }
1834}
1835
1836impl fmt::Debug for StructureRef {
1837    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1838        let mut debug = f.debug_struct(self.name());
1839
1840        for (id, field) in self.iter() {
1841            if field.type_() == Structure::static_type() {
1842                let s = field.get::<Structure>().unwrap();
1843                debug.field(id, &s);
1844            } else if field.type_() == crate::Array::static_type() {
1845                let arr = field.get::<crate::Array>().unwrap();
1846                debug.field(id, &arr);
1847            } else if field.type_() == crate::List::static_type() {
1848                let list = field.get::<crate::List>().unwrap();
1849                debug.field(id, &list);
1850            } else {
1851                debug.field(id, &field);
1852            }
1853        }
1854
1855        debug.finish()
1856    }
1857}
1858
1859impl PartialEq for StructureRef {
1860    #[doc(alias = "gst_structure_is_equal")]
1861    fn eq(&self, other: &StructureRef) -> bool {
1862        unsafe { from_glib(ffi::gst_structure_is_equal(&self.0, &other.0)) }
1863    }
1864}
1865
1866impl Eq for StructureRef {}
1867
1868impl glib::types::StaticType for StructureRef {
1869    #[inline]
1870    fn static_type() -> glib::types::Type {
1871        unsafe { from_glib(ffi::gst_structure_get_type()) }
1872    }
1873}
1874
1875unsafe impl<'a> glib::value::FromValue<'a> for &'a StructureRef {
1876    type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
1877
1878    unsafe fn from_value(value: &'a glib::Value) -> Self {
1879        unsafe {
1880            skip_assert_initialized!();
1881            &*(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const StructureRef)
1882        }
1883    }
1884}
1885
1886impl glib::value::ToValue for StructureRef {
1887    fn to_value(&self) -> glib::Value {
1888        let mut value = glib::Value::for_value_type::<Structure>();
1889        unsafe {
1890            glib::gobject_ffi::g_value_set_boxed(
1891                value.to_glib_none_mut().0,
1892                self.as_ptr() as *mut _,
1893            )
1894        }
1895        value
1896    }
1897
1898    fn value_type(&self) -> glib::Type {
1899        Self::static_type()
1900    }
1901}
1902
1903impl glib::value::ToValueOptional for StructureRef {
1904    fn to_value_optional(s: Option<&Self>) -> glib::Value {
1905        skip_assert_initialized!();
1906        let mut value = glib::Value::for_value_type::<Structure>();
1907        unsafe {
1908            glib::gobject_ffi::g_value_set_boxed(
1909                value.to_glib_none_mut().0,
1910                s.map(|s| s.as_ptr()).unwrap_or(ptr::null()) as *mut _,
1911            )
1912        }
1913        value
1914    }
1915}
1916
1917crate::utils::define_fixed_size_iter!(
1918    FieldIterator,
1919    &'a StructureRef,
1920    &'a glib::GStr,
1921    |collection: &StructureRef| collection.n_fields(),
1922    |collection: &StructureRef, idx: usize| unsafe {
1923        let field_name = ffi::gst_structure_nth_field_name(&collection.0, idx as u32);
1924        glib::GStr::from_ptr(field_name)
1925    }
1926);
1927
1928#[cfg(feature = "v1_26")]
1929crate::utils::define_fixed_size_iter!(
1930    FieldIdIterator,
1931    &'a StructureRef,
1932    &'a crate::IdStr,
1933    |collection: &StructureRef| collection.n_fields(),
1934    |collection: &StructureRef, idx: usize| unsafe {
1935        let field_name = ffi::gst_structure_id_str_nth_field_name(&collection.0, idx as u32);
1936        debug_assert!(!field_name.is_null());
1937
1938        &*(field_name as *const crate::IdStr)
1939    }
1940);
1941
1942#[must_use = "iterators are lazy and do nothing unless consumed"]
1943#[derive(Debug)]
1944pub struct Iter<'a> {
1945    iter: FieldIterator<'a>,
1946}
1947
1948impl<'a> Iter<'a> {
1949    fn new(structure: &'a StructureRef) -> Iter<'a> {
1950        skip_assert_initialized!();
1951        Iter {
1952            iter: FieldIterator::new(structure),
1953        }
1954    }
1955}
1956
1957impl<'a> Iterator for Iter<'a> {
1958    type Item = (&'a glib::GStr, &'a SendValue);
1959
1960    fn next(&mut self) -> Option<Self::Item> {
1961        let f = self.iter.next()?;
1962        let v = self.iter.collection.value(f);
1963        Some((f, v.unwrap()))
1964    }
1965
1966    fn size_hint(&self) -> (usize, Option<usize>) {
1967        self.iter.size_hint()
1968    }
1969
1970    fn count(self) -> usize {
1971        self.iter.count()
1972    }
1973
1974    fn nth(&mut self, n: usize) -> Option<Self::Item> {
1975        let f = self.iter.nth(n)?;
1976        let v = self.iter.collection.value(f);
1977        Some((f, v.unwrap()))
1978    }
1979
1980    fn last(self) -> Option<Self::Item> {
1981        let structure = self.iter.collection;
1982        let f = self.iter.last()?;
1983        let v = structure.value(f);
1984        Some((f, v.unwrap()))
1985    }
1986}
1987
1988impl DoubleEndedIterator for Iter<'_> {
1989    fn next_back(&mut self) -> Option<Self::Item> {
1990        let f = self.iter.next_back()?;
1991        let v = self.iter.collection.value(f);
1992        Some((f, v.unwrap()))
1993    }
1994
1995    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
1996        let f = self.iter.nth_back(n)?;
1997        let v = self.iter.collection.value(f);
1998        Some((f, v.unwrap()))
1999    }
2000}
2001
2002impl ExactSizeIterator for Iter<'_> {}
2003
2004impl std::iter::FusedIterator for Iter<'_> {}
2005
2006#[cfg(feature = "v1_26")]
2007#[must_use = "iterators are lazy and do nothing unless consumed"]
2008#[derive(Debug)]
2009pub struct IdIter<'a> {
2010    iter: FieldIdIterator<'a>,
2011}
2012
2013#[cfg(feature = "v1_26")]
2014impl<'a> IdIter<'a> {
2015    fn new(structure: &'a StructureRef) -> IdIter<'a> {
2016        skip_assert_initialized!();
2017        IdIter {
2018            iter: FieldIdIterator::new(structure),
2019        }
2020    }
2021}
2022
2023#[cfg(feature = "v1_26")]
2024impl<'a> Iterator for IdIter<'a> {
2025    type Item = (&'a IdStr, &'a SendValue);
2026
2027    fn next(&mut self) -> Option<Self::Item> {
2028        let f = self.iter.next()?;
2029        let v = self.iter.collection.value_by_id(f);
2030        Some((f, v.unwrap()))
2031    }
2032
2033    fn size_hint(&self) -> (usize, Option<usize>) {
2034        self.iter.size_hint()
2035    }
2036
2037    fn count(self) -> usize {
2038        self.iter.count()
2039    }
2040
2041    fn nth(&mut self, n: usize) -> Option<Self::Item> {
2042        let f = self.iter.nth(n)?;
2043        let v = self.iter.collection.value_by_id(f);
2044        Some((f, v.unwrap()))
2045    }
2046
2047    fn last(self) -> Option<Self::Item> {
2048        let structure = self.iter.collection;
2049        let f = self.iter.last()?;
2050        let v = structure.value_by_id(f);
2051        Some((f, v.unwrap()))
2052    }
2053}
2054
2055#[cfg(feature = "v1_26")]
2056impl DoubleEndedIterator for IdIter<'_> {
2057    fn next_back(&mut self) -> Option<Self::Item> {
2058        let f = self.iter.next_back()?;
2059        let v = self.iter.collection.value_by_id(f);
2060        Some((f, v.unwrap()))
2061    }
2062
2063    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
2064        let f = self.iter.nth_back(n)?;
2065        let v = self.iter.collection.value_by_id(f);
2066        Some((f, v.unwrap()))
2067    }
2068}
2069
2070#[cfg(feature = "v1_26")]
2071impl ExactSizeIterator for IdIter<'_> {}
2072#[cfg(feature = "v1_26")]
2073impl std::iter::FusedIterator for IdIter<'_> {}
2074
2075impl<'a> IntoIterator for &'a StructureRef {
2076    type IntoIter = Iter<'a>;
2077    type Item = (&'a glib::GStr, &'a SendValue);
2078
2079    fn into_iter(self) -> Self::IntoIter {
2080        self.iter()
2081    }
2082}
2083
2084impl<'a> std::iter::Extend<(&'a str, SendValue)> for StructureRef {
2085    fn extend<T: IntoIterator<Item = (&'a str, SendValue)>>(&mut self, iter: T) {
2086        iter.into_iter().for_each(|(f, v)| self.set_value(f, v));
2087    }
2088}
2089
2090impl<'a> std::iter::Extend<(&'a glib::GStr, SendValue)> for StructureRef {
2091    fn extend<T: IntoIterator<Item = (&'a glib::GStr, SendValue)>>(&mut self, iter: T) {
2092        iter.into_iter().for_each(|(f, v)| self.set_value(f, v));
2093    }
2094}
2095
2096impl std::iter::Extend<(String, SendValue)> for StructureRef {
2097    fn extend<T: IntoIterator<Item = (String, SendValue)>>(&mut self, iter: T) {
2098        iter.into_iter().for_each(|(f, v)| self.set_value(&f, v));
2099    }
2100}
2101
2102impl std::iter::Extend<(glib::GString, SendValue)> for StructureRef {
2103    fn extend<T: IntoIterator<Item = (glib::GString, SendValue)>>(&mut self, iter: T) {
2104        iter.into_iter().for_each(|(f, v)| self.set_value(&f, v));
2105    }
2106}
2107
2108impl<'a> std::iter::Extend<(&'a IdStr, SendValue)> for StructureRef {
2109    #[allow(deprecated)]
2110    fn extend<T: IntoIterator<Item = (&'a IdStr, SendValue)>>(&mut self, iter: T) {
2111        iter.into_iter()
2112            .for_each(|(f, v)| self.set_value_with_id(f, v));
2113    }
2114}
2115
2116impl std::iter::Extend<(IdStr, SendValue)> for StructureRef {
2117    #[allow(deprecated)]
2118    fn extend<T: IntoIterator<Item = (IdStr, SendValue)>>(&mut self, iter: T) {
2119        iter.into_iter()
2120            .for_each(|(f, v)| self.set_value_with_id(f, v));
2121    }
2122}
2123
2124impl std::iter::Extend<(glib::Quark, SendValue)> for StructureRef {
2125    #[allow(deprecated)]
2126    fn extend<T: IntoIterator<Item = (glib::Quark, SendValue)>>(&mut self, iter: T) {
2127        iter.into_iter()
2128            .for_each(|(f, v)| self.set_value_by_quark(f, v));
2129    }
2130}
2131
2132// Need gst_value_hash from 1.28
2133#[cfg(feature = "v1_28")]
2134impl std::hash::Hash for StructureRef {
2135    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2136        use crate::value::GstValueExt;
2137        use std::hash::{DefaultHasher, Hasher};
2138
2139        let name = self.name();
2140        name.hash(state);
2141
2142        // re-implement gst_hash_structure() so the hashing is not depending on the fields order.
2143        let mut fields_hash = 0;
2144        for (field, value) in self.iter() {
2145            let mut field_hasher = DefaultHasher::new();
2146            field.hash(&mut field_hasher);
2147            let value_hash = value.hash().unwrap();
2148            value_hash.hash(&mut field_hasher);
2149
2150            fields_hash ^= field_hasher.finish();
2151        }
2152        fields_hash.hash(state);
2153    }
2154}
2155
2156#[cfg(feature = "v1_28")]
2157impl std::hash::Hash for Structure {
2158    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2159        self.as_ref().hash(state);
2160    }
2161}
2162
2163#[derive(Debug)]
2164#[must_use = "The builder must be built to be used"]
2165pub struct Builder {
2166    s: Structure,
2167}
2168
2169impl Builder {
2170    fn new(name: impl IntoGStr) -> Self {
2171        skip_assert_initialized!();
2172        Builder {
2173            s: Structure::new_empty(name),
2174        }
2175    }
2176
2177    fn from_static(name: impl AsRef<GStr> + 'static) -> Self {
2178        skip_assert_initialized!();
2179        Builder {
2180            s: Structure::new_empty_from_static(name),
2181        }
2182    }
2183
2184    pub fn from_id(name: impl AsRef<IdStr>) -> Builder {
2185        skip_assert_initialized!();
2186        Builder {
2187            s: Structure::new_empty_from_id(name),
2188        }
2189    }
2190
2191    // rustdoc-stripper-ignore-next
2192    /// Sets field `name` to the given value `value`.
2193    ///
2194    /// Overrides any default or previously defined value for `name`.
2195    #[inline]
2196    pub fn field(mut self, name: impl IntoGStr, value: impl Into<glib::Value> + Send) -> Self {
2197        self.s.set(name, value);
2198        self
2199    }
2200
2201    // rustdoc-stripper-ignore-next
2202    /// Sets field `name` to the given value `value`.
2203    ///
2204    /// Overrides any default or previously defined value for `name`.
2205    #[inline]
2206    pub fn field_with_static(
2207        mut self,
2208        name: impl AsRef<GStr> + 'static,
2209        value: impl Into<glib::Value> + Send,
2210    ) -> Self {
2211        self.s.set_with_static(name, value);
2212        self
2213    }
2214
2215    // rustdoc-stripper-ignore-next
2216    /// Sets field `name` to the given value `value`.
2217    ///
2218    /// Overrides any default or previously defined value for `name`.
2219    #[inline]
2220    pub fn field_with_id(
2221        mut self,
2222        name: impl AsRef<IdStr>,
2223        value: impl Into<glib::Value> + Send,
2224    ) -> Self {
2225        self.s.set_with_id(name, value);
2226        self
2227    }
2228
2229    impl_builder_gvalue_extra_setters!(field);
2230
2231    #[must_use = "Building the structure without using it has no effect"]
2232    pub fn build(self) -> Structure {
2233        self.s
2234    }
2235}
2236
2237#[cfg(test)]
2238mod tests {
2239    use super::*;
2240    use glib::gstr;
2241
2242    #[test]
2243    fn new_set_get() {
2244        use glib::{Type, value};
2245
2246        crate::init().unwrap();
2247
2248        let mut s = Structure::new_empty("test");
2249        assert_eq!(s.name(), "test");
2250
2251        s.set("f1", "abc");
2252        s.set("f2", String::from("bcd"));
2253        s.set("f3", 123i32);
2254        s.set("f5", Some("efg"));
2255        s.set("f7", 42i32);
2256
2257        assert_eq!(s.get::<&str>("f1"), Ok("abc"));
2258        assert_eq!(s.get::<Option<&str>>("f2"), Ok(Some("bcd")));
2259        assert_eq!(s.get::<i32>("f3"), Ok(123i32));
2260        assert_eq!(s.get_optional::<&str>("f1"), Ok(Some("abc")));
2261        assert_eq!(s.get_optional::<&str>("f4"), Ok(None));
2262        assert_eq!(s.get_optional::<i32>("f3"), Ok(Some(123i32)));
2263        assert_eq!(s.get_optional::<i32>("f4"), Ok(None));
2264        assert_eq!(s.get::<&str>("f5"), Ok("efg"));
2265        assert_eq!(s.get::<i32>("f7"), Ok(42i32));
2266
2267        assert_eq!(
2268            s.get::<i32>("f2"),
2269            Err(GetError::from_value_get_error(
2270                idstr!("f2"),
2271                value::ValueTypeMismatchError::new(Type::STRING, Type::I32),
2272            ))
2273        );
2274        assert_eq!(
2275            s.get::<bool>("f3"),
2276            Err(GetError::from_value_get_error(
2277                idstr!("f3"),
2278                value::ValueTypeMismatchError::new(Type::I32, Type::BOOL),
2279            ))
2280        );
2281        assert_eq!(
2282            s.get::<&str>("f4"),
2283            Err(GetError::new_field_not_found(idstr!("f4")))
2284        );
2285        assert_eq!(
2286            s.get::<i32>("f4"),
2287            Err(GetError::new_field_not_found(idstr!("f4")))
2288        );
2289
2290        assert_eq!(
2291            s.fields().collect::<Vec<_>>(),
2292            vec!["f1", "f2", "f3", "f5", "f7"]
2293        );
2294
2295        let v = s.iter().map(|(f, v)| (f, v.clone())).collect::<Vec<_>>();
2296        assert_eq!(v.len(), 5);
2297        assert_eq!(v[0].0, "f1");
2298        assert_eq!(v[0].1.get::<&str>(), Ok("abc"));
2299        assert_eq!(v[1].0, "f2");
2300        assert_eq!(v[1].1.get::<&str>(), Ok("bcd"));
2301        assert_eq!(v[2].0, "f3");
2302        assert_eq!(v[2].1.get::<i32>(), Ok(123i32));
2303        assert_eq!(v[3].0, "f5");
2304        assert_eq!(v[3].1.get::<&str>(), Ok("efg"));
2305        assert_eq!(v[4].0, "f7");
2306        assert_eq!(v[4].1.get::<i32>(), Ok(42i32));
2307
2308        let s2 = Structure::builder("test")
2309            .field("f1", "abc")
2310            .field("f2", String::from("bcd"))
2311            .field("f3", 123i32)
2312            .field_if_some("f4", Option::<i32>::None)
2313            .field_if_some("f5", Some("efg"))
2314            .field_if_some("f6", Option::<&str>::None)
2315            .field_if("f7", 42i32, true)
2316            .field_if("f8", 21i32, false)
2317            .build();
2318        assert_eq!(s, s2);
2319
2320        let mut s3 = Structure::new_empty("test");
2321
2322        s3.set_if_some("f1", Some("abc"));
2323        s3.set_if_some("f2", Some(String::from("bcd")));
2324        s3.set_if_some("f3", Some(123i32));
2325        s3.set_if_some("f4", Option::<i32>::None);
2326        s3.set_if_some("f5", Some("efg"));
2327        s3.set_if_some("f6", Option::<&str>::None);
2328        s3.set_if("f7", 42i32, true);
2329        s3.set_if("f8", 21i32, false);
2330        assert_eq!(s, s3);
2331    }
2332
2333    #[test]
2334    fn new_set_get_static() {
2335        use glib::{Type, value};
2336
2337        crate::init().unwrap();
2338
2339        let mut s = Structure::new_empty_from_static(gstr!("test"));
2340        assert_eq!(s.name(), "test");
2341
2342        static F1: &GStr = gstr!("f1");
2343        static F2: &GStr = gstr!("f2");
2344        static F3: &GStr = gstr!("f3");
2345
2346        s.set_with_static(F1, "abc");
2347        s.set_with_static_if(F2, String::from("bcd"), true);
2348        s.set_with_static_if(F3, "not_set", false);
2349
2350        assert_eq!(s.get::<&str>(F1), Ok("abc"));
2351        assert_eq!(s.get::<Option<&str>>(F2), Ok(Some("bcd")));
2352        assert_eq!(s.get_optional::<&str>(F1), Ok(Some("abc")));
2353        assert_eq!(s.get_optional::<&str>(F3), Ok(None));
2354
2355        assert_eq!(
2356            s.get::<i32>(F2),
2357            Err(GetError::from_value_get_error(
2358                idstr!("f2"),
2359                value::ValueTypeMismatchError::new(Type::STRING, Type::I32),
2360            ))
2361        );
2362        assert_eq!(
2363            s.get::<&str>(F3),
2364            Err(GetError::new_field_not_found(idstr!("f3")))
2365        );
2366
2367        let s2 = Structure::builder("test")
2368            .field_with_static(F1, "abc")
2369            .field_with_static(F2, String::from("bcd"))
2370            .build();
2371        assert_eq!(s, s2);
2372
2373        let mut s3 = Structure::new_empty("test");
2374
2375        s3.set_with_static_if_some(F1, Some("abc"));
2376        s3.set_with_static_if_some(F2, Some(String::from("bcd")));
2377
2378        assert_eq!(s, s3);
2379    }
2380
2381    #[test]
2382    fn new_set_get_id_str() {
2383        use glib::{Type, value};
2384
2385        crate::init().unwrap();
2386
2387        let mut s = Structure::new_empty_from_id(idstr!("test"));
2388        assert_eq!(s.name(), "test");
2389        #[cfg(feature = "v1_26")]
2390        assert_eq!(s.name_id(), "test");
2391
2392        let f1 = idstr!("f1");
2393        let f2 = idstr!("f2");
2394        let f3 = idstr!("f3");
2395
2396        s.set_with_id(&f1, "abc");
2397        s.set_with_id_if(&f2, String::from("bcd"), true);
2398        s.set_with_id_if(&f3, "not_set", false);
2399
2400        assert_eq!(s.get_by_id::<&str>(&f1), Ok("abc"));
2401        assert_eq!(s.get_by_id::<&str>(f1.clone()), Ok("abc"));
2402        assert_eq!(s.get_by_id::<Option<&str>>(&f2), Ok(Some("bcd")));
2403        assert_eq!(s.get_by_id::<Option<&str>>(f2.clone()), Ok(Some("bcd")));
2404        assert_eq!(s.get_optional_by_id::<&str>(&f1), Ok(Some("abc")));
2405        assert_eq!(s.get_optional_by_id::<&str>(&f3), Ok(None));
2406
2407        assert_eq!(
2408            s.get_by_id::<i32>(&f2),
2409            Err(GetError::from_value_get_error(
2410                f2.clone(),
2411                value::ValueTypeMismatchError::new(Type::STRING, Type::I32),
2412            ))
2413        );
2414        assert_eq!(
2415            s.get_by_id::<&str>(&f3),
2416            Err(GetError::new_field_not_found(f3.clone()))
2417        );
2418
2419        let s2 = Structure::builder("test")
2420            .field_with_id(&f1, "abc")
2421            .field_with_id(&f2, String::from("bcd"))
2422            .build();
2423        assert_eq!(s, s2);
2424
2425        let mut s3 = Structure::new_empty("test");
2426
2427        s3.set_with_id_if_some(f1, Some("abc"));
2428        s3.set_with_id_if_some(f2, Some(String::from("bcd")));
2429
2430        assert_eq!(s, s3);
2431    }
2432
2433    #[test]
2434    fn test_string_conversion() {
2435        crate::init().unwrap();
2436
2437        let a = "Test, f1=(string)abc, f2=(uint)123;";
2438
2439        let s = a.parse::<Structure>().unwrap();
2440        assert_eq!(s.get::<&str>("f1"), Ok("abc"));
2441        assert_eq!(s.get::<u32>("f2"), Ok(123));
2442
2443        assert_eq!(a, s.to_string());
2444    }
2445
2446    #[test]
2447    fn test_from_value_optional() {
2448        use glib::value::ToValue;
2449
2450        crate::init().unwrap();
2451
2452        let a = None::<&Structure>.to_value();
2453        assert!(a.get::<Option<Structure>>().unwrap().is_none());
2454        let b = "foo".parse::<Structure>().unwrap().to_value();
2455        assert!(b.get::<Option<Structure>>().unwrap().is_some());
2456    }
2457
2458    #[test]
2459    fn test_new_from_iter() {
2460        crate::init().unwrap();
2461
2462        let s = Structure::builder("test")
2463            .field("f1", "abc")
2464            .field_with_static(gstr!("f2"), String::from("bcd"))
2465            .field_with_id(idstr!("f3"), 123i32)
2466            .build();
2467
2468        let s2 = Structure::from_iter(
2469            s.name(),
2470            s.iter()
2471                .filter(|(f, _)| *f == "f1")
2472                .map(|(f, v)| (f, v.clone())),
2473        );
2474
2475        assert_eq!(s2.name(), "test");
2476        assert_eq!(s2.get::<&str>("f1"), Ok("abc"));
2477        assert!(s2.get::<&str>("f2").is_err());
2478        assert!(s2.get_by_id::<&str>(idstr!("f3")).is_err());
2479    }
2480
2481    #[test]
2482    fn test_debug() {
2483        crate::init().unwrap();
2484
2485        let s = Structure::builder("test")
2486            .field("f1", "abc")
2487            .field("f2", String::from("bcd"))
2488            .field("f3", 123i32)
2489            .field(
2490                "f4",
2491                Structure::builder("nested").field("badger", true).build(),
2492            )
2493            .field("f5", crate::Array::new(["a", "b", "c"]))
2494            .field("f6", crate::List::new(["d", "e", "f"]))
2495            .build();
2496
2497        assert_eq!(
2498            format!("{s:?}"),
2499            "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\"]) })"
2500        );
2501    }
2502
2503    #[test]
2504    fn builder_field_from_iter() {
2505        crate::init().unwrap();
2506
2507        static SLIST: &GStr = gstr!("slist");
2508        let ilist = idstr!("ilist");
2509        let s = Structure::builder("test")
2510            .field_from_iter::<crate::Array, i32>("array", [1, 2, 3])
2511            .field_with_static_from_iter::<crate::List, i32>(SLIST, [4, 5, 6])
2512            .field_with_id_from_iter::<crate::List, i32>(&ilist, [7, 8, 9])
2513            .build();
2514        assert!(
2515            s.get::<crate::Array>("array")
2516                .unwrap()
2517                .iter()
2518                .map(|val| val.get::<i32>().unwrap())
2519                .eq([1, 2, 3])
2520        );
2521        assert!(
2522            s.get::<crate::List>("slist")
2523                .unwrap()
2524                .iter()
2525                .map(|val| val.get::<i32>().unwrap())
2526                .eq([4, 5, 6])
2527        );
2528        assert!(
2529            s.get_by_id::<crate::List>(&ilist)
2530                .unwrap()
2531                .iter()
2532                .map(|val| val.get::<i32>().unwrap())
2533                .eq([7, 8, 9])
2534        );
2535
2536        let array = Vec::<i32>::new();
2537        let s = Structure::builder("test")
2538            .field_from_iter::<crate::Array, _>("array", &array)
2539            .field_with_static_from_iter::<crate::List, _>(SLIST, &array)
2540            .field_with_id_from_iter::<crate::List, _>(&ilist, &array)
2541            .build();
2542        assert!(s.get::<crate::Array>("array").unwrap().as_ref().is_empty());
2543        assert!(s.get::<crate::List>(SLIST).unwrap().as_ref().is_empty());
2544        assert!(
2545            s.get_by_id::<crate::List>(ilist)
2546                .unwrap()
2547                .as_ref()
2548                .is_empty()
2549        );
2550    }
2551
2552    #[test]
2553    fn builder_field_if_not_empty() {
2554        crate::init().unwrap();
2555
2556        static SLIST: &GStr = gstr!("slist");
2557        let ilist = idstr!("ilist");
2558        let s = Structure::builder_from_id(idstr!("test"))
2559            .field_if_not_empty::<crate::Array, i32>("array", [1, 2, 3])
2560            .field_with_static_if_not_empty::<crate::List, i32>(SLIST, [4, 5, 6])
2561            .field_with_id_if_not_empty::<crate::List, i32>(&ilist, [7, 8, 9])
2562            .build();
2563        assert!(
2564            s.get::<crate::Array>("array")
2565                .unwrap()
2566                .iter()
2567                .map(|val| val.get::<i32>().unwrap())
2568                .eq([1, 2, 3])
2569        );
2570        assert!(
2571            s.get::<crate::List>("slist")
2572                .unwrap()
2573                .iter()
2574                .map(|val| val.get::<i32>().unwrap())
2575                .eq([4, 5, 6])
2576        );
2577        assert!(
2578            s.get_by_id::<crate::List>(&ilist)
2579                .unwrap()
2580                .iter()
2581                .map(|val| val.get::<i32>().unwrap())
2582                .eq([7, 8, 9])
2583        );
2584
2585        let array = Vec::<i32>::new();
2586        let s = Structure::builder("test")
2587            .field_if_not_empty::<crate::Array, _>("array", &array)
2588            .field_with_static_if_not_empty::<crate::List, _>(SLIST, &array)
2589            .field_with_id_if_not_empty::<crate::List, _>(ilist, &array)
2590            .build();
2591        assert!(!s.has_field("array"));
2592        assert!(!s.has_field("slist"));
2593        assert!(!s.has_field("ilist"));
2594    }
2595
2596    #[test]
2597    fn nth_field_remove_field() {
2598        crate::init().unwrap();
2599
2600        let f3 = idstr!("f3");
2601        let f5 = idstr!("f5");
2602        let f8 = idstr!("f8");
2603        let mut s = Structure::builder("test")
2604            .field("f1", "abc")
2605            .field("f2", "bcd")
2606            .field_with_id(&f3, "cde")
2607            .field("f4", "def")
2608            .field_with_id(&f5, "efg")
2609            .field("f6", "fgh")
2610            .field("f7", "ghi")
2611            .field_with_id(&f8, "hij")
2612            .build();
2613
2614        assert_eq!(s.iter().next().unwrap().0, "f1");
2615        assert_eq!(
2616            s.fields().collect::<Vec<_>>(),
2617            vec!["f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8"]
2618        );
2619        assert!(s.has_field("f8"));
2620        assert_eq!(s.nth_field_name(7), Some(gstr!("f8")));
2621        assert!(s.nth_field_name(8).is_none());
2622
2623        #[cfg(feature = "v1_26")]
2624        assert_eq!(s.id_iter().next().unwrap().0, "f1");
2625        #[cfg(feature = "v1_26")]
2626        assert_eq!(
2627            s.field_ids().collect::<Vec<_>>(),
2628            vec!["f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8"]
2629        );
2630        #[cfg(feature = "v1_26")]
2631        assert!(s.has_field_by_id(&f8));
2632        #[cfg(feature = "v1_26")]
2633        assert_eq!(s.nth_field_by_id(7), Some(&f8));
2634        #[cfg(feature = "v1_26")]
2635        assert!(s.nth_field_by_id(8).is_none());
2636
2637        assert_eq!(s.nth_field_name(1), Some(gstr!("f2")));
2638        s.remove_field("f2");
2639        assert_eq!(s.nth_field_name(1), Some(gstr!("f3")));
2640        assert!(s.nth_field_name(7).is_none());
2641        assert_eq!(
2642            s.fields().collect::<Vec<_>>(),
2643            vec!["f1", "f3", "f4", "f5", "f6", "f7", "f8"]
2644        );
2645
2646        assert_eq!(s.nth_field_name(1), Some(gstr!("f3")));
2647        s.remove_field_by_id(&f3);
2648        assert_eq!(s.nth_field_name(1), Some(gstr!("f4")));
2649        assert!(s.nth_field_name(6).is_none());
2650        #[cfg(feature = "v1_26")]
2651        assert_eq!(s.nth_field_by_id(2), Some(&f5));
2652        #[cfg(feature = "v1_26")]
2653        assert!(s.nth_field_by_id(6).is_none());
2654        assert_eq!(
2655            s.fields().collect::<Vec<_>>(),
2656            vec!["f1", "f4", "f5", "f6", "f7", "f8"]
2657        );
2658
2659        s.remove_fields(["f4", "f6"]);
2660        assert_eq!(s.fields().collect::<Vec<_>>(), vec!["f1", "f5", "f7", "f8"]);
2661
2662        s.remove_field_by_ids([&f5, &f8]);
2663        assert_eq!(s.fields().collect::<Vec<_>>(), vec!["f1", "f7"]);
2664        #[cfg(feature = "v1_26")]
2665        assert_eq!(s.field_ids().collect::<Vec<_>>(), vec!["f1", "f7"]);
2666
2667        s.remove_all_fields();
2668        assert!(s.is_empty());
2669    }
2670
2671    #[cfg(feature = "v1_26")]
2672    #[test]
2673    fn map_in_place() {
2674        crate::init().unwrap();
2675
2676        let f1 = idstr!("f1");
2677        let f2 = idstr!("f2");
2678        let f3 = idstr!("f3");
2679        let mut s = Structure::builder_from_id(idstr!("test"))
2680            .field_with_id(&f1, "abc")
2681            .field_with_id(&f2, "bcd")
2682            .field_with_id(&f3, false)
2683            .build();
2684        assert!(!s.get_by_id::<bool>(&f3).unwrap());
2685
2686        s.map_in_place_by_id(|name, value| {
2687            if *name == f3 {
2688                *value = true.into()
2689            }
2690
2691            std::ops::ControlFlow::Continue(())
2692        });
2693        assert!(s.get_by_id::<bool>(&f3).unwrap());
2694
2695        s.map_in_place_by_id(|name, value| {
2696            match name.as_str() {
2697                "f2" => return std::ops::ControlFlow::Break(()),
2698                "f3" => *value = false.into(),
2699                _ => (),
2700            }
2701            std::ops::ControlFlow::Continue(())
2702        });
2703        assert!(s.get_by_id::<bool>(&f3).unwrap());
2704
2705        s.filter_map_in_place_by_id(|name, value| {
2706            if *name == f3 && value.get::<bool>().unwrap() {
2707                None
2708            } else {
2709                Some(value)
2710            }
2711        });
2712
2713        assert_eq!(s.field_ids().collect::<Vec<_>>(), vec![&f1, &f2]);
2714    }
2715
2716    #[cfg(feature = "v1_28")]
2717    #[test]
2718    fn test_hash() {
2719        crate::init().unwrap();
2720
2721        use std::hash::BuildHasher;
2722        let bh = std::hash::RandomState::new();
2723
2724        // Different names
2725        let s1 = Structure::builder("test1").build();
2726        let s2 = Structure::builder("test2").build();
2727        assert_eq!(bh.hash_one(&s1), bh.hash_one(&s1));
2728        assert_eq!(bh.hash_one(&s2), bh.hash_one(&s2));
2729        assert_ne!(bh.hash_one(&s1), bh.hash_one(&s2));
2730
2731        // Same name different fields
2732        let s1 = Structure::builder("test").field("a", 1u32).build();
2733        let s2 = Structure::builder("test").field("b", 1u32).build();
2734        assert_eq!(bh.hash_one(&s1), bh.hash_one(&s1));
2735        assert_eq!(bh.hash_one(&s2), bh.hash_one(&s2));
2736        assert_ne!(bh.hash_one(&s1), bh.hash_one(&s2));
2737
2738        // Same name different field values
2739        let s1 = Structure::builder("test").field("a", 1u32).build();
2740        let s2 = Structure::builder("test").field("a", 2u32).build();
2741        assert_eq!(bh.hash_one(&s1), bh.hash_one(&s1));
2742        assert_eq!(bh.hash_one(&s2), bh.hash_one(&s2));
2743        assert_ne!(bh.hash_one(&s1), bh.hash_one(&s2));
2744
2745        // Same structure but fields in a different order
2746        let s1 = Structure::builder("test")
2747            .field("a", 1u32)
2748            .field("b", 2u32)
2749            .build();
2750        let s2 = Structure::builder("test")
2751            .field("b", 2u32)
2752            .field("a", 1u32)
2753            .build();
2754        assert_eq!(bh.hash_one(&s1), bh.hash_one(&s1));
2755        assert_eq!(bh.hash_one(&s2), bh.hash_one(&s2));
2756        assert_eq!(bh.hash_one(&s1), bh.hash_one(&s2));
2757    }
2758}