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::{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<'a> Iterator for Iter<'a> {
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<'a> DoubleEndedIterator for Iter<'a> {
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: usize, overflow: bool) = 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<'a> ExactSizeIterator for Iter<'a> {}
98
99impl<'a> std::iter::FusedIterator for Iter<'a> {}
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 pub fn streams(self, streams: impl IntoIterator<Item = Stream>) -> Self {
119 for stream in streams.into_iter() {
120 unsafe {
121 ffi::gst_stream_collection_add_stream(
122 (self.0).to_glib_none().0,
123 stream.into_glib_ptr(),
124 );
125 }
126 }
127
128 self
129 }
130
131 #[must_use = "Building the stream collection without using it has no effect"]
132 pub fn build(self) -> StreamCollection {
133 self.0
134 }
135}
136
137impl StreamCollection {
138 #[doc(alias = "gst_stream_collection_new")]
139 pub fn builder(upstream_id: Option<&str>) -> StreamCollectionBuilder {
140 assert_initialized_main_thread!();
141 let upstream_id = upstream_id.to_glib_none();
142 let collection = unsafe { from_glib_full(ffi::gst_stream_collection_new(upstream_id.0)) };
143
144 StreamCollectionBuilder(collection)
145 }
146
147 #[doc(alias = "stream-notify")]
148 pub fn connect_stream_notify<
149 F: Fn(&Self, &Stream, &glib::ParamSpec) + Send + Sync + 'static,
150 >(
151 &self,
152 detail: Option<&str>,
153 f: F,
154 ) -> SignalHandlerId {
155 unsafe extern "C" fn stream_notify_trampoline<
156 F: Fn(&StreamCollection, &Stream, &glib::ParamSpec) + Send + Sync + 'static,
157 >(
158 this: *mut ffi::GstStreamCollection,
159 object: *mut ffi::GstStream,
160 p0: *mut glib::gobject_ffi::GParamSpec,
161 f: glib::ffi::gpointer,
162 ) {
163 let f: &F = &*(f as *const F);
164 f(
165 &from_glib_borrow(this),
166 &from_glib_borrow(object),
167 &from_glib_borrow(p0),
168 )
169 }
170 unsafe {
171 let f: Box_<F> = Box_::new(f);
172 let detailed_signal_name = detail.map(|name| format!("stream-notify::{name}\0"));
173 let signal_name: &[u8] = detailed_signal_name
174 .as_ref()
175 .map_or(&b"stream-notify\0"[..], |n| n.as_bytes());
176 connect_raw(
177 self.as_ptr() as *mut _,
178 signal_name.as_ptr() as *const _,
179 Some(transmute::<_, unsafe extern "C" fn()>(
180 stream_notify_trampoline::<F> as *const (),
181 )),
182 Box_::into_raw(f),
183 )
184 }
185 }
186
187 pub fn iter(&self) -> Iter {
188 Iter::new(self)
189 }
190
191 pub fn len(&self) -> usize {
192 self.size() as usize
193 }
194
195 pub fn is_empty(&self) -> bool {
196 self.len() == 0
197 }
198
199 pub fn debug(&self) -> Debug {
200 Debug(self)
201 }
202}
203
204impl<'a> IntoIterator for &'a StreamCollection {
205 type IntoIter = Iter<'a>;
206 type Item = Stream;
207
208 fn into_iter(self) -> Self::IntoIter {
209 self.iter()
210 }
211}
212
213pub struct Debug<'a>(&'a StreamCollection);
214
215impl<'a> fmt::Debug for Debug<'a> {
216 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
217 struct Streams<'a>(&'a StreamCollection);
218
219 impl<'a> fmt::Debug for Streams<'a> {
220 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
221 let mut f: DebugList<'_, '_> = f.debug_list();
222
223 for stream: Stream in self.0.iter() {
224 f.entry(&stream.debug());
225 }
226
227 f.finish()
228 }
229 }
230
231 let streams: Streams<'_> = Streams(self.0);
232
233 f&mut DebugStruct<'_, '_>.debug_struct("StreamCollection")
234 .field(name:"streams", &streams)
235 .finish()
236 }
237}
238