gstreamer_sdp/
sdp_media.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    ffi::CStr,
6    fmt, mem, ops, ptr,
7};
8
9use glib::translate::*;
10
11use crate::{
12    ffi, sdp_attribute::SDPAttribute, sdp_bandwidth::SDPBandwidth, sdp_connection::SDPConnection,
13    sdp_key::SDPKey,
14};
15
16glib::wrapper! {
17    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
18    #[doc(alias = "GstSDPMedia")]
19    pub struct SDPMedia(Boxed<ffi::GstSDPMedia>);
20
21    match fn {
22        copy => |ptr| {
23            let mut copy = ptr::null_mut();
24            let res = ffi::gst_sdp_media_copy(ptr, &mut copy);
25            debug_assert_eq!(res, ffi::GST_SDP_OK);
26            copy
27        },
28        free => |ptr| {
29            let res = ffi::gst_sdp_media_free(ptr);
30            debug_assert_eq!(res, ffi::GST_SDP_OK);
31        },
32    }
33}
34
35impl SDPMedia {
36    #[doc(alias = "gst_sdp_media_new")]
37    pub fn new() -> Self {
38        assert_initialized_main_thread!();
39        unsafe {
40            let mut media = ptr::null_mut();
41            ffi::gst_sdp_media_new(&mut media);
42            from_glib_full(media)
43        }
44    }
45}
46
47impl Default for SDPMedia {
48    fn default() -> Self {
49        Self::new()
50    }
51}
52
53unsafe impl Send for SDPMedia {}
54unsafe impl Sync for SDPMedia {}
55
56impl ops::Deref for SDPMedia {
57    type Target = SDPMediaRef;
58
59    fn deref(&self) -> &SDPMediaRef {
60        unsafe { &*(self.as_ptr() as *const SDPMediaRef) }
61    }
62}
63
64impl ops::DerefMut for SDPMedia {
65    fn deref_mut(&mut self) -> &mut SDPMediaRef {
66        unsafe { &mut *(self.to_glib_none_mut().0 as *mut SDPMediaRef) }
67    }
68}
69
70impl fmt::Debug for SDPMedia {
71    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72        <SDPMediaRef as fmt::Debug>::fmt(self, f)
73    }
74}
75
76impl fmt::Display for SDPMedia {
77    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78        <SDPMediaRef as fmt::Display>::fmt(self, f)
79    }
80}
81
82#[repr(transparent)]
83#[doc(alias = "GstSDPMedia")]
84pub struct SDPMediaRef(ffi::GstSDPMedia);
85
86impl fmt::Debug for SDPMediaRef {
87    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
88        use std::cell::RefCell;
89
90        struct DebugIter<I>(RefCell<I>);
91        impl<I: Iterator> fmt::Debug for DebugIter<I>
92        where
93            I::Item: fmt::Debug,
94        {
95            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
96                f.debug_list().entries(&mut *self.0.borrow_mut()).finish()
97            }
98        }
99
100        f.debug_struct("SDPMedia")
101            .field("formats", &DebugIter(RefCell::new(self.formats())))
102            .field("connections", &DebugIter(RefCell::new(self.connections())))
103            .field("bandwidths", &DebugIter(RefCell::new(self.bandwidths())))
104            .field("attributes", &DebugIter(RefCell::new(self.attributes())))
105            .field("information", &self.information())
106            .field("key", &self.key())
107            .field("media", &self.media())
108            .field("port", &self.port())
109            .field("num-ports", &self.num_ports())
110            .field("proto", &self.proto())
111            .finish()
112    }
113}
114
115impl fmt::Display for SDPMediaRef {
116    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
117        match self.as_text() {
118            Ok(text) => f.write_str(text.as_str()),
119            Err(_) => Err(fmt::Error),
120        }
121    }
122}
123
124unsafe impl Send for SDPMediaRef {}
125unsafe impl Sync for SDPMediaRef {}
126
127impl SDPMediaRef {
128    #[doc(alias = "gst_sdp_media_add_attribute")]
129    pub fn add_attribute(&mut self, key: &str, value: Option<&str>) {
130        let value = value.to_glib_none();
131        unsafe { ffi::gst_sdp_media_add_attribute(&mut self.0, key.to_glib_none().0, value.0) };
132    }
133
134    #[doc(alias = "gst_sdp_media_add_bandwidth")]
135    pub fn add_bandwidth(&mut self, bwtype: &str, bandwidth: u32) {
136        unsafe {
137            ffi::gst_sdp_media_add_bandwidth(&mut self.0, bwtype.to_glib_none().0, bandwidth)
138        };
139    }
140
141    #[doc(alias = "gst_sdp_media_add_connection")]
142    pub fn add_connection(
143        &mut self,
144        nettype: &str,
145        addrtype: &str,
146        address: &str,
147        ttl: u32,
148        addr_number: u32,
149    ) {
150        unsafe {
151            ffi::gst_sdp_media_add_connection(
152                &mut self.0,
153                nettype.to_glib_none().0,
154                addrtype.to_glib_none().0,
155                address.to_glib_none().0,
156                ttl,
157                addr_number,
158            )
159        };
160    }
161
162    #[doc(alias = "gst_sdp_media_add_format")]
163    pub fn add_format(&mut self, format: &str) {
164        unsafe { ffi::gst_sdp_media_add_format(&mut self.0, format.to_glib_none().0) };
165    }
166
167    #[doc(alias = "gst_sdp_media_as_text")]
168    pub fn as_text(&self) -> Result<String, glib::error::BoolError> {
169        unsafe {
170            match from_glib_full(ffi::gst_sdp_media_as_text(&self.0)) {
171                Some(s) => Ok(s),
172                None => Err(glib::bool_error!(
173                    "Failed to convert the contents of media to a text string"
174                )),
175            }
176        }
177    }
178
179    pub fn attributes(&self) -> AttributesIter {
180        AttributesIter::new(self)
181    }
182
183    pub fn formats(&self) -> FormatsIter {
184        FormatsIter::new(self)
185    }
186
187    pub fn bandwidths(&self) -> BandwidthsIter {
188        BandwidthsIter::new(self)
189    }
190
191    pub fn connections(&self) -> ConnectionsIter {
192        ConnectionsIter::new(self)
193    }
194
195    #[doc(alias = "gst_sdp_media_attributes_len")]
196    pub fn attributes_len(&self) -> u32 {
197        unsafe { ffi::gst_sdp_media_attributes_len(&self.0) }
198    }
199
200    #[doc(alias = "gst_sdp_media_attributes_to_caps")]
201    pub fn attributes_to_caps(&self, caps: &mut gst::CapsRef) -> Result<(), glib::BoolError> {
202        let result = unsafe { ffi::gst_sdp_media_attributes_to_caps(&self.0, caps.as_mut_ptr()) };
203        match result {
204            ffi::GST_SDP_OK => Ok(()),
205            _ => Err(glib::bool_error!("Failed to store attributes in caps")),
206        }
207    }
208
209    #[doc(alias = "gst_sdp_media_bandwidths_len")]
210    pub fn bandwidths_len(&self) -> u32 {
211        unsafe { ffi::gst_sdp_media_bandwidths_len(&self.0) }
212    }
213
214    #[doc(alias = "gst_sdp_media_connections_len")]
215    pub fn connections_len(&self) -> u32 {
216        unsafe { ffi::gst_sdp_media_connections_len(&self.0) }
217    }
218
219    #[doc(alias = "gst_sdp_media_formats_len")]
220    pub fn formats_len(&self) -> u32 {
221        unsafe { ffi::gst_sdp_media_formats_len(&self.0) }
222    }
223
224    #[doc(alias = "get_attribute")]
225    #[doc(alias = "gst_sdp_media_get_attribute")]
226    pub fn attribute(&self, idx: u32) -> Option<&SDPAttribute> {
227        if idx >= self.attributes_len() {
228            return None;
229        }
230
231        unsafe {
232            let ptr = ffi::gst_sdp_media_get_attribute(&self.0, idx);
233            if ptr.is_null() {
234                None
235            } else {
236                Some(&*(ptr as *mut SDPAttribute))
237            }
238        }
239    }
240
241    #[doc(alias = "get_attribute_val")]
242    #[doc(alias = "gst_sdp_media_get_attribute_val")]
243    pub fn attribute_val(&self, key: &str) -> Option<&str> {
244        unsafe {
245            let ptr = ffi::gst_sdp_media_get_attribute_val(&self.0, key.to_glib_none().0);
246            if ptr.is_null() {
247                None
248            } else {
249                CStr::from_ptr(ptr).to_str().ok()
250            }
251        }
252    }
253
254    #[doc(alias = "get_attribute_val_n")]
255    #[doc(alias = "gst_sdp_media_get_attribute_val_n")]
256    pub fn attribute_val_n(&self, key: &str, nth: u32) -> Option<&str> {
257        unsafe {
258            let ptr = ffi::gst_sdp_media_get_attribute_val_n(&self.0, key.to_glib_none().0, nth);
259            if ptr.is_null() {
260                None
261            } else {
262                CStr::from_ptr(ptr).to_str().ok()
263            }
264        }
265    }
266
267    #[doc(alias = "get_bandwidth")]
268    #[doc(alias = "gst_sdp_media_get_bandwidth")]
269    pub fn bandwidth(&self, idx: u32) -> Option<&SDPBandwidth> {
270        if idx >= self.bandwidths_len() {
271            return None;
272        }
273
274        unsafe {
275            let ptr = ffi::gst_sdp_media_get_bandwidth(&self.0, idx);
276            if ptr.is_null() {
277                None
278            } else {
279                Some(&*(ptr as *mut SDPBandwidth))
280            }
281        }
282    }
283
284    #[doc(alias = "get_caps_from_media")]
285    #[doc(alias = "gst_sdp_media_get_caps_from_media")]
286    pub fn caps_from_media(&self, pt: i32) -> Option<gst::Caps> {
287        unsafe { from_glib_full(ffi::gst_sdp_media_get_caps_from_media(&self.0, pt)) }
288    }
289
290    #[doc(alias = "get_connection")]
291    #[doc(alias = "gst_sdp_media_get_connection")]
292    pub fn connection(&self, idx: u32) -> Option<&SDPConnection> {
293        if idx >= self.connections_len() {
294            return None;
295        }
296
297        unsafe {
298            let ptr = ffi::gst_sdp_media_get_connection(&self.0, idx);
299            if ptr.is_null() {
300                None
301            } else {
302                Some(&*(ptr as *mut SDPConnection))
303            }
304        }
305    }
306
307    #[doc(alias = "get_format")]
308    #[doc(alias = "gst_sdp_media_get_format")]
309    pub fn format(&self, idx: u32) -> Option<&str> {
310        if idx >= self.formats_len() {
311            return None;
312        }
313
314        unsafe {
315            let ptr = ffi::gst_sdp_media_get_format(&self.0, idx);
316            if ptr.is_null() {
317                None
318            } else {
319                CStr::from_ptr(ptr).to_str().ok()
320            }
321        }
322    }
323
324    #[doc(alias = "get_information")]
325    #[doc(alias = "gst_sdp_media_get_information")]
326    pub fn information(&self) -> Option<&str> {
327        unsafe {
328            let ptr = ffi::gst_sdp_media_get_information(&self.0);
329            if ptr.is_null() {
330                None
331            } else {
332                CStr::from_ptr(ptr).to_str().ok()
333            }
334        }
335    }
336
337    #[doc(alias = "get_key")]
338    #[doc(alias = "gst_sdp_media_get_key")]
339    pub fn key(&self) -> Option<&SDPKey> {
340        unsafe {
341            let ptr = ffi::gst_sdp_media_get_key(&self.0);
342            if ptr.is_null() {
343                None
344            } else {
345                Some(&*(ptr as *mut SDPKey))
346            }
347        }
348    }
349
350    #[doc(alias = "get_media")]
351    #[doc(alias = "gst_sdp_media_get_media")]
352    pub fn media(&self) -> Option<&str> {
353        unsafe {
354            let ptr = ffi::gst_sdp_media_get_media(&self.0);
355            if ptr.is_null() {
356                None
357            } else {
358                CStr::from_ptr(ptr).to_str().ok()
359            }
360        }
361    }
362
363    #[doc(alias = "get_num_ports")]
364    #[doc(alias = "gst_sdp_media_get_num_ports")]
365    pub fn num_ports(&self) -> u32 {
366        unsafe { ffi::gst_sdp_media_get_num_ports(&self.0) }
367    }
368
369    #[doc(alias = "get_port")]
370    #[doc(alias = "gst_sdp_media_get_port")]
371    pub fn port(&self) -> u32 {
372        unsafe { ffi::gst_sdp_media_get_port(&self.0) }
373    }
374
375    #[doc(alias = "get_proto")]
376    #[doc(alias = "gst_sdp_media_get_proto")]
377    pub fn proto(&self) -> Option<&str> {
378        unsafe {
379            let ptr = ffi::gst_sdp_media_get_proto(&self.0);
380            if ptr.is_null() {
381                None
382            } else {
383                CStr::from_ptr(ptr).to_str().ok()
384            }
385        }
386    }
387
388    #[doc(alias = "gst_sdp_media_insert_attribute")]
389    pub fn insert_attribute(
390        &mut self,
391        idx: Option<u32>,
392        attr: SDPAttribute,
393    ) -> Result<(), glib::BoolError> {
394        if let Some(idx) = idx {
395            if idx >= self.attributes_len() {
396                return Err(glib::bool_error!("Failed to insert attribute"));
397            }
398        }
399
400        let idx = idx.map(|idx| idx as i32).unwrap_or(-1);
401        let mut attr = mem::ManuallyDrop::new(attr);
402        let result = unsafe { ffi::gst_sdp_media_insert_attribute(&mut self.0, idx, &mut attr.0) };
403        match result {
404            ffi::GST_SDP_OK => Ok(()),
405            _ => Err(glib::bool_error!("Failed to insert attribute")),
406        }
407    }
408
409    #[doc(alias = "gst_sdp_media_insert_bandwidth")]
410    pub fn insert_bandwidth(
411        &mut self,
412        idx: Option<u32>,
413        bw: SDPBandwidth,
414    ) -> Result<(), glib::BoolError> {
415        if let Some(idx) = idx {
416            if idx >= self.bandwidths_len() {
417                return Err(glib::bool_error!("Failed to insert bandwidth"));
418            }
419        }
420
421        let idx = idx.map(|idx| idx as i32).unwrap_or(-1);
422        let mut bw = mem::ManuallyDrop::new(bw);
423        let result = unsafe { ffi::gst_sdp_media_insert_bandwidth(&mut self.0, idx, &mut bw.0) };
424        match result {
425            ffi::GST_SDP_OK => Ok(()),
426            _ => Err(glib::bool_error!("Failed to insert attribute")),
427        }
428    }
429
430    #[doc(alias = "gst_sdp_media_insert_connection")]
431    pub fn insert_connection(
432        &mut self,
433        idx: Option<u32>,
434        conn: SDPConnection,
435    ) -> Result<(), glib::BoolError> {
436        if let Some(idx) = idx {
437            if idx >= self.connections_len() {
438                return Err(glib::bool_error!("Failed to insert connection"));
439            }
440        }
441
442        let idx = idx.map(|idx| idx as i32).unwrap_or(-1);
443        let mut conn = mem::ManuallyDrop::new(conn);
444        let result = unsafe { ffi::gst_sdp_media_insert_connection(&mut self.0, idx, &mut conn.0) };
445        match result {
446            ffi::GST_SDP_OK => Ok(()),
447            _ => Err(glib::bool_error!("Failed to insert connection")),
448        }
449    }
450
451    #[doc(alias = "gst_sdp_media_insert_format")]
452    pub fn insert_format(&mut self, idx: Option<u32>, format: &str) -> Result<(), glib::BoolError> {
453        if let Some(idx) = idx {
454            if idx >= self.formats_len() {
455                return Err(glib::bool_error!("Failed to insert format"));
456            }
457        }
458
459        let idx = idx.map(|idx| idx as i32).unwrap_or(-1);
460        let result =
461            unsafe { ffi::gst_sdp_media_insert_format(&mut self.0, idx, format.to_glib_none().0) };
462        match result {
463            ffi::GST_SDP_OK => Ok(()),
464            _ => Err(glib::bool_error!("Failed to insert format")),
465        }
466    }
467
468    #[doc(alias = "gst_sdp_media_remove_attribute")]
469    pub fn remove_attribute(&mut self, idx: u32) -> Result<(), glib::BoolError> {
470        if idx >= self.attributes_len() {
471            return Err(glib::bool_error!("Failed to remove attribute"));
472        }
473
474        let result = unsafe { ffi::gst_sdp_media_remove_attribute(&mut self.0, idx) };
475        match result {
476            ffi::GST_SDP_OK => Ok(()),
477            _ => Err(glib::bool_error!("Failed to remove attribute")),
478        }
479    }
480
481    #[doc(alias = "gst_sdp_media_remove_bandwidth")]
482    pub fn remove_bandwidth(&mut self, idx: u32) -> Result<(), glib::BoolError> {
483        if idx >= self.bandwidths_len() {
484            return Err(glib::bool_error!("Failed to remove bandwidth"));
485        }
486
487        let result = unsafe { ffi::gst_sdp_media_remove_bandwidth(&mut self.0, idx) };
488        match result {
489            ffi::GST_SDP_OK => Ok(()),
490            _ => Err(glib::bool_error!("Failed to remove bandwidth")),
491        }
492    }
493
494    #[doc(alias = "gst_sdp_media_remove_connection")]
495    pub fn remove_connection(&mut self, idx: u32) -> Result<(), glib::BoolError> {
496        if idx >= self.connections_len() {
497            return Err(glib::bool_error!("Failed to remove connection"));
498        }
499
500        let result = unsafe { ffi::gst_sdp_media_remove_connection(&mut self.0, idx) };
501        match result {
502            ffi::GST_SDP_OK => Ok(()),
503            _ => Err(glib::bool_error!("Failed to remove connection")),
504        }
505    }
506
507    #[doc(alias = "gst_sdp_media_remove_format")]
508    pub fn remove_format(&mut self, idx: u32) -> Result<(), glib::BoolError> {
509        if idx >= self.formats_len() {
510            return Err(glib::bool_error!("Failed to remove format"));
511        }
512
513        let result = unsafe { ffi::gst_sdp_media_remove_format(&mut self.0, idx) };
514        match result {
515            ffi::GST_SDP_OK => Ok(()),
516            _ => Err(glib::bool_error!("Failed to remove format")),
517        }
518    }
519
520    #[doc(alias = "gst_sdp_media_replace_attribute")]
521    pub fn replace_attribute(
522        &mut self,
523        idx: u32,
524        attr: SDPAttribute,
525    ) -> Result<(), glib::BoolError> {
526        if idx >= self.attributes_len() {
527            return Err(glib::bool_error!("Failed to replace attribute"));
528        }
529
530        let mut attr = mem::ManuallyDrop::new(attr);
531        let result = unsafe { ffi::gst_sdp_media_replace_attribute(&mut self.0, idx, &mut attr.0) };
532        match result {
533            ffi::GST_SDP_OK => Ok(()),
534            _ => Err(glib::bool_error!("Failed to replace attribute")),
535        }
536    }
537
538    #[doc(alias = "gst_sdp_media_replace_bandwidth")]
539    pub fn replace_bandwidth(&mut self, idx: u32, bw: SDPBandwidth) -> Result<(), glib::BoolError> {
540        if idx >= self.bandwidths_len() {
541            return Err(glib::bool_error!("Failed to replace bandwidth"));
542        }
543
544        let mut bw = mem::ManuallyDrop::new(bw);
545        let result = unsafe { ffi::gst_sdp_media_replace_bandwidth(&mut self.0, idx, &mut bw.0) };
546        match result {
547            ffi::GST_SDP_OK => Ok(()),
548            _ => Err(glib::bool_error!("Failed to replace bandwidth")),
549        }
550    }
551
552    #[doc(alias = "gst_sdp_media_replace_connection")]
553    pub fn replace_connection(
554        &mut self,
555        idx: u32,
556        conn: SDPConnection,
557    ) -> Result<(), glib::BoolError> {
558        if idx >= self.connections_len() {
559            return Err(glib::bool_error!("Failed to replace connection"));
560        }
561
562        let mut conn = mem::ManuallyDrop::new(conn);
563        let result =
564            unsafe { ffi::gst_sdp_media_replace_connection(&mut self.0, idx, &mut conn.0) };
565        match result {
566            ffi::GST_SDP_OK => Ok(()),
567            _ => Err(glib::bool_error!("Failed to replace connection")),
568        }
569    }
570
571    #[doc(alias = "gst_sdp_media_replace_format")]
572    pub fn replace_format(&mut self, idx: u32, format: &str) -> Result<(), glib::BoolError> {
573        if idx >= self.formats_len() {
574            return Err(glib::bool_error!("Failed to replace format"));
575        }
576
577        let result =
578            unsafe { ffi::gst_sdp_media_replace_format(&mut self.0, idx, format.to_glib_none().0) };
579        match result {
580            ffi::GST_SDP_OK => Ok(()),
581            _ => Err(glib::bool_error!("Failed to replace format")),
582        }
583    }
584
585    #[doc(alias = "gst_sdp_media_set_information")]
586    pub fn set_information(&mut self, information: &str) {
587        unsafe { ffi::gst_sdp_media_set_information(&mut self.0, information.to_glib_none().0) };
588    }
589
590    #[doc(alias = "gst_sdp_media_set_key")]
591    pub fn set_key(&mut self, type_: &str, data: &str) {
592        unsafe {
593            ffi::gst_sdp_media_set_key(&mut self.0, type_.to_glib_none().0, data.to_glib_none().0)
594        };
595    }
596
597    #[doc(alias = "gst_sdp_media_set_media")]
598    pub fn set_media(&mut self, med: &str) {
599        unsafe { ffi::gst_sdp_media_set_media(&mut self.0, med.to_glib_none().0) };
600    }
601
602    #[doc(alias = "gst_sdp_media_set_port_info")]
603    pub fn set_port_info(&mut self, port: u32, num_ports: u32) {
604        unsafe { ffi::gst_sdp_media_set_port_info(&mut self.0, port, num_ports) };
605    }
606
607    #[doc(alias = "gst_sdp_media_set_proto")]
608    pub fn set_proto(&mut self, proto: &str) {
609        unsafe { ffi::gst_sdp_media_set_proto(&mut self.0, proto.to_glib_none().0) };
610    }
611
612    #[doc(alias = "gst_sdp_media_set_media_from_caps")]
613    pub fn set_media_from_caps(
614        caps: &gst::CapsRef,
615        media: &mut SDPMedia,
616    ) -> Result<(), glib::BoolError> {
617        skip_assert_initialized!();
618        let result = unsafe {
619            ffi::gst_sdp_media_set_media_from_caps(caps.as_ptr(), media.to_glib_none_mut().0)
620        };
621        match result {
622            ffi::GST_SDP_OK => Ok(()),
623            _ => Err(glib::bool_error!("Failed to set media from caps")),
624        }
625    }
626}
627
628impl Borrow<SDPMediaRef> for SDPMedia {
629    fn borrow(&self) -> &SDPMediaRef {
630        self
631    }
632}
633
634impl BorrowMut<SDPMediaRef> for SDPMedia {
635    fn borrow_mut(&mut self) -> &mut SDPMediaRef {
636        &mut *self
637    }
638}
639
640impl ToOwned for SDPMediaRef {
641    type Owned = SDPMedia;
642
643    fn to_owned(&self) -> SDPMedia {
644        unsafe {
645            let mut ptr = ptr::null_mut();
646            ffi::gst_sdp_media_copy(&self.0, &mut ptr);
647            from_glib_full(ptr)
648        }
649    }
650}
651
652macro_rules! define_iter(
653    ($name:ident, $typ:ty, $get_item:expr, $get_len:expr) => {
654    #[must_use = "iterators are lazy and do nothing unless consumed"]
655    #[derive(Debug)]
656    pub struct $name<'a> {
657        media: &'a SDPMediaRef,
658        idx: usize,
659        len: usize,
660    }
661
662    impl<'a> $name<'a> {
663        #[allow(clippy::redundant_closure_call)]
664        fn new(media: &'a SDPMediaRef) -> $name<'a> {
665            skip_assert_initialized!();
666            let len = $get_len(media);
667
668            $name {
669                media,
670                idx: 0,
671                len: len as usize,
672            }
673        }
674    }
675
676    #[allow(clippy::redundant_closure_call)]
677    impl<'a> Iterator for $name<'a> {
678        type Item = $typ;
679
680        fn next(&mut self) -> Option<Self::Item> {
681            if self.idx >= self.len {
682                return None;
683            }
684
685            let item = $get_item(self.media, self.idx as u32).unwrap();
686            self.idx += 1;
687            Some(item)
688        }
689
690        fn size_hint(&self) -> (usize, Option<usize>) {
691            let remaining = self.len - self.idx;
692
693            (remaining, Some(remaining))
694        }
695
696
697        fn count(self) -> usize {
698            self.len - self.idx
699        }
700
701        fn nth(&mut self, n: usize) -> Option<Self::Item> {
702            let (end, overflow) = self.idx.overflowing_add(n);
703            if end >= self.len || overflow {
704                self.idx = self.len;
705                None
706            } else {
707                self.idx = end + 1;
708                Some($get_item(self.media, end as u32).unwrap())
709            }
710        }
711
712        fn last(self) -> Option<Self::Item> {
713            if self.idx == self.len {
714                None
715            } else {
716                Some($get_item(self.media, self.len as u32 - 1).unwrap())
717            }
718        }
719    }
720
721    #[allow(clippy::redundant_closure_call)]
722    impl<'a> DoubleEndedIterator for $name<'a> {
723        fn next_back(&mut self) -> Option<Self::Item> {
724            if self.idx == self.len {
725                return None;
726            }
727
728            self.len -= 1;
729
730            Some($get_item(self.media, self.len as u32).unwrap())
731        }
732
733        fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
734            let (end, overflow) = self.len.overflowing_sub(n);
735            if end <= self.idx || overflow {
736                self.idx = self.len;
737                None
738            } else {
739                self.len = end - 1;
740                Some($get_item(self.media, self.len as u32).unwrap())
741            }
742        }
743    }
744
745    impl<'a> ExactSizeIterator for $name<'a> {}
746
747    impl<'a> std::iter::FusedIterator for $name<'a> {}
748    }
749);
750
751define_iter!(
752    BandwidthsIter,
753    &'a SDPBandwidth,
754    |media: &'a SDPMediaRef, idx| media.bandwidth(idx),
755    |media: &SDPMediaRef| media.bandwidths_len()
756);
757define_iter!(
758    FormatsIter,
759    &'a str,
760    |media: &'a SDPMediaRef, idx| media.format(idx),
761    |media: &SDPMediaRef| media.formats_len()
762);
763define_iter!(
764    ConnectionsIter,
765    &'a SDPConnection,
766    |media: &'a SDPMediaRef, idx| media.connection(idx),
767    |media: &SDPMediaRef| media.connections_len()
768);
769define_iter!(
770    AttributesIter,
771    &'a SDPAttribute,
772    |media: &'a SDPMediaRef, idx| media.attribute(idx),
773    |media: &SDPMediaRef| media.attributes_len()
774);
775
776#[cfg(test)]
777mod tests {
778    use super::*;
779
780    fn init() {
781        gst::init().unwrap();
782    }
783
784    #[test]
785    fn debug_impl() {
786        init();
787
788        let sdp = SDPMedia::new();
789        assert!(!format!("{sdp:?}").is_empty());
790    }
791}