gstreamer_analytics/
relation_meta.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::translate::*;
4use gst::prelude::*;
5use std::marker::PhantomData;
6
7use crate::{ffi, RelTypes};
8
9#[repr(transparent)]
10#[doc(alias = "GstAnalyticsRelationMeta")]
11pub struct AnalyticsRelationMeta(ffi::GstAnalyticsRelationMeta);
12
13unsafe impl Send for AnalyticsRelationMeta {}
14unsafe impl Sync for AnalyticsRelationMeta {}
15
16#[derive(Debug, Copy, Clone)]
17#[doc(alias = "GstAnalyticsRelationMetaInitParams")]
18pub struct AnalyticsRelationMetaInitParams(ffi::GstAnalyticsRelationMetaInitParams);
19
20impl Default for AnalyticsRelationMetaInitParams {
21    fn default() -> Self {
22        Self(ffi::GstAnalyticsRelationMetaInitParams {
23            initial_relation_order: 0,
24            initial_buf_size: 0,
25        })
26    }
27}
28
29impl AnalyticsRelationMetaInitParams {
30    pub fn new(initial_relation_order: usize, initial_buf_size: usize) -> Self {
31        skip_assert_initialized!();
32        Self(ffi::GstAnalyticsRelationMetaInitParams {
33            initial_relation_order,
34            initial_buf_size,
35        })
36    }
37}
38
39#[derive(Debug, Clone)]
40pub struct AnalyticsMtdRef<'a, T: AnalyticsMtd> {
41    id: u32,
42    meta: gst::MetaRef<'a, AnalyticsRelationMeta>,
43    mtd_type: PhantomData<&'a T>,
44}
45
46#[derive(Debug)]
47pub struct AnalyticsMtdRefMut<'a, T: AnalyticsMtd> {
48    id: u32,
49    meta: &'a mut gst::MetaRefMut<'a, AnalyticsRelationMeta, gst::meta::Standalone>,
50    mtd_type: PhantomData<&'a T>,
51}
52
53pub struct AnalyticsRelationPath {
54    garray: *mut glib::ffi::GArray,
55}
56
57impl std::fmt::Debug for AnalyticsRelationMeta {
58    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
59        f.debug_struct("AnalyticsRelationMeta")
60            .field("len", &self.len())
61            .finish()
62    }
63}
64
65impl AnalyticsRelationMeta {
66    #[doc(alias = "gst_buffer_add_analytics_relation_meta")]
67    pub fn add(buffer: &mut gst::BufferRef) -> gst::MetaRefMut<Self, gst::meta::Standalone> {
68        skip_assert_initialized!();
69
70        unsafe {
71            let meta_ptr = ffi::gst_buffer_add_analytics_relation_meta(buffer.as_mut_ptr());
72            Self::from_mut_ptr(buffer, meta_ptr)
73        }
74    }
75
76    #[doc(alias = "gst_buffer_add_analytics_relation_meta_full")]
77    pub fn add_full<'a>(
78        buffer: &'a mut gst::BufferRef,
79        init_params: &AnalyticsRelationMetaInitParams,
80    ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
81        skip_assert_initialized!();
82
83        unsafe {
84            let meta_ptr = ffi::gst_buffer_add_analytics_relation_meta_full(
85                buffer.as_mut_ptr(),
86                mut_override(&init_params.0),
87            );
88            Self::from_mut_ptr(buffer, meta_ptr)
89        }
90    }
91
92    #[doc(alias = "gst_analytics_relation_get_length")]
93    pub fn len(&self) -> usize {
94        unsafe { ffi::gst_analytics_relation_get_length(self.as_mut_ptr()) }
95    }
96
97    pub fn is_empty(&self) -> bool {
98        self.len() == 0
99    }
100
101    #[doc(alias = "gst_analytics_relation_meta_set_relation")]
102    pub fn set_relation(
103        &mut self,
104        type_: crate::RelTypes,
105        an_meta_first_id: u32,
106        an_meta_second_id: u32,
107    ) -> Result<(), glib::BoolError> {
108        let ret = unsafe {
109            from_glib(ffi::gst_analytics_relation_meta_set_relation(
110                self.as_mut_ptr(),
111                type_.into_glib(),
112                an_meta_first_id,
113                an_meta_second_id,
114            ))
115        };
116
117        if ret {
118            Ok(())
119        } else {
120            Err(glib::bool_error!(
121                "Could not set relation {:}->{:} of type {:?}",
122                an_meta_first_id,
123                an_meta_second_id,
124                type_
125            ))
126        }
127    }
128
129    #[doc(alias = "gst_analytics_relation_meta_get_relation")]
130    pub fn relation(&self, an_meta_first_id: u32, an_meta_second_id: u32) -> crate::RelTypes {
131        unsafe {
132            from_glib(ffi::gst_analytics_relation_meta_get_relation(
133                self.as_mut_ptr(),
134                an_meta_first_id,
135                an_meta_second_id,
136            ))
137        }
138    }
139
140    #[doc(alias = "gst_analytics_relation_meta_exist")]
141    pub fn exist(
142        &self,
143        an_meta_first_id: u32,
144        an_meta_second_id: u32,
145        relation_span: i32,
146        cond_types: crate::RelTypes,
147    ) -> bool {
148        unsafe {
149            from_glib(ffi::gst_analytics_relation_meta_exist(
150                self.as_mut_ptr(),
151                an_meta_first_id,
152                an_meta_second_id,
153                relation_span,
154                cond_types.into_glib(),
155                std::ptr::null_mut(),
156            ))
157        }
158    }
159
160    #[doc(alias = "gst_analytics_relation_meta_exist")]
161    pub fn exist_path(
162        &self,
163        an_meta_first_id: u32,
164        an_meta_second_id: u32,
165        relation_span: i32,
166        cond_types: crate::RelTypes,
167    ) -> Result<AnalyticsRelationPath, glib::BoolError> {
168        let mut array = std::ptr::null_mut::<glib::ffi::GArray>();
169        let ret = unsafe {
170            from_glib(ffi::gst_analytics_relation_meta_exist(
171                self.as_mut_ptr(),
172                an_meta_first_id,
173                an_meta_second_id,
174                relation_span,
175                cond_types.into_glib(),
176                &mut array,
177            ))
178        };
179
180        if ret {
181            Ok(AnalyticsRelationPath { garray: array })
182        } else {
183            Err(glib::bool_error!("Such relation doesn't exist"))
184        }
185    }
186
187    pub unsafe fn as_mut_ptr(&self) -> *mut ffi::GstAnalyticsRelationMeta {
188        mut_override(&self.0)
189    }
190}
191
192impl UnsafeFrom<&AnalyticsRelationMeta> for ffi::GstAnalyticsMtd {
193    unsafe fn unsafe_from(t: &AnalyticsRelationMeta) -> Self {
194        ffi::GstAnalyticsMtd {
195            id: 0,
196            meta: t.as_mut_ptr(),
197        }
198    }
199}
200
201impl AnalyticsRelationPath {
202    pub fn as_slice(&self) -> &[u32] {
203        unsafe {
204            std::slice::from_raw_parts(
205                (*self.garray).data as *const u32,
206                (*self.garray).len as usize,
207            )
208        }
209    }
210}
211
212impl Drop for AnalyticsRelationPath {
213    fn drop(&mut self) {
214        unsafe {
215            glib::ffi::g_array_free(self.garray, glib::ffi::GTRUE);
216        }
217    }
218}
219
220mod sealed {
221    pub trait Sealed {}
222    impl<T> Sealed for T {}
223}
224
225pub trait AnalyticsMetaRefExt<'a>: sealed::Sealed {
226    #[doc(alias = "gst_analytics_relation_meta_get_mtd")]
227    fn mtd<T: AnalyticsMtd>(&self, an_meta_id: u32) -> Option<AnalyticsMtdRef<'a, T>>;
228    fn iter<T: AnalyticsMtd>(&'a self) -> AnalyticsMtdIter<'a, T>;
229    fn iter_direct_related<T: AnalyticsMtd>(
230        &'a self,
231        an_meta_id: u32,
232        rel_type: RelTypes,
233    ) -> AnalyticsMtdIter<'a, T>;
234}
235
236impl<'a> AnalyticsMetaRefExt<'a> for gst::MetaRef<'a, AnalyticsRelationMeta> {
237    fn mtd<T: AnalyticsMtd>(&self, an_meta_id: u32) -> Option<AnalyticsMtdRef<'a, T>> {
238        unsafe {
239            let mut mtd = std::mem::MaybeUninit::uninit();
240            let ret = from_glib(ffi::gst_analytics_relation_meta_get_mtd(
241                self.as_mut_ptr(),
242                an_meta_id,
243                T::mtd_type(),
244                mtd.as_mut_ptr(),
245            ));
246            let id = mtd.assume_init().id;
247
248            if ret {
249                Some(AnalyticsMtdRef::from_meta(self, id))
250            } else {
251                None
252            }
253        }
254    }
255
256    fn iter<T: AnalyticsMtd>(&'a self) -> AnalyticsMtdIter<'a, T> {
257        AnalyticsMtdIter::new(self)
258    }
259    fn iter_direct_related<T: AnalyticsMtd>(
260        &'a self,
261        an_meta_id: u32,
262        rel_type: RelTypes,
263    ) -> AnalyticsMtdIter<'a, T> {
264        AnalyticsMtdIter::new_direct_related(self, an_meta_id, rel_type.into_glib())
265    }
266}
267
268impl<'a, T: AnalyticsMtd> AnalyticsMtdRef<'a, T> {
269    pub fn id(&self) -> u32 {
270        self.id
271    }
272
273    pub unsafe fn from_meta(meta: &gst::MetaRef<'a, AnalyticsRelationMeta>, id: u32) -> Self {
274        skip_assert_initialized!();
275        AnalyticsMtdRef {
276            meta: meta.clone(),
277            id,
278            mtd_type: PhantomData,
279        }
280    }
281
282    #[doc(alias = "gst_analytics_mtd_get_mtd_type")]
283    pub fn mtd_type(&self) -> ffi::GstAnalyticsMtdType {
284        unsafe {
285            let mtd = ffi::GstAnalyticsMtd::unsafe_from(self);
286            ffi::gst_analytics_mtd_get_mtd_type(&mtd)
287        }
288    }
289}
290impl<'a> AnalyticsMtdRef<'a, AnalyticsAnyMtd> {
291    pub fn downcast<T: AnalyticsMtd>(
292        self,
293    ) -> Result<AnalyticsMtdRef<'a, T>, AnalyticsMtdRef<'a, AnalyticsAnyMtd>> {
294        if self.mtd_type() == T::mtd_type() {
295            Ok(AnalyticsMtdRef {
296                id: self.id,
297                meta: self.meta,
298                mtd_type: PhantomData,
299            })
300        } else {
301            Err(self)
302        }
303    }
304
305    pub fn downcast_ref<T: AnalyticsMtd>(&self) -> Option<&AnalyticsMtdRef<'a, T>> {
306        unsafe {
307            if self.mtd_type() == T::mtd_type() {
308                Some(&*(self as *const _ as *const _))
309            } else {
310                None
311            }
312        }
313    }
314}
315
316impl<'a> AnalyticsMtdRefMut<'a, AnalyticsAnyMtd> {
317    pub fn downcast_mut<T: AnalyticsMtd>(&mut self) -> Option<&mut AnalyticsMtdRefMut<'a, T>> {
318        unsafe {
319            if self.as_ref().mtd_type() == T::mtd_type() {
320                Some(&mut *(self as *mut _ as *mut _))
321            } else {
322                None
323            }
324        }
325    }
326}
327
328impl<'a, T: AnalyticsMtd> UnsafeFrom<&AnalyticsMtdRef<'a, T>> for ffi::GstAnalyticsMtd {
329    unsafe fn unsafe_from(t: &AnalyticsMtdRef<'a, T>) -> Self {
330        ffi::GstAnalyticsMtd {
331            id: t.id,
332            meta: t.meta.as_mut_ptr(),
333        }
334    }
335}
336
337pub trait AnalyticsMetaRefMutExt<'a>: sealed::Sealed {
338    #[doc(alias = "gst_analytics_relation_meta_get_mtd")]
339    fn mtd_mut<T: AnalyticsMtd>(&'a mut self, an_meta_id: u32)
340        -> Option<AnalyticsMtdRefMut<'a, T>>;
341
342    fn iter_mut<T: AnalyticsMtd>(&'a mut self) -> AnalyticsMtdIterMut<'a, T>;
343    fn iter_direct_related_mut<T: AnalyticsMtd>(
344        &'a mut self,
345        an_meta_id: u32,
346        rel_type: RelTypes,
347    ) -> AnalyticsMtdIterMut<'a, T>;
348}
349
350impl<'a> AnalyticsMetaRefMutExt<'a>
351    for gst::MetaRefMut<'a, AnalyticsRelationMeta, gst::meta::Standalone>
352{
353    fn mtd_mut<T: AnalyticsMtd>(
354        &'a mut self,
355        an_meta_id: u32,
356    ) -> Option<AnalyticsMtdRefMut<'a, T>> {
357        unsafe {
358            let mut mtd = std::mem::MaybeUninit::uninit();
359            let ret = from_glib(ffi::gst_analytics_relation_meta_get_mtd(
360                self.as_mut_ptr(),
361                an_meta_id,
362                T::mtd_type(),
363                mtd.as_mut_ptr(),
364            ));
365            let id = mtd.assume_init().id;
366
367            if ret {
368                Some(AnalyticsMtdRefMut::from_meta(self, id))
369            } else {
370                None
371            }
372        }
373    }
374
375    fn iter_mut<T: AnalyticsMtd>(&'a mut self) -> AnalyticsMtdIterMut<'a, T> {
376        AnalyticsMtdIterMut::new(self)
377    }
378    fn iter_direct_related_mut<T: AnalyticsMtd>(
379        &'a mut self,
380        an_meta_id: u32,
381        rel_type: RelTypes,
382    ) -> AnalyticsMtdIterMut<'a, T> {
383        AnalyticsMtdIterMut::new_direct_related(self, an_meta_id, rel_type.into_glib())
384    }
385}
386
387unsafe impl MetaAPI for AnalyticsRelationMeta {
388    type GstType = ffi::GstAnalyticsRelationMeta;
389
390    #[doc(alias = "gst_analytics_relation_meta_api_get_type")]
391    #[inline]
392    fn meta_api() -> glib::Type {
393        unsafe { from_glib(ffi::gst_analytics_relation_meta_api_get_type()) }
394    }
395}
396
397pub unsafe trait AnalyticsMtd {
398    fn mtd_type() -> ffi::GstAnalyticsMtdType;
399}
400
401pub trait AnalyticsMtdExt: AnalyticsMtd {
402    #[doc(alias = "gst_analytics_mtd_type_get_name")]
403    fn type_name() -> &'static str {
404        unsafe {
405            let ptr = ffi::gst_analytics_mtd_type_get_name(Self::mtd_type());
406            std::ffi::CStr::from_ptr(ptr).to_str().unwrap()
407        }
408    }
409}
410
411impl<T: AnalyticsMtd> AnalyticsMtdExt for T {}
412
413impl<'a, T: AnalyticsMtd> AnalyticsMtdRefMut<'a, T> {
414    pub fn id(&self) -> u32 {
415        self.id
416    }
417
418    pub unsafe fn from_meta(
419        meta: &'a mut gst::MetaRefMut<'a, AnalyticsRelationMeta, gst::meta::Standalone>,
420        id: u32,
421    ) -> Self {
422        skip_assert_initialized!();
423        AnalyticsMtdRefMut {
424            meta,
425            id,
426            mtd_type: PhantomData,
427        }
428    }
429}
430
431impl<'a, T: AnalyticsMtd> UnsafeFrom<&mut AnalyticsMtdRefMut<'a, T>> for ffi::GstAnalyticsMtd {
432    unsafe fn unsafe_from(t: &mut AnalyticsMtdRefMut<'a, T>) -> Self {
433        ffi::GstAnalyticsMtd {
434            id: t.id,
435            meta: t.meta.as_mut_ptr(),
436        }
437    }
438}
439
440impl<'a, T: AnalyticsMtd> From<AnalyticsMtdRefMut<'a, T>> for AnalyticsMtdRef<'a, T> {
441    fn from(value: AnalyticsMtdRefMut<'a, T>) -> Self {
442        skip_assert_initialized!();
443        AnalyticsMtdRef {
444            meta: value.meta.as_ref().clone(),
445            id: value.id,
446            mtd_type: value.mtd_type,
447        }
448    }
449}
450
451impl<'a, T: AnalyticsMtd> From<&mut AnalyticsMtdRefMut<'a, T>> for AnalyticsMtdRef<'a, T> {
452    fn from(value: &mut AnalyticsMtdRefMut<'a, T>) -> Self {
453        skip_assert_initialized!();
454        AnalyticsMtdRef {
455            meta: value.meta.as_ref().clone(),
456            id: value.id,
457            mtd_type: value.mtd_type,
458        }
459    }
460}
461
462impl<'a, T: AnalyticsMtd> AsRef<AnalyticsMtdRef<'a, T>> for AnalyticsMtdRefMut<'a, T> {
463    #[inline]
464    fn as_ref(&self) -> &AnalyticsMtdRef<'a, T> {
465        unsafe { &*(self as *const AnalyticsMtdRefMut<'a, T> as *const AnalyticsMtdRef<'a, T>) }
466    }
467}
468
469macro_rules! define_mtd_iter {
470    ($name:ident, $metaref:ty, $itemref:ty, $copy_meta:expr) => {
471        #[must_use = "iterators are lazy and do nothing unless consumed"]
472        pub struct $name<'a, T: AnalyticsMtd> {
473            meta: $metaref,
474            state: glib::ffi::gpointer,
475            mtd_type: ffi::GstAnalyticsMtdType,
476            an_meta_id: u32,
477            rel_type: ffi::GstAnalyticsRelTypes,
478            phantom: std::marker::PhantomData<T>,
479        }
480
481        impl<'a, T: AnalyticsMtd> $name<'a, T> {
482            fn new(meta: $metaref) -> Self {
483                skip_assert_initialized!();
484                $name {
485                    meta,
486                    state: std::ptr::null_mut(),
487                    mtd_type: T::mtd_type(),
488                    an_meta_id: u32::MAX,
489                    rel_type: RelTypes::ANY.into_glib(),
490                    phantom: PhantomData,
491                }
492            }
493            fn new_direct_related(
494                meta: $metaref,
495                an_meta_id: u32,
496                rel_type: ffi::GstAnalyticsRelTypes,
497            ) -> Self {
498                skip_assert_initialized!();
499                $name {
500                    meta,
501                    state: std::ptr::null_mut(),
502                    mtd_type: T::mtd_type(),
503                    an_meta_id,
504                    rel_type,
505                    phantom: PhantomData,
506                }
507            }
508        }
509
510        impl<'a, T: AnalyticsMtd + 'a> Iterator for $name<'a, T> {
511            type Item = $itemref;
512
513            fn next(&mut self) -> Option<Self::Item> {
514                unsafe {
515                    let mut mtd = ffi::GstAnalyticsMtd::unsafe_from(&**self.meta);
516                    let ret = {
517                        if self.an_meta_id == u32::MAX {
518                            ffi::gst_analytics_relation_meta_iterate(
519                                self.meta.as_mut_ptr(),
520                                &mut self.state,
521                                self.mtd_type,
522                                &mut mtd,
523                            )
524                        } else {
525                            ffi::gst_analytics_relation_meta_get_direct_related(
526                                self.meta.as_mut_ptr(),
527                                self.an_meta_id,
528                                self.rel_type,
529                                self.mtd_type,
530                                &mut self.state,
531                                &mut mtd,
532                            )
533                        }
534                    };
535                    if from_glib(ret) {
536                        // This is a known clippy limitation
537                        // https://github.com/rust-lang/rust-clippy/issues/1553
538                        #[allow(clippy::redundant_closure_call)]
539                        Some(Self::Item::from_meta($copy_meta(self.meta), mtd.id))
540                    } else {
541                        None
542                    }
543                }
544            }
545        }
546    };
547}
548
549define_mtd_iter!(
550    AnalyticsMtdIter,
551    &'a gst::MetaRef<'a, AnalyticsRelationMeta>,
552    AnalyticsMtdRef<'a, T>,
553    |meta| meta
554);
555
556define_mtd_iter!(
557    AnalyticsMtdIterMut,
558    &'a mut gst::MetaRefMut<'a, AnalyticsRelationMeta, gst::meta::Standalone>,
559    AnalyticsMtdRefMut<'a, T>,
560    |meta: &mut _| &mut *(meta as *mut gst::MetaRefMut<
561        'a,
562        AnalyticsRelationMeta,
563        gst::meta::Standalone,
564    >)
565);
566
567#[derive(Debug)]
568pub enum AnalyticsAnyMtd {}
569
570unsafe impl AnalyticsMtd for AnalyticsAnyMtd {
571    fn mtd_type() -> ffi::GstAnalyticsMtdType {
572        ffi::GST_ANALYTICS_MTD_TYPE_ANY as ffi::GstAnalyticsMtdType
573    }
574}
575
576#[cfg(test)]
577mod tests {
578    use crate::*;
579
580    #[test]
581    fn build_relation_meta() {
582        gst::init().unwrap();
583
584        let mut buf = gst::Buffer::new();
585
586        let meta = AnalyticsRelationMeta::add(buf.make_mut());
587
588        assert!(meta.is_empty());
589    }
590
591    #[test]
592    fn build_relation_meta_full() {
593        gst::init().unwrap();
594
595        let mut buf = gst::Buffer::new();
596
597        let params = AnalyticsRelationMetaInitParams::new(10, 10);
598        let meta = AnalyticsRelationMeta::add_full(buf.make_mut(), &params);
599
600        assert!(meta.is_empty());
601    }
602
603    #[test]
604    fn relations() {
605        gst::init().unwrap();
606
607        let mut buf = gst::Buffer::new();
608        let _ = AnalyticsRelationMeta::add(buf.make_mut());
609
610        let mut meta = buf.make_mut().meta_mut::<AnalyticsRelationMeta>().unwrap();
611        let od = meta
612            .add_od_mtd(glib::Quark::from_str("blb"), 0, 1, 10, 20, 0.8)
613            .unwrap();
614        let od1_id = od.id();
615
616        let od = meta
617            .add_od_mtd(glib::Quark::from_str("blb"), 0, 1, 10, 20, 0.8)
618            .unwrap();
619        let od2_id = od.id();
620
621        let od: AnalyticsMtdRef<'_, AnalyticsODMtd> = meta
622            .add_od_mtd(glib::Quark::from_str("blb"), 0, 1, 10, 20, 0.8)
623            .unwrap();
624        let od3_id = od.id();
625
626        meta.set_relation(RelTypes::IS_PART_OF, od1_id, od2_id)
627            .unwrap();
628        meta.set_relation(RelTypes::IS_PART_OF, od2_id, od3_id)
629            .unwrap();
630
631        meta.set_relation(RelTypes::IS_PART_OF, 8888, 9999)
632            .expect_err("Invalid id");
633
634        let meta = buf.meta::<AnalyticsRelationMeta>().unwrap();
635        assert!(meta.relation(od1_id, od2_id) == crate::RelTypes::IS_PART_OF);
636        assert!(meta.relation(od2_id, od3_id) == crate::RelTypes::IS_PART_OF);
637
638        assert!(meta.exist(od1_id, od2_id, 1, crate::RelTypes::IS_PART_OF));
639        assert!(meta.exist(od1_id, od3_id, 2, crate::RelTypes::IS_PART_OF));
640        assert!(!meta.exist(od2_id, od1_id, 1, crate::RelTypes::IS_PART_OF));
641        assert!(!meta.exist(od1_id, od3_id, 1, crate::RelTypes::IS_PART_OF));
642        assert!(!meta.exist(od1_id, od2_id, 1, crate::RelTypes::CONTAIN));
643
644        let path = meta
645            .exist_path(od1_id, od3_id, 3, crate::RelTypes::ANY)
646            .unwrap();
647
648        assert_eq!(path.as_slice().len(), 3);
649        assert_eq!(path.as_slice()[0], od1_id);
650        assert_eq!(path.as_slice()[1], od2_id);
651        assert_eq!(path.as_slice()[2], od3_id);
652
653        assert_eq!(meta.len(), meta.iter::<AnalyticsAnyMtd>().count());
654        assert_eq!(meta.len(), meta.iter::<AnalyticsODMtd>().count());
655        for mtd in meta.iter::<AnalyticsODMtd>() {
656            assert_eq!(mtd.obj_type().unwrap(), glib::Quark::from_str("blb"))
657        }
658
659        assert_eq!(meta.len(), meta.iter::<AnalyticsAnyMtd>().count());
660        for mtd in meta.iter::<AnalyticsAnyMtd>() {
661            if let Ok(mtd) = mtd.downcast::<AnalyticsODMtd>() {
662                assert_eq!(mtd.obj_type().unwrap(), glib::Quark::from_str("blb"))
663            }
664        }
665
666        assert_eq!(
667            meta.iter_direct_related::<AnalyticsODMtd>(od1_id, crate::RelTypes::IS_PART_OF)
668                .count(),
669            1
670        );
671        assert_eq!(
672            meta.iter_direct_related::<AnalyticsODMtd>(od2_id, crate::RelTypes::IS_PART_OF)
673                .count(),
674            1
675        );
676        assert_eq!(
677            meta.iter_direct_related::<AnalyticsODMtd>(od3_id, crate::RelTypes::IS_PART_OF)
678                .count(),
679            0
680        );
681        assert_eq!(
682            meta.iter_direct_related::<AnalyticsODMtd>(od1_id, crate::RelTypes::CONTAIN)
683                .count(),
684            0
685        );
686
687        assert_eq!(
688            meta.iter_direct_related::<AnalyticsAnyMtd>(od1_id, crate::RelTypes::CONTAIN)
689                .count(),
690            0
691        );
692        for mtd in meta.iter_direct_related::<AnalyticsODMtd>(od1_id, crate::RelTypes::IS_PART_OF) {
693            assert_eq!(mtd.obj_type().unwrap(), glib::Quark::from_str("blb"))
694        }
695
696        let mut meta = buf.make_mut().meta_mut::<AnalyticsRelationMeta>().unwrap();
697        assert_eq!(meta.len(), meta.iter_mut::<AnalyticsAnyMtd>().count());
698
699        let mut meta = buf.make_mut().meta_mut::<AnalyticsRelationMeta>().unwrap();
700        let _ = meta.add_tracking_mtd(10, gst::ClockTime::from_seconds(10));
701        let _ = meta.add_tracking_mtd(10, gst::ClockTime::from_seconds(10));
702
703        for mut item in meta.iter_mut::<AnalyticsTrackingMtd>() {
704            item.set_lost().unwrap();
705        }
706    }
707}