Skip to main content

toasty_core/stmt/
value_stream.rs

1use crate::schema::Schema;
2use crate::stmt::Type;
3
4use super::Value;
5
6use std::{
7    collections::VecDeque,
8    fmt, mem,
9    panic::Location,
10    pin::Pin,
11    sync::Arc,
12    task::{Context, Poll},
13};
14use tokio_stream::{Stream, StreamExt};
15
16/// An async stream of [`Value`]s with optional type checking.
17///
18/// `ValueStream` combines a buffered front-end with an optional async
19/// [`Stream`] back-end. Values can be pushed into the buffer or pulled
20/// from the underlying stream. When a [`Type`] is attached via
21/// [`typed`](ValueStream::typed), every yielded value is checked at
22/// runtime.
23///
24/// Implements [`Stream`] from `tokio_stream`, yielding
25/// `Result<Value>` items.
26///
27/// # Examples
28///
29/// ```ignore
30/// use toasty_core::stmt::{Value, ValueStream};
31///
32/// let mut stream = ValueStream::from_value(Value::from(42_i64));
33/// let val = stream.next().await.unwrap().unwrap();
34/// assert_eq!(val, Value::from(42_i64));
35/// ```
36#[derive(Default)]
37pub struct ValueStream {
38    buffer: Buffer,
39    stream: Option<DynStream>,
40
41    /// If set, check values to ensure they are the correct type. The schema
42    /// resolves `Type::Model` (`#[document]`) field layouts for the check.
43    ty: Option<(Arc<Schema>, Type, &'static Location<'static>)>,
44}
45
46#[derive(Debug)]
47struct Iter<I> {
48    iter: I,
49}
50
51#[derive(Clone, Default)]
52enum Buffer {
53    #[default]
54    Empty,
55    One(Value),
56    Many(VecDeque<Value>),
57}
58
59type DynStream = Pin<Box<dyn Stream<Item = crate::Result<Value>> + Send + 'static>>;
60
61impl ValueStream {
62    /// Creates a stream containing a single value.
63    pub fn from_value(value: impl Into<Value>) -> Self {
64        Self {
65            buffer: Buffer::One(value.into()),
66            stream: None,
67            ty: None,
68        }
69    }
70
71    /// Creates a stream backed by an async [`Stream`] of `Result<Value>`.
72    pub fn from_stream<T: Stream<Item = crate::Result<Value>> + Send + 'static>(stream: T) -> Self {
73        Self {
74            buffer: Buffer::Empty,
75            stream: Some(Box::pin(stream)),
76            ty: None,
77        }
78    }
79
80    /// Creates a fully-buffered stream from a vector of values.
81    pub fn from_vec(records: Vec<Value>) -> Self {
82        Self {
83            buffer: Buffer::Many(records.into()),
84            stream: None,
85            ty: None,
86        }
87    }
88
89    /// Creates a stream from a fallible iterator.
90    #[allow(clippy::should_implement_trait)]
91    pub fn from_iter<T, I>(iter: I) -> Self
92    where
93        T: Into<Value>,
94        I: Iterator<Item = crate::Result<T>> + Send + 'static,
95    {
96        Self::from_stream(Iter { iter })
97    }
98
99    /// Returns the next record in the stream
100    pub async fn next(&mut self) -> Option<crate::Result<Value>> {
101        StreamExt::next(self).await
102    }
103
104    /// Peek at the next record in the stream
105    pub async fn peek(&mut self) -> Option<crate::Result<&Value>> {
106        if self.buffer.is_empty() {
107            match self.next().await {
108                Some(Ok(value)) => self.buffer.push(value),
109                Some(Err(e)) => return Some(Err(e)),
110                None => return None,
111            }
112        }
113
114        self.buffer.first().map(Ok)
115    }
116
117    /// Force the stream to preload at least one record, if there are more
118    /// records to stream.
119    pub async fn tap(&mut self) -> crate::Result<()> {
120        if let Some(Err(e)) = self.peek().await {
121            Err(e)
122        } else {
123            Ok(())
124        }
125    }
126
127    /// Returns the minimum number of elements this stream will yield.
128    ///
129    /// This is derived from the stream's `size_hint` lower bound plus
130    /// the number of buffered elements.
131    pub fn min_len(&self) -> usize {
132        let (ret, _) = self.size_hint();
133        ret
134    }
135
136    /// Consumes the stream and collects all values into a `Vec`.
137    pub async fn collect(mut self) -> crate::Result<Vec<Value>> {
138        let mut ret = Vec::with_capacity(self.min_len());
139
140        while let Some(res) = self.next().await {
141            ret.push(res?);
142        }
143
144        Ok(ret)
145    }
146
147    /// Fully buffers the stream and returns a clone of it.
148    ///
149    /// After this call, both the original and the returned stream are
150    /// fully buffered and contain the same values.
151    pub async fn dup(&mut self) -> crate::Result<Self> {
152        self.buffer().await?;
153
154        Ok(Self {
155            buffer: self.buffer.clone(),
156            stream: None,
157            ty: self.ty.clone(),
158        })
159    }
160
161    /// Returns a clone if the stream is fully buffered, or `None` if
162    /// there is an unconsumed async stream that cannot be cloned.
163    pub fn try_clone(&self) -> Option<Self> {
164        if self.stream.is_some() {
165            return None;
166        }
167
168        Some(Self {
169            buffer: self.buffer.clone(),
170            stream: None,
171            ty: self.ty.clone(),
172        })
173    }
174
175    /// Drains the underlying async stream into the buffer.
176    ///
177    /// After this call, all remaining values are buffered locally and
178    /// [`is_buffered`](ValueStream::is_buffered) returns `true`.
179    pub async fn buffer(&mut self) -> crate::Result<()> {
180        if let Some(stream) = &mut self.stream {
181            while let Some(res) = stream.next().await {
182                let value = res?;
183
184                if let Some((schema, ty, location)) = &self.ty {
185                    assert!(
186                        value.is_a(&schema.app, ty),
187                        "expected `{ty:?}`; was={value:#?}; origin={location}"
188                    );
189                }
190
191                self.buffer.push(value);
192            }
193        }
194
195        Ok(())
196    }
197
198    /// Returns `true` if the ValueStream is fully buffered (no remaining stream)
199    pub fn is_buffered(&self) -> bool {
200        self.stream.is_none()
201    }
202
203    /// Returns a clone of only the currently buffered values
204    /// Does not consume any stream data or wait for additional values
205    pub fn buffered_to_vec(&self) -> Vec<Value> {
206        match &self.buffer {
207            Buffer::Empty => Vec::new(),
208            Buffer::One(value) => vec![value.clone()],
209            Buffer::Many(values) => values.iter().cloned().collect(),
210        }
211    }
212
213    /// Returns a mutable iterator over the buffered values.
214    ///
215    /// # Panics
216    ///
217    /// Panics if the stream has an unconsumed async back-end. Call
218    /// [`buffer`](ValueStream::buffer) first to ensure all values are
219    /// buffered.
220    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Value> {
221        assert!(self.stream.is_none());
222
223        // TODO: don't box
224        match &mut self.buffer {
225            Buffer::Empty => Box::new(None.into_iter()),
226            Buffer::One(v) => Box::new(Some(v).into_iter()),
227            Buffer::Many(v) => Box::new(v.iter_mut()) as Box<dyn Iterator<Item = &mut Value>>,
228        }
229    }
230
231    /// Attaches a [`Type`] constraint to this stream.
232    ///
233    /// Every value yielded from the stream (both already-buffered and
234    /// future) will be checked against `ty` at runtime. If a value does
235    /// not match, the check panics with a diagnostic message.
236    ///
237    /// # Panics
238    ///
239    /// Panics if an already-buffered value is not compatible with `ty`,
240    /// or if a previously set type differs from `ty`.
241    #[track_caller]
242    pub fn typed(mut self, schema: Arc<Schema>, ty: Type) -> ValueStream {
243        let location = Location::caller();
244
245        match &self.ty {
246            Some((_, prev, _)) => assert_eq!(*prev, ty),
247            None => {
248                // Validate already-buffered values against the new type.
249                // Document values have already been raised to their positional
250                // `Value::Record` form by the engine (see the engine's
251                // document raising), so this is a shape check only.
252                let mut tmp = mem::take(&mut self.buffer);
253                while let Some(value) = tmp.next() {
254                    assert!(
255                        value.is_a(&schema.app, &ty),
256                        "expected `{ty:?}`; was={value:#?}; origin={location}"
257                    );
258                    self.buffer.push(value);
259                }
260
261                self.ty = Some((schema, ty, location));
262            }
263        }
264
265        self
266    }
267}
268
269impl Stream for ValueStream {
270    type Item = crate::Result<Value>;
271
272    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
273        if let Some(next) = self.buffer.next() {
274            Poll::Ready(Some(Ok(next)))
275        } else if let Some(stream) = self.stream.as_mut() {
276            match Pin::new(stream).poll_next(cx) {
277                Poll::Ready(Some(Ok(value))) => {
278                    if let Some((schema, ty, location)) = &self.ty {
279                        assert!(
280                            value.is_a(&schema.app, ty),
281                            "expected `{ty:?}`; was={value:#?}; origin={location}"
282                        );
283                    }
284                    Poll::Ready(Some(Ok(value)))
285                }
286
287                other => other,
288            }
289        } else {
290            Poll::Ready(None)
291        }
292    }
293
294    fn size_hint(&self) -> (usize, Option<usize>) {
295        let (mut low, mut high) = match &self.stream {
296            Some(stream) => stream.size_hint(),
297            None => (0, Some(0)),
298        };
299
300        let buffered = self.buffer.len();
301
302        low += buffered;
303
304        if let Some(high) = high.as_mut() {
305            *high += buffered;
306        }
307
308        (low, high)
309    }
310}
311
312impl From<Value> for ValueStream {
313    fn from(src: Value) -> Self {
314        Self {
315            buffer: Buffer::One(src),
316            stream: None,
317            ty: None,
318        }
319    }
320}
321
322impl From<Vec<Value>> for ValueStream {
323    fn from(value: Vec<Value>) -> Self {
324        Self::from_vec(value)
325    }
326}
327
328impl<I> Unpin for Iter<I> {}
329
330impl<T, I> Stream for Iter<I>
331where
332    I: Iterator<Item = crate::Result<T>>,
333    T: Into<Value>,
334{
335    type Item = crate::Result<Value>;
336
337    fn poll_next(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<Self::Item>> {
338        Poll::Ready(self.iter.next().map(|res| res.map(|item| item.into())))
339    }
340
341    fn size_hint(&self) -> (usize, Option<usize>) {
342        self.iter.size_hint()
343    }
344}
345
346impl fmt::Debug for ValueStream {
347    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
348        f.debug_struct("RecordStream").finish()
349    }
350}
351
352impl Buffer {
353    fn is_empty(&self) -> bool {
354        self.len() == 0
355    }
356
357    fn len(&self) -> usize {
358        match self {
359            Self::Empty => 0,
360            Self::One(_) => 1,
361            Self::Many(v) => v.len(),
362        }
363    }
364
365    fn first(&self) -> Option<&Value> {
366        match self {
367            Self::Empty => None,
368            Self::One(value) => Some(value),
369            Self::Many(values) => values.front(),
370        }
371    }
372
373    fn next(&mut self) -> Option<Value> {
374        match self {
375            Self::Empty => None,
376            Self::One(_) => {
377                let Self::One(value) = mem::take(self) else {
378                    panic!()
379                };
380                Some(value)
381            }
382            Self::Many(values) => values.pop_front(),
383        }
384    }
385
386    fn push(&mut self, value: Value) {
387        match self {
388            Self::Empty => {
389                *self = Self::One(value);
390            }
391            Self::One(_) => {
392                let Self::One(first) = mem::replace(self, Self::Many(VecDeque::with_capacity(2)))
393                else {
394                    panic!()
395                };
396
397                let Self::Many(values) = self else { panic!() };
398
399                values.push_back(first);
400                values.push_back(value);
401            }
402            Self::Many(values) => {
403                values.push_back(value);
404            }
405        }
406    }
407}