Skip to main content

substrate_data/wire/
stream.rs

1//! [`Stream`]: a list kept in the binary form — its items written as they
2//! come (no `Vec` of them on the way), checked when the stream is decoded
3//! and read back one at a time, when asked. For the big ones: a table's rows, a picture's pixels, a log.
4//!
5//! ```
6//! use substrate_data::{Schema, Stream};
7//!
8//! #[derive(Schema)]
9//! struct Sheet {
10//!     name: String,
11//!     cells: Stream<u16>,
12//! }
13//!
14//! let sheet = Sheet { name: "q3".into(), cells: (0..1000u16).map(|i| i % 3).collect() };
15//! let back: Sheet = substrate_data::read_bytes(&substrate_data::to_bytes(&sheet)).unwrap();
16//! assert_eq!(back.cells.len(), 1000);
17//! assert_eq!(back.cells.iter().filter(|c| *c == 2).count(), 333);
18//! ```
19
20use std::fmt;
21use std::marker::PhantomData;
22
23use crate::binary::{Decoder, Writer};
24use crate::frame::{Packer, Unpacker};
25use crate::model::borrowed::ValueRef;
26use crate::model::value::{Seg, Value};
27use crate::schema::{Reader, Schema, Shape};
28
29/// A list of `T` kept written: its body in the binary form, its strings its own.
30pub struct Stream<T> {
31    /// The items, written one after another.
32    items: Vec<u8>,
33    len: usize,
34    item: PhantomData<fn() -> T>,
35}
36
37impl<T: Schema> Stream<T> {
38    /// Writes items one by one ([`StreamWriter::push`]).
39    #[must_use]
40    pub fn writer() -> StreamWriter<T> {
41        StreamWriter {
42            w: Writer::body(),
43            len: 0,
44            item: PhantomData,
45        }
46    }
47
48    /// How many items.
49    #[must_use]
50    pub fn len(&self) -> usize {
51        self.len
52    }
53
54    /// Whether it has none.
55    #[must_use]
56    pub fn is_empty(&self) -> bool {
57        self.len == 0
58    }
59
60    /// The items, read as they're asked for. A stream that was decoded has had
61    /// every item checked, so none is unreadable.
62    pub fn iter(&self) -> impl Iterator<Item = T> + '_ {
63        let mut d = Decoder::body(&self.items);
64        (0..self.len).map_while(move |_| T::decode(&mut d))
65    }
66
67    /// Every item, read now.
68    #[must_use]
69    pub fn to_vec(&self) -> Vec<T> {
70        self.iter().collect()
71    }
72
73    /// How many bytes it takes.
74    #[must_use]
75    pub fn bytes_len(&self) -> usize {
76        self.items.len()
77    }
78}
79
80/// Writes a [`Stream`]'s items as they come.
81#[derive(Debug)]
82pub struct StreamWriter<T> {
83    w: Writer,
84    len: usize,
85    item: PhantomData<fn() -> T>,
86}
87
88impl<T: Schema> StreamWriter<T> {
89    /// Writes `item`.
90    pub fn push(&mut self, item: &T) {
91        item.encode(&mut self.w);
92        self.len += 1;
93    }
94
95    /// The stream written.
96    #[must_use]
97    pub fn finish(self) -> Stream<T> {
98        Stream {
99            items: self.w.finish(),
100            len: self.len,
101            item: PhantomData,
102        }
103    }
104}
105
106impl<T: Schema> FromIterator<T> for Stream<T> {
107    fn from_iter<I: IntoIterator<Item = T>>(items: I) -> Self {
108        let mut w = Stream::writer();
109        for item in items {
110            w.push(&item);
111        }
112        w.finish()
113    }
114}
115
116impl<T: Schema> From<Vec<T>> for Stream<T> {
117    fn from(items: Vec<T>) -> Self {
118        items.into_iter().collect()
119    }
120}
121
122impl<T> Clone for Stream<T> {
123    fn clone(&self) -> Self {
124        Stream {
125            items: self.items.clone(),
126            len: self.len,
127            item: PhantomData,
128        }
129    }
130}
131
132impl<T> PartialEq for Stream<T> {
133    fn eq(&self, other: &Self) -> bool {
134        self.len == other.len && self.items == other.items
135    }
136}
137
138impl<T> Default for Stream<T> {
139    fn default() -> Self {
140        Stream {
141            items: Vec::new(),
142            len: 0,
143            item: PhantomData,
144        }
145    }
146}
147
148impl<T> fmt::Debug for Stream<T> {
149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150        write!(f, "Stream({} items, {} bytes)", self.len, self.items.len())
151    }
152}
153
154impl<T: Schema> Schema for Stream<T> {
155    fn shape() -> Shape {
156        Shape::List(T::shape)
157    }
158    /// The slow way (a text file, a value): read whole, then written.
159    fn read(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<Self> {
160        let ValueRef::List(items) = v else {
161            cx.expected(crate::schema::Expected::List, v);
162            return None;
163        };
164        let mut w = Stream::writer();
165        let mut ok = true;
166        for (i, item) in items.iter().enumerate() {
167            match cx.at(Seg::Index(i), |cx| T::read(item, cx)) {
168                Some(x) => w.push(&x),
169                None => ok = false,
170            }
171        }
172        ok.then(|| w.finish())
173    }
174    fn write(&self) -> Value {
175        Value::List(self.iter().map(|item| item.write()).collect())
176    }
177    fn encode(&self, w: &mut Writer) {
178        w.stream_body(self.len, &self.items);
179    }
180    fn decode(d: &mut Decoder<'_>) -> Option<Self> {
181        let mut body = Decoder::body(d.stream()?);
182        let len = body.stream_count()?;
183        // Every item is read once now, so a stream that decodes is one whose
184        // items all read: an item this `T` cannot read (a newer item type,
185        // a corrupt byte) fails the stream, as it does in the text form and
186        // in a frame, and the slow path names its index.
187        let items = body.rest();
188        let mut check = Decoder::body(items);
189        for _ in 0..len {
190            T::decode(&mut check)?;
191        }
192        check.at_end().then(|| Stream {
193            items: items.to_vec(),
194            len,
195            item: PhantomData,
196        })
197    }
198    /// In a frame it's a list, as its shape says.
199    fn pack(&self, p: &mut Packer) {
200        T::pack_list(&self.to_vec(), p);
201    }
202    fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
203        T::unpack_list(u).map(Stream::from)
204    }
205}