gstreamer/
bufferlist.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{
4    cmp, fmt,
5    ops::{ControlFlow, RangeBounds},
6    ptr,
7};
8
9use glib::translate::*;
10
11use crate::{ffi, Buffer, BufferRef};
12
13mini_object_wrapper!(BufferList, BufferListRef, ffi::GstBufferList, || {
14    ffi::gst_buffer_list_get_type()
15});
16
17impl BufferList {
18    /// Creates a new, empty [`BufferList`][crate::BufferList].
19    ///
20    /// # Returns
21    ///
22    /// the new [`BufferList`][crate::BufferList].
23    #[doc(alias = "gst_buffer_list_new")]
24    pub fn new() -> Self {
25        assert_initialized_main_thread!();
26        unsafe { from_glib_full(ffi::gst_buffer_list_new()) }
27    }
28
29    /// Creates a new, empty [`BufferList`][crate::BufferList]. The list will have `size` space
30    /// preallocated so that memory reallocations can be avoided.
31    /// ## `size`
32    /// an initial reserved size
33    ///
34    /// # Returns
35    ///
36    /// the new [`BufferList`][crate::BufferList].
37    #[doc(alias = "gst_buffer_list_new_sized")]
38    pub fn new_sized(size: usize) -> Self {
39        assert_initialized_main_thread!();
40        unsafe { from_glib_full(ffi::gst_buffer_list_new_sized(u32::try_from(size).unwrap())) }
41    }
42}
43
44impl BufferListRef {
45    #[doc(alias = "gst_buffer_list_insert")]
46    pub fn insert(&mut self, idx: impl Into<Option<usize>>, buffer: Buffer) {
47        unsafe {
48            let len = self.len();
49            debug_assert!(len <= u32::MAX as usize);
50
51            let idx = idx.into();
52            let idx = cmp::min(idx.unwrap_or(len), len) as i32;
53            ffi::gst_buffer_list_insert(self.as_mut_ptr(), idx, buffer.into_glib_ptr());
54        }
55    }
56
57    #[doc(alias = "gst_buffer_list_add")]
58    pub fn add(&mut self, buffer: Buffer) {
59        self.insert(None, buffer);
60    }
61
62    #[doc(alias = "gst_buffer_list_copy_deep")]
63    pub fn copy_deep(&self) -> BufferList {
64        unsafe { from_glib_full(ffi::gst_buffer_list_copy_deep(self.as_ptr())) }
65    }
66
67    fn buffer_range_to_start_end_idx(&self, range: impl RangeBounds<usize>) -> (usize, usize) {
68        let n = self.len();
69        debug_assert!(n <= u32::MAX as usize);
70
71        let start_idx = match range.start_bound() {
72            std::ops::Bound::Included(idx) => *idx,
73            std::ops::Bound::Excluded(idx) => idx.checked_add(1).unwrap(),
74            std::ops::Bound::Unbounded => 0,
75        };
76        assert!(start_idx < n);
77
78        let end_idx = match range.end_bound() {
79            std::ops::Bound::Included(idx) => idx.checked_add(1).unwrap(),
80            std::ops::Bound::Excluded(idx) => *idx,
81            std::ops::Bound::Unbounded => n,
82        };
83        assert!(end_idx <= n);
84
85        (start_idx, end_idx)
86    }
87
88    #[doc(alias = "gst_buffer_list_remove")]
89    pub fn remove(&mut self, range: impl RangeBounds<usize>) {
90        let (start_idx, end_idx) = self.buffer_range_to_start_end_idx(range);
91
92        unsafe {
93            ffi::gst_buffer_list_remove(
94                self.as_mut_ptr(),
95                start_idx as u32,
96                (end_idx - start_idx) as u32,
97            )
98        }
99    }
100
101    #[doc(alias = "gst_buffer_list_get")]
102    pub fn get(&self, idx: usize) -> Option<&BufferRef> {
103        unsafe {
104            if idx >= self.len() {
105                return None;
106            }
107            let ptr = ffi::gst_buffer_list_get(self.as_mut_ptr(), idx as u32);
108            Some(BufferRef::from_ptr(ptr))
109        }
110    }
111
112    #[doc(alias = "gst_buffer_list_get")]
113    pub fn get_owned(&self, idx: usize) -> Option<Buffer> {
114        unsafe {
115            if idx >= self.len() {
116                return None;
117            }
118            let ptr = ffi::gst_buffer_list_get(self.as_mut_ptr(), idx as u32);
119            Some(from_glib_none(ptr))
120        }
121    }
122
123    #[doc(alias = "gst_buffer_list_get_writable")]
124    #[doc(alias = "get_writable")]
125    pub fn get_mut(&mut self, idx: usize) -> Option<&mut BufferRef> {
126        unsafe {
127            if idx >= self.len() {
128                return None;
129            }
130            let ptr = ffi::gst_buffer_list_get_writable(self.as_mut_ptr(), idx as u32);
131            Some(BufferRef::from_mut_ptr(ptr))
132        }
133    }
134
135    #[doc(alias = "gst_buffer_list_length")]
136    pub fn len(&self) -> usize {
137        unsafe { ffi::gst_buffer_list_length(self.as_mut_ptr()) as usize }
138    }
139
140    #[doc(alias = "gst_buffer_list_calculate_size")]
141    pub fn calculate_size(&self) -> usize {
142        unsafe { ffi::gst_buffer_list_calculate_size(self.as_mut_ptr()) }
143    }
144
145    pub fn is_empty(&self) -> bool {
146        self.len() == 0
147    }
148
149    pub fn iter(&self) -> Iter {
150        Iter::new(self)
151    }
152
153    pub fn iter_owned(&self) -> IterOwned {
154        IterOwned::new(self)
155    }
156
157    #[doc(alias = "gst_buffer_list_foreach")]
158    pub fn foreach<F: FnMut(&Buffer, usize) -> ControlFlow<(), ()>>(&self, func: F) -> bool {
159        unsafe extern "C" fn trampoline<F: FnMut(&Buffer, usize) -> ControlFlow<(), ()>>(
160            buffer: *mut *mut ffi::GstBuffer,
161            idx: u32,
162            user_data: glib::ffi::gpointer,
163        ) -> glib::ffi::gboolean {
164            let func = user_data as *mut F;
165            let res = (*func)(&Buffer::from_glib_borrow(*buffer), idx as usize);
166
167            matches!(res, ControlFlow::Continue(_)).into_glib()
168        }
169
170        unsafe {
171            let mut func = func;
172            let func_ptr: &mut F = &mut func;
173
174            from_glib(ffi::gst_buffer_list_foreach(
175                self.as_ptr() as *mut _,
176                Some(trampoline::<F>),
177                func_ptr as *mut _ as *mut _,
178            ))
179        }
180    }
181
182    #[doc(alias = "gst_buffer_list_foreach")]
183    pub fn foreach_mut<F: FnMut(Buffer, usize) -> ControlFlow<Option<Buffer>, Option<Buffer>>>(
184        &mut self,
185        func: F,
186    ) -> bool {
187        unsafe extern "C" fn trampoline<
188            F: FnMut(Buffer, usize) -> ControlFlow<Option<Buffer>, Option<Buffer>>,
189        >(
190            buffer: *mut *mut ffi::GstBuffer,
191            idx: u32,
192            user_data: glib::ffi::gpointer,
193        ) -> glib::ffi::gboolean {
194            let func = user_data as *mut F;
195            let res = (*func)(
196                Buffer::from_glib_full(ptr::replace(
197                    buffer as *mut *const ffi::GstBuffer,
198                    ptr::null_mut::<ffi::GstBuffer>(),
199                )),
200                idx as usize,
201            );
202
203            let (cont, res_buffer) = match res {
204                ControlFlow::Continue(res_buffer) => (true, res_buffer),
205                ControlFlow::Break(res_buffer) => (false, res_buffer),
206            };
207
208            match res_buffer {
209                None => {
210                    *buffer = ptr::null_mut();
211                }
212                Some(new_buffer) => {
213                    *buffer = new_buffer.into_glib_ptr();
214                }
215            }
216
217            cont.into_glib()
218        }
219
220        unsafe {
221            let mut func = func;
222            let func_ptr: &mut F = &mut func;
223
224            from_glib(ffi::gst_buffer_list_foreach(
225                self.as_ptr() as *mut _,
226                Some(trampoline::<F>),
227                func_ptr as *mut _ as *mut _,
228            ))
229        }
230    }
231
232    pub fn drain(&mut self, range: impl RangeBounds<usize>) -> Drain<'_> {
233        let (start_idx, end_idx) = self.buffer_range_to_start_end_idx(range);
234        Drain {
235            list: self,
236            start_idx,
237            end_idx,
238        }
239    }
240}
241
242impl Default for BufferList {
243    fn default() -> Self {
244        Self::new()
245    }
246}
247
248impl fmt::Debug for BufferList {
249    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
250        BufferListRef::fmt(self, f)
251    }
252}
253
254impl fmt::Debug for BufferListRef {
255    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
256        use crate::{utils::Displayable, ClockTime};
257
258        let size = self.iter().map(|b| b.size()).sum::<usize>();
259        let (pts, dts) = self
260            .get(0)
261            .map(|b| (b.pts(), b.dts()))
262            .unwrap_or((ClockTime::NONE, ClockTime::NONE));
263
264        f.debug_struct("BufferList")
265            .field("ptr", &self.as_ptr())
266            .field("buffers", &self.len())
267            .field("pts", &pts.display())
268            .field("dts", &dts.display())
269            .field("size", &size)
270            .finish()
271    }
272}
273
274macro_rules! define_iter(
275    ($name:ident, $styp:ty, $get_item:expr) => {
276    #[derive(Debug)]
277    pub struct $name<'a> {
278        list: &'a BufferListRef,
279        idx: usize,
280        size: usize,
281    }
282
283    impl<'a> $name<'a> {
284        fn new(list: &'a BufferListRef) -> $name<'a> {
285            skip_assert_initialized!();
286            $name {
287                list,
288                idx: 0,
289                size: list.len(),
290            }
291        }
292    }
293
294    #[allow(clippy::redundant_closure_call)]
295    impl<'a> Iterator for $name<'a> {
296        type Item = $styp;
297
298        fn next(&mut self) -> Option<Self::Item> {
299            if self.idx >= self.size {
300                return None;
301            }
302
303            let item = $get_item(self.list, self.idx).unwrap();
304            self.idx += 1;
305
306            Some(item)
307        }
308
309        fn size_hint(&self) -> (usize, Option<usize>) {
310            let remaining = self.size - self.idx;
311
312            (remaining, Some(remaining))
313        }
314
315        fn count(self) -> usize {
316            self.size - self.idx
317        }
318
319        fn nth(&mut self, n: usize) -> Option<Self::Item> {
320            let (end, overflow) = self.idx.overflowing_add(n);
321            if end >= self.size || overflow {
322                self.idx = self.size;
323                None
324            } else {
325                self.idx = end + 1;
326                Some($get_item(self.list, end).unwrap())
327            }
328        }
329
330        fn last(self) -> Option<Self::Item> {
331            if self.idx == self.size {
332                None
333            } else {
334                Some($get_item(self.list, self.size - 1).unwrap())
335            }
336        }
337    }
338
339    #[allow(clippy::redundant_closure_call)]
340    impl<'a> DoubleEndedIterator for $name<'a> {
341        fn next_back(&mut self) -> Option<Self::Item> {
342            if self.idx == self.size {
343                return None;
344            }
345
346            self.size -= 1;
347            Some($get_item(self.list, self.size).unwrap())
348        }
349
350        fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
351            let (end, overflow) = self.size.overflowing_sub(n);
352            if end <= self.idx || overflow {
353                self.idx = self.size;
354                None
355            } else {
356                self.size = end - 1;
357                Some($get_item(self.list, self.size).unwrap())
358            }
359        }
360    }
361
362    impl<'a> ExactSizeIterator for $name<'a> {}
363    impl<'a> std::iter::FusedIterator for $name<'a> {}
364    }
365);
366
367define_iter!(Iter, &'a BufferRef, |list: &'a BufferListRef, idx| {
368    list.get(idx)
369});
370
371define_iter!(IterOwned, Buffer, |list: &BufferListRef, idx| {
372    list.get_owned(idx)
373});
374
375#[derive(Debug)]
376pub struct Drain<'a> {
377    list: &'a mut BufferListRef,
378    start_idx: usize,
379    end_idx: usize,
380}
381
382impl Iterator for Drain<'_> {
383    type Item = Buffer;
384
385    #[inline]
386    fn next(&mut self) -> Option<Self::Item> {
387        if self.start_idx >= self.end_idx {
388            return None;
389        }
390
391        let buffer = unsafe {
392            let buffer = Buffer::from_glib_none(ffi::gst_buffer_list_get(
393                self.list.as_mut_ptr(),
394                self.start_idx as u32,
395            ));
396            ffi::gst_buffer_list_remove(self.list.as_mut_ptr(), self.start_idx as u32, 1);
397            buffer
398        };
399
400        self.end_idx -= 1;
401
402        Some(buffer)
403    }
404
405    #[inline]
406    fn size_hint(&self) -> (usize, Option<usize>) {
407        let remaining = self.end_idx - self.start_idx;
408
409        (remaining, Some(remaining))
410    }
411
412    #[inline]
413    fn count(self) -> usize {
414        self.end_idx - self.start_idx
415    }
416
417    #[inline]
418    fn nth(&mut self, n: usize) -> Option<Self::Item> {
419        let (end, overflow) = self.start_idx.overflowing_add(n);
420        if end >= self.end_idx || overflow {
421            unsafe {
422                ffi::gst_buffer_list_remove(
423                    self.list.as_mut_ptr(),
424                    self.start_idx as u32,
425                    (self.end_idx - self.start_idx) as u32,
426                );
427            }
428            self.start_idx = self.end_idx;
429            None
430        } else {
431            let buffer = unsafe {
432                let buffer = Buffer::from_glib_none(ffi::gst_buffer_list_get(
433                    self.list.as_mut_ptr(),
434                    end as u32,
435                ));
436                ffi::gst_buffer_list_remove(
437                    self.list.as_mut_ptr(),
438                    self.start_idx as u32,
439                    n as u32,
440                );
441                buffer
442            };
443            self.end_idx -= n;
444            Some(buffer)
445        }
446    }
447
448    #[inline]
449    fn last(mut self) -> Option<Self::Item> {
450        if self.start_idx == self.end_idx {
451            None
452        } else {
453            let buffer = unsafe {
454                let buffer = Buffer::from_glib_none(ffi::gst_buffer_list_get(
455                    self.list.as_mut_ptr(),
456                    self.end_idx as u32 - 1,
457                ));
458                ffi::gst_buffer_list_remove(
459                    self.list.as_mut_ptr(),
460                    self.start_idx as u32,
461                    (self.end_idx - self.start_idx) as u32,
462                );
463                buffer
464            };
465            self.end_idx = self.start_idx;
466            Some(buffer)
467        }
468    }
469}
470
471impl DoubleEndedIterator for Drain<'_> {
472    #[inline]
473    fn next_back(&mut self) -> Option<Self::Item> {
474        if self.start_idx == self.end_idx {
475            return None;
476        }
477
478        self.end_idx -= 1;
479        let buffer = unsafe {
480            let buffer = Buffer::from_glib_none(ffi::gst_buffer_list_get(
481                self.list.as_mut_ptr(),
482                self.end_idx as u32,
483            ));
484            ffi::gst_buffer_list_remove(self.list.as_mut_ptr(), self.end_idx as u32, 1);
485            buffer
486        };
487
488        Some(buffer)
489    }
490
491    #[inline]
492    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
493        let (end, overflow) = self.end_idx.overflowing_sub(n);
494        if end <= self.start_idx || overflow {
495            unsafe {
496                ffi::gst_buffer_list_remove(
497                    self.list.as_mut_ptr(),
498                    self.start_idx as u32,
499                    (self.end_idx - self.start_idx) as u32,
500                );
501            }
502            self.start_idx = self.end_idx;
503            None
504        } else {
505            self.end_idx = end - 1;
506            let buffer = unsafe {
507                let buffer = Buffer::from_glib_none(ffi::gst_buffer_list_get(
508                    self.list.as_mut_ptr(),
509                    self.end_idx as u32,
510                ));
511                ffi::gst_buffer_list_remove(self.list.as_mut_ptr(), self.end_idx as u32, n as u32);
512                buffer
513            };
514
515            Some(buffer)
516        }
517    }
518}
519
520impl ExactSizeIterator for Drain<'_> {}
521
522impl std::iter::FusedIterator for Drain<'_> {}
523
524impl Drop for Drain<'_> {
525    fn drop(&mut self) {
526        if self.start_idx >= self.end_idx {
527            return;
528        }
529
530        unsafe {
531            ffi::gst_buffer_list_remove(
532                self.list.as_mut_ptr(),
533                self.start_idx as u32,
534                (self.end_idx - self.start_idx) as u32,
535            );
536        }
537    }
538}
539
540impl<'a> IntoIterator for &'a BufferListRef {
541    type IntoIter = Iter<'a>;
542    type Item = &'a BufferRef;
543
544    fn into_iter(self) -> Self::IntoIter {
545        self.iter()
546    }
547}
548
549impl From<Buffer> for BufferList {
550    fn from(value: Buffer) -> Self {
551        skip_assert_initialized!();
552
553        let mut list = BufferList::new_sized(1);
554        {
555            let list = list.get_mut().unwrap();
556            list.add(value);
557        }
558        list
559    }
560}
561
562impl<const N: usize> From<[Buffer; N]> for BufferList {
563    fn from(value: [Buffer; N]) -> Self {
564        skip_assert_initialized!();
565
566        let mut list = BufferList::new_sized(N);
567        {
568            let list = list.get_mut().unwrap();
569            value.into_iter().for_each(|b| list.add(b));
570        }
571        list
572    }
573}
574
575impl std::iter::FromIterator<Buffer> for BufferList {
576    fn from_iter<T: IntoIterator<Item = Buffer>>(iter: T) -> Self {
577        assert_initialized_main_thread!();
578
579        let iter = iter.into_iter();
580
581        let mut list = BufferList::new_sized(iter.size_hint().0);
582
583        {
584            let list = list.get_mut().unwrap();
585            iter.for_each(|b| list.add(b));
586        }
587
588        list
589    }
590}
591
592impl std::iter::Extend<Buffer> for BufferListRef {
593    fn extend<T: IntoIterator<Item = Buffer>>(&mut self, iter: T) {
594        iter.into_iter().for_each(|b| self.add(b));
595    }
596}
597
598#[cfg(test)]
599mod tests {
600    use super::*;
601    use crate::ClockTime;
602
603    fn make_buffer_list(size: usize) -> BufferList {
604        skip_assert_initialized!();
605
606        let mut buffer_list = BufferList::new();
607        {
608            let buffer_list = buffer_list.get_mut().unwrap();
609            for i in 0..size {
610                let mut buffer = Buffer::new();
611                buffer
612                    .get_mut()
613                    .unwrap()
614                    .set_pts(ClockTime::SECOND * i as u64);
615                buffer_list.add(buffer);
616            }
617        }
618        buffer_list
619    }
620
621    #[test]
622    fn test_foreach() {
623        crate::init().unwrap();
624
625        let buffer_list = make_buffer_list(2);
626
627        let mut res = vec![];
628        buffer_list.foreach(|buffer, idx| {
629            res.push((buffer.pts(), idx));
630            ControlFlow::Continue(())
631        });
632
633        assert_eq!(
634            res,
635            &[(Some(ClockTime::ZERO), 0), (Some(ClockTime::SECOND), 1)]
636        );
637    }
638
639    #[test]
640    fn test_foreach_mut() {
641        crate::init().unwrap();
642
643        let mut buffer_list = make_buffer_list(3);
644
645        let mut res = vec![];
646        buffer_list.get_mut().unwrap().foreach_mut(|buffer, idx| {
647            res.push((buffer.pts(), idx));
648
649            if let Some(ClockTime::ZERO) = buffer.pts() {
650                ControlFlow::Continue(Some(buffer))
651            } else if let Some(ClockTime::SECOND) = buffer.pts() {
652                ControlFlow::Continue(None)
653            } else {
654                let mut new_buffer = Buffer::new();
655                new_buffer.get_mut().unwrap().set_pts(3 * ClockTime::SECOND);
656                ControlFlow::Continue(Some(new_buffer))
657            }
658        });
659
660        assert_eq!(
661            res,
662            &[
663                (Some(ClockTime::ZERO), 0),
664                (Some(ClockTime::SECOND), 1),
665                (Some(2 * ClockTime::SECOND), 1)
666            ]
667        );
668
669        let mut res = vec![];
670        buffer_list.foreach(|buffer, idx| {
671            res.push((buffer.pts(), idx));
672            ControlFlow::Continue(())
673        });
674
675        assert_eq!(
676            res,
677            &[(Some(ClockTime::ZERO), 0), (Some(3 * ClockTime::SECOND), 1)]
678        );
679
680        // Try removing buffers from inside foreach_mut
681        let mut buffer_list = BufferList::new();
682        for i in 0..10 {
683            let buffer_list = buffer_list.get_mut().unwrap();
684            let mut buffer = Buffer::new();
685            buffer.get_mut().unwrap().set_pts(i * ClockTime::SECOND);
686            buffer_list.add(buffer);
687        }
688
689        assert_eq!(buffer_list.len(), 10);
690
691        let buffer_list_ref = buffer_list.make_mut();
692
693        buffer_list_ref.foreach_mut(|buf, _n| {
694            let keep_packet = (buf.pts().unwrap() / ClockTime::SECOND) % 3 != 0;
695            ControlFlow::Continue(keep_packet.then_some(buf))
696        });
697
698        assert_eq!(buffer_list.len(), 6);
699
700        let res = buffer_list
701            .iter()
702            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
703            .collect::<Vec<_>>();
704
705        assert_eq!(res, &[1, 2, 4, 5, 7, 8]);
706    }
707
708    #[test]
709    fn test_remove() {
710        crate::init().unwrap();
711
712        let mut buffer_list = make_buffer_list(10);
713
714        buffer_list.make_mut().remove(0..2);
715
716        let buffers_left = buffer_list
717            .iter()
718            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
719            .collect::<Vec<_>>();
720
721        assert_eq!(buffers_left, &[2, 3, 4, 5, 6, 7, 8, 9]);
722
723        buffer_list.make_mut().remove(0..=2);
724
725        let buffers_left = buffer_list
726            .iter()
727            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
728            .collect::<Vec<_>>();
729
730        assert_eq!(buffers_left, &[5, 6, 7, 8, 9]);
731
732        buffer_list.make_mut().remove(2..);
733
734        let buffers_left = buffer_list
735            .iter()
736            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
737            .collect::<Vec<_>>();
738
739        assert_eq!(buffers_left, &[5, 6]);
740
741        buffer_list.make_mut().remove(..);
742
743        assert!(buffer_list.is_empty());
744    }
745
746    #[test]
747    fn test_drain() {
748        crate::init().unwrap();
749
750        let mut buffer_list = make_buffer_list(10);
751
752        let buffers_removed = buffer_list
753            .make_mut()
754            .drain(0..2)
755            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
756            .collect::<Vec<_>>();
757
758        assert_eq!(buffers_removed, &[0, 1]);
759
760        let buffers_left = buffer_list
761            .iter()
762            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
763            .collect::<Vec<_>>();
764
765        assert_eq!(buffers_left, &[2, 3, 4, 5, 6, 7, 8, 9]);
766
767        let buffers_removed = buffer_list
768            .make_mut()
769            .drain(0..=2)
770            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
771            .collect::<Vec<_>>();
772
773        assert_eq!(buffers_removed, &[2, 3, 4]);
774
775        let buffers_left = buffer_list
776            .iter()
777            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
778            .collect::<Vec<_>>();
779
780        assert_eq!(buffers_left, &[5, 6, 7, 8, 9]);
781
782        let buffers_removed = buffer_list
783            .make_mut()
784            .drain(2..)
785            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
786            .collect::<Vec<_>>();
787
788        assert_eq!(buffers_removed, &[7, 8, 9]);
789
790        let buffers_left = buffer_list
791            .iter()
792            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
793            .collect::<Vec<_>>();
794
795        assert_eq!(buffers_left, &[5, 6]);
796
797        let buffers_removed = buffer_list
798            .make_mut()
799            .drain(..)
800            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
801            .collect::<Vec<_>>();
802
803        assert_eq!(buffers_removed, &[5, 6]);
804
805        assert!(buffer_list.is_empty());
806    }
807
808    #[test]
809    fn test_drain_drop() {
810        crate::init().unwrap();
811
812        let mut buffer_list = make_buffer_list(10);
813
814        buffer_list.make_mut().drain(0..2);
815
816        let buffers_left = buffer_list
817            .iter()
818            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
819            .collect::<Vec<_>>();
820
821        assert_eq!(buffers_left, &[2, 3, 4, 5, 6, 7, 8, 9]);
822
823        buffer_list.make_mut().drain(0..=2);
824
825        let buffers_left = buffer_list
826            .iter()
827            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
828            .collect::<Vec<_>>();
829
830        assert_eq!(buffers_left, &[5, 6, 7, 8, 9]);
831
832        buffer_list.make_mut().drain(2..);
833
834        let buffers_left = buffer_list
835            .iter()
836            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
837            .collect::<Vec<_>>();
838
839        assert_eq!(buffers_left, &[5, 6]);
840
841        buffer_list.make_mut().drain(..);
842
843        assert!(buffer_list.is_empty());
844    }
845}