rodio/source/
from_iter.rs

1use std::time::Duration;
2
3use super::SeekError;
4use crate::common::{ChannelCount, SampleRate};
5use crate::Source;
6
7/// Builds a source that chains sources provided by an iterator.
8///
9/// The `iterator` parameter is an iterator that produces a source. The source is then played.
10/// Whenever the source ends, the `iterator` is used again in order to produce the source that is
11/// played next.
12///
13/// If the `iterator` produces `None`, then the sound ends.
14pub fn from_iter<I>(iterator: I) -> FromIter<I::IntoIter>
15where
16    I: IntoIterator,
17{
18    let mut iterator = iterator.into_iter();
19    let first_source = iterator.next();
20
21    FromIter {
22        iterator,
23        current_source: first_source,
24    }
25}
26
27/// A source that chains sources provided by an iterator.
28#[derive(Clone)]
29pub struct FromIter<I>
30where
31    I: Iterator,
32{
33    // The iterator that provides sources.
34    iterator: I,
35    // Is only ever `None` if the first element of the iterator is `None`.
36    current_source: Option<I::Item>,
37}
38
39impl<I> Iterator for FromIter<I>
40where
41    I: Iterator,
42    I::Item: Iterator + Source,
43{
44    type Item = <I::Item as Iterator>::Item;
45
46    #[inline]
47    fn next(&mut self) -> Option<Self::Item> {
48        loop {
49            if let Some(src) = &mut self.current_source {
50                if let Some(value) = src.next() {
51                    return Some(value);
52                }
53            }
54
55            if let Some(src) = self.iterator.next() {
56                self.current_source = Some(src);
57            } else {
58                return None;
59            }
60        }
61    }
62
63    #[inline]
64    fn size_hint(&self) -> (usize, Option<usize>) {
65        if let Some(cur) = &self.current_source {
66            (cur.size_hint().0, None)
67        } else {
68            (0, None)
69        }
70    }
71}
72
73impl<I> Source for FromIter<I>
74where
75    I: Iterator,
76    I::Item: Iterator + Source,
77{
78    #[inline]
79    fn current_span_len(&self) -> Option<usize> {
80        // This function is non-trivial because the boundary between the current source and the
81        // next must be a span boundary as well.
82        //
83        // The current sound is free to return `None` for `current_span_len()`, in which case
84        // we *should* return the number of samples remaining the current sound.
85        // This can be estimated with `size_hint()`.
86        //
87        // If the `size_hint` is `None` as well, we are in the worst case scenario. To handle this
88        // situation we force a span to have a maximum number of samples indicate by this
89        // constant.
90        const THRESHOLD: usize = 10240;
91
92        // Try the current `current_span_len`.
93        if let Some(src) = &self.current_source {
94            if let Some(val) = src.current_span_len() {
95                if val != 0 {
96                    return Some(val);
97                }
98            }
99        }
100
101        // Try the size hint.
102        if let Some(src) = &self.current_source {
103            if let Some(val) = src.size_hint().1 {
104                if val < THRESHOLD && val != 0 {
105                    return Some(val);
106                }
107            }
108        }
109
110        // Otherwise we use the constant value.
111        Some(THRESHOLD)
112    }
113
114    #[inline]
115    fn channels(&self) -> ChannelCount {
116        if let Some(src) = &self.current_source {
117            src.channels()
118        } else {
119            // Dummy value that only happens if the iterator was empty.
120            2
121        }
122    }
123
124    #[inline]
125    fn sample_rate(&self) -> SampleRate {
126        if let Some(src) = &self.current_source {
127            src.sample_rate()
128        } else {
129            // Dummy value that only happens if the iterator was empty.
130            44100
131        }
132    }
133
134    #[inline]
135    fn total_duration(&self) -> Option<Duration> {
136        None
137    }
138
139    #[inline]
140    fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
141        if let Some(source) = self.current_source.as_mut() {
142            source.try_seek(pos)
143        } else {
144            Ok(())
145        }
146    }
147}
148
149#[cfg(test)]
150mod tests {
151    use crate::buffer::SamplesBuffer;
152    use crate::source::{from_iter, Source};
153
154    #[test]
155    fn basic() {
156        let mut rx = from_iter((0..2).map(|n| {
157            if n == 0 {
158                SamplesBuffer::new(1, 48000, vec![10.0, -10.0, 10.0, -10.0])
159            } else if n == 1 {
160                SamplesBuffer::new(2, 96000, vec![5.0, 5.0, 5.0, 5.0])
161            } else {
162                unreachable!()
163            }
164        }));
165
166        assert_eq!(rx.channels(), 1);
167        assert_eq!(rx.sample_rate(), 48000);
168        assert_eq!(rx.next(), Some(10.0));
169        assert_eq!(rx.next(), Some(-10.0));
170        assert_eq!(rx.next(), Some(10.0));
171        assert_eq!(rx.next(), Some(-10.0));
172        /*assert_eq!(rx.channels(), 2);
173        assert_eq!(rx.sample_rate(), 96000);*/
174        // FIXME: not working
175        assert_eq!(rx.next(), Some(5.0));
176        assert_eq!(rx.next(), Some(5.0));
177        assert_eq!(rx.next(), Some(5.0));
178        assert_eq!(rx.next(), Some(5.0));
179        assert_eq!(rx.next(), None);
180    }
181}