gstreamer/
stream_collection.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{boxed::Box as Box_, fmt, mem::transmute};
4
5use glib::{
6    object::ObjectType as ObjectType_,
7    signal::{connect_raw, SignalHandlerId},
8    translate::*,
9};
10
11use crate::{ffi, Stream, StreamCollection};
12
13#[derive(Debug)]
14pub struct Iter<'a> {
15    collection: &'a StreamCollection,
16    idx: usize,
17    size: usize,
18}
19
20impl<'a> Iter<'a> {
21    fn new(collection: &'a StreamCollection) -> Iter<'a> {
22        skip_assert_initialized!();
23        Iter {
24            collection,
25            idx: 0,
26            size: collection.len(),
27        }
28    }
29}
30
31impl Iterator for Iter<'_> {
32    type Item = Stream;
33
34    fn next(&mut self) -> Option<Self::Item> {
35        if self.idx >= self.size {
36            return None;
37        }
38
39        let item = self.collection.stream(self.idx as u32).unwrap();
40        self.idx += 1;
41
42        Some(item)
43    }
44
45    fn size_hint(&self) -> (usize, Option<usize>) {
46        let remaining = self.size - self.idx;
47
48        (remaining, Some(remaining))
49    }
50
51    fn count(self) -> usize {
52        self.size - self.idx
53    }
54
55    fn nth(&mut self, n: usize) -> Option<Self::Item> {
56        let (end, overflow) = self.idx.overflowing_add(n);
57        if end >= self.size || overflow {
58            self.idx = self.size;
59            None
60        } else {
61            self.idx = end + 1;
62            Some(self.collection.stream(end as u32).unwrap())
63        }
64    }
65
66    fn last(self) -> Option<Self::Item> {
67        if self.idx == self.size {
68            None
69        } else {
70            Some(self.collection.stream(self.size as u32 - 1).unwrap())
71        }
72    }
73}
74
75impl DoubleEndedIterator for Iter<'_> {
76    fn next_back(&mut self) -> Option<Self::Item> {
77        if self.idx == self.size {
78            return None;
79        }
80
81        self.size -= 1;
82        Some(self.collection.stream(self.size as u32).unwrap())
83    }
84
85    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
86        let (end, overflow) = self.size.overflowing_sub(n);
87        if end <= self.idx || overflow {
88            self.idx = self.size;
89            None
90        } else {
91            self.size = end - 1;
92            Some(self.collection.stream(self.size as u32).unwrap())
93        }
94    }
95}
96
97impl ExactSizeIterator for Iter<'_> {}
98
99impl std::iter::FusedIterator for Iter<'_> {}
100
101#[derive(Debug, Clone)]
102#[must_use = "The builder must be built to be used"]
103pub struct StreamCollectionBuilder(StreamCollection);
104
105impl StreamCollectionBuilder {
106    #[doc(alias = "gst_stream_collection_add_stream")]
107    pub fn stream(self, stream: Stream) -> Self {
108        unsafe {
109            ffi::gst_stream_collection_add_stream(
110                (self.0).to_glib_none().0,
111                stream.into_glib_ptr(),
112            );
113        }
114
115        self
116    }
117
118    #[doc(alias = "gst_stream_collection_add_stream")]
119    pub fn stream_if(self, stream: Stream, predicate: bool) -> Self {
120        if predicate {
121            unsafe {
122                ffi::gst_stream_collection_add_stream(
123                    (self.0).to_glib_none().0,
124                    stream.into_glib_ptr(),
125                );
126            }
127
128            self
129        } else {
130            self
131        }
132    }
133
134    #[doc(alias = "gst_stream_collection_add_stream")]
135    pub fn stream_if_some(self, stream: Option<Stream>) -> Self {
136        if let Some(stream) = stream {
137            self.stream(stream)
138        } else {
139            self
140        }
141    }
142
143    pub fn streams(self, streams: impl IntoIterator<Item = Stream>) -> Self {
144        for stream in streams.into_iter() {
145            unsafe {
146                ffi::gst_stream_collection_add_stream(
147                    (self.0).to_glib_none().0,
148                    stream.into_glib_ptr(),
149                );
150            }
151        }
152
153        self
154    }
155
156    pub fn streams_if(self, streams: impl IntoIterator<Item = Stream>, predicate: bool) -> Self {
157        if predicate {
158            for stream in streams.into_iter() {
159                unsafe {
160                    ffi::gst_stream_collection_add_stream(
161                        (self.0).to_glib_none().0,
162                        stream.into_glib_ptr(),
163                    );
164                }
165            }
166
167            self
168        } else {
169            self
170        }
171    }
172
173    pub fn streams_if_some(self, streams: Option<impl IntoIterator<Item = Stream>>) -> Self {
174        if let Some(streams) = streams {
175            self.streams(streams)
176        } else {
177            self
178        }
179    }
180
181    pub fn streams_if_not_empty(self, streams: impl IntoIterator<Item = Stream>) -> Self {
182        let mut streams = streams.into_iter().peekable();
183        if streams.peek().is_some() {
184            self.streams(streams)
185        } else {
186            self
187        }
188    }
189
190    #[must_use = "Building the stream collection without using it has no effect"]
191    pub fn build(self) -> StreamCollection {
192        self.0
193    }
194}
195
196impl StreamCollection {
197    #[doc(alias = "gst_stream_collection_new")]
198    pub fn builder(upstream_id: Option<&str>) -> StreamCollectionBuilder {
199        assert_initialized_main_thread!();
200        let upstream_id = upstream_id.to_glib_none();
201        let collection = unsafe { from_glib_full(ffi::gst_stream_collection_new(upstream_id.0)) };
202
203        StreamCollectionBuilder(collection)
204    }
205
206    /// The stream notify signal is used to be notified of property changes to
207    /// streams within the collection.
208    /// ## `prop_stream`
209    /// the [`Stream`][crate::Stream] that originated the signal
210    /// ## `prop`
211    /// the property that changed
212    #[doc(alias = "stream-notify")]
213    pub fn connect_stream_notify<
214        F: Fn(&Self, &Stream, &glib::ParamSpec) + Send + Sync + 'static,
215    >(
216        &self,
217        detail: Option<&str>,
218        f: F,
219    ) -> SignalHandlerId {
220        unsafe extern "C" fn stream_notify_trampoline<
221            F: Fn(&StreamCollection, &Stream, &glib::ParamSpec) + Send + Sync + 'static,
222        >(
223            this: *mut ffi::GstStreamCollection,
224            object: *mut ffi::GstStream,
225            p0: *mut glib::gobject_ffi::GParamSpec,
226            f: glib::ffi::gpointer,
227        ) {
228            let f: &F = &*(f as *const F);
229            f(
230                &from_glib_borrow(this),
231                &from_glib_borrow(object),
232                &from_glib_borrow(p0),
233            )
234        }
235        unsafe {
236            let f: Box_<F> = Box_::new(f);
237            let detailed_signal_name = detail.map(|name| format!("stream-notify::{name}\0"));
238            let signal_name: &[u8] = detailed_signal_name
239                .as_ref()
240                .map_or(&b"stream-notify\0"[..], |n| n.as_bytes());
241            connect_raw(
242                self.as_ptr() as *mut _,
243                signal_name.as_ptr() as *const _,
244                Some(transmute::<*const (), unsafe extern "C" fn()>(
245                    stream_notify_trampoline::<F> as *const (),
246                )),
247                Box_::into_raw(f),
248            )
249        }
250    }
251
252    pub fn iter(&self) -> Iter {
253        Iter::new(self)
254    }
255
256    pub fn len(&self) -> usize {
257        self.size() as usize
258    }
259
260    pub fn is_empty(&self) -> bool {
261        self.len() == 0
262    }
263
264    pub fn debug(&self) -> Debug {
265        Debug(self)
266    }
267}
268
269impl<'a> IntoIterator for &'a StreamCollection {
270    type IntoIter = Iter<'a>;
271    type Item = Stream;
272
273    fn into_iter(self) -> Self::IntoIter {
274        self.iter()
275    }
276}
277
278pub struct Debug<'a>(&'a StreamCollection);
279
280impl fmt::Debug for Debug<'_> {
281    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
282        struct Streams<'a>(&'a StreamCollection);
283
284        impl fmt::Debug for Streams<'_> {
285            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
286                let mut f = f.debug_list();
287
288                for stream in self.0.iter() {
289                    f.entry(&stream.debug());
290                }
291
292                f.finish()
293            }
294        }
295
296        let streams = Streams(self.0);
297
298        f.debug_struct("StreamCollection")
299            .field("streams", &streams)
300            .finish()
301    }
302}