Skip to main content

resand/
stream.rs

1use std::{
2    any::type_name,
3    fmt::Display,
4    io::{Read, Seek, Write},
5};
6
7#[derive(Debug)]
8pub struct StreamError {
9    pub error: std::io::Error,
10    pub pos: u64,
11    pub context: Vec<String>,
12}
13
14impl StreamError {
15    pub fn new_context(error: std::io::Error, pos: u64, context: Vec<String>) -> Self {
16        Self {
17            error,
18            pos,
19            context,
20        }
21    }
22
23    pub fn new(error: std::io::Error, pos: u64) -> Self {
24        Self {
25            error,
26            pos,
27            context: Vec::new(),
28        }
29    }
30
31    pub fn add_context<C: ToString>(self, new_context: C) -> Self {
32        let mut context = self.context;
33        context.push(new_context.to_string());
34        Self::new_context(self.error, self.pos, context)
35    }
36
37    pub fn new_string_context<E: ToString, C: ToString>(error: E, pos: u64, context: C) -> Self {
38        Self {
39            error: std::io::Error::other(error.to_string()),
40            pos,
41            context: vec![context.to_string()],
42        }
43    }
44}
45
46impl Display for StreamError {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        let string = format!("error: {} at {} with context:", self.error, self.pos);
49
50        let mut context_str = String::new();
51
52        for ctx in &self.context {
53            context_str.push_str(&format!("\n{ctx}"));
54        }
55
56        write!(f, "{string}\n{context_str}")
57    }
58}
59
60pub type StreamResult<T> = Result<T, StreamError>;
61
62pub trait NewResultCtx {
63    fn add_context<C: ToString, F: FnOnce() -> C>(self, context: F) -> Self;
64}
65
66impl<T> NewResultCtx for StreamResult<T> {
67    fn add_context<C: ToString, F: FnOnce() -> C>(self, context: F) -> Self {
68        match self {
69            Ok(v) => Ok(v),
70            Err(e) => Err(e.add_context(context())),
71        }
72    }
73}
74
75pub trait Readable: Sized {
76    type Args;
77    fn read<R: Read + Seek>(reader: &mut R, args: Self::Args) -> StreamResult<Self>;
78}
79
80pub trait Writeable: Sized {
81    type Args;
82    fn write<W: Write + Seek>(self, writer: &mut W, args: Self::Args) -> StreamResult<()>;
83}
84
85pub trait ResultCtx: Sized {
86    type OkT;
87    fn with_context<C: ToString, F: FnOnce() -> C>(
88        self,
89        pos: u64,
90        context: F,
91    ) -> StreamResult<Self::OkT>;
92    fn stream_context<C: ToString, F: FnOnce() -> C>(self, context: F) -> StreamResult<Self::OkT>;
93    fn with_pos(self, pos: u64) -> StreamResult<Self::OkT>;
94}
95
96impl From<std::io::Error> for StreamError {
97    fn from(value: std::io::Error) -> Self {
98        Self::new(value, u64::MAX)
99    }
100}
101
102impl<T> ResultCtx for Result<T, std::io::Error> {
103    type OkT = T;
104    fn with_context<C: ToString, F: FnOnce() -> C>(
105        self,
106        pos: u64,
107        context: F,
108    ) -> StreamResult<<Self as ResultCtx>::OkT> {
109        match self {
110            Ok(v) => StreamResult::Ok(v),
111            Err(e) => StreamResult::Err(StreamError::new_context(
112                e,
113                pos,
114                vec![context().to_string()],
115            )),
116        }
117    }
118    fn with_pos(self, pos: u64) -> StreamResult<Self::OkT> {
119        match self {
120            Ok(v) => StreamResult::Ok(v),
121            Err(e) => StreamResult::Err(StreamError::new(e, pos)),
122        }
123    }
124    fn stream_context<C: ToString, F: FnOnce() -> C>(self, context: F) -> StreamResult<Self::OkT> {
125        self.with_context(u64::MAX, context)
126    }
127}
128
129fn read_data<R: Read + Seek, const N: usize>(reader: &mut R) -> StreamResult<[u8; N]> {
130    let mut buf = [0; N];
131    reader
132        .read_exact(&mut buf)
133        .with_context(reader.stream_position()?, || format!("read_data<{N}>"))?;
134    Ok(buf)
135}
136
137fn write_data<W: Write + Seek>(data: &[u8], writer: &mut W) -> StreamResult<()> {
138    writer
139        .write_all(data)
140        .with_context(writer.stream_position()?, || "write_data")
141}
142
143pub trait ReadableNoOptions: Sized {
144    fn read_no_opts<R: Read + Seek>(reader: &mut R) -> StreamResult<Self>;
145}
146
147pub trait WriteableNoOptions {
148    fn write_no_opts<W: Write + Seek>(self, writer: &mut W) -> StreamResult<()>;
149}
150
151impl<T: Readable<Args = ()>> ReadableNoOptions for T {
152    fn read_no_opts<R: Read + Seek>(reader: &mut R) -> StreamResult<Self> {
153        T::read(reader, ())
154    }
155}
156
157impl<T: Writeable<Args = ()>> WriteableNoOptions for T {
158    fn write_no_opts<W: Write + Seek>(self, writer: &mut W) -> StreamResult<()> {
159        self.write(writer, ())
160    }
161}
162
163impl Readable for u8 {
164    type Args = ();
165    fn read<R: Read + Seek>(reader: &mut R, _args: Self::Args) -> StreamResult<Self> {
166        Ok(Self::from_le_bytes(
167            read_data(reader).add_context(|| "read u8")?,
168        ))
169    }
170}
171
172impl Readable for u16 {
173    type Args = ();
174    fn read<R: Read + Seek>(reader: &mut R, _args: Self::Args) -> StreamResult<Self> {
175        Ok(Self::from_le_bytes(
176            read_data(reader).add_context(|| "read u16")?,
177        ))
178    }
179}
180
181impl Readable for u32 {
182    type Args = ();
183    fn read<R: Read + Seek>(reader: &mut R, _args: Self::Args) -> StreamResult<Self> {
184        Ok(Self::from_le_bytes(
185            read_data(reader).add_context(|| "read u32")?,
186        ))
187    }
188}
189
190impl Readable for u64 {
191    type Args = ();
192    fn read<R: Read + Seek>(reader: &mut R, _args: Self::Args) -> StreamResult<Self> {
193        Ok(Self::from_le_bytes(
194            read_data(reader).add_context(|| "read u64")?,
195        ))
196    }
197}
198
199impl Readable for f32 {
200    type Args = ();
201    fn read<R: Read + Seek>(reader: &mut R, _args: Self::Args) -> StreamResult<Self> {
202        Ok(Self::from_le_bytes(
203            read_data(reader).add_context(|| "read f32")?,
204        ))
205    }
206}
207impl Readable for f64 {
208    type Args = ();
209    fn read<R: Read + Seek>(reader: &mut R, _args: Self::Args) -> StreamResult<Self> {
210        Ok(Self::from_le_bytes(
211            read_data(reader).add_context(|| "read f64")?,
212        ))
213    }
214}
215
216impl Writeable for u8 {
217    type Args = ();
218    fn write<W: Write + Seek>(self, writer: &mut W, _args: Self::Args) -> StreamResult<()> {
219        write_data(&self.to_le_bytes(), writer).add_context(|| "write u8")
220    }
221}
222
223impl Writeable for u16 {
224    type Args = ();
225    fn write<W: Write + Seek>(self, writer: &mut W, _args: Self::Args) -> StreamResult<()> {
226        write_data(&self.to_le_bytes(), writer).add_context(|| "write u16")
227    }
228}
229
230impl Writeable for u32 {
231    type Args = ();
232    fn write<W: Write + Seek>(self, writer: &mut W, _args: Self::Args) -> StreamResult<()> {
233        write_data(&self.to_le_bytes(), writer).add_context(|| "write u32")
234    }
235}
236impl Writeable for u64 {
237    type Args = ();
238    fn write<W: Write + Seek>(self, writer: &mut W, _args: Self::Args) -> StreamResult<()> {
239        write_data(&self.to_le_bytes(), writer).add_context(|| "write u64")
240    }
241}
242impl Writeable for f32 {
243    type Args = ();
244    fn write<W: Write + Seek>(self, writer: &mut W, _args: Self::Args) -> StreamResult<()> {
245        write_data(&self.to_le_bytes(), writer).add_context(|| "write f32")
246    }
247}
248impl Writeable for f64 {
249    type Args = ();
250    fn write<W: Write + Seek>(self, writer: &mut W, _args: Self::Args) -> StreamResult<()> {
251        write_data(&self.to_le_bytes(), writer).add_context(|| "write f64")
252    }
253}
254
255pub trait VecReadable: Sized {
256    fn read_vec<R: Read + Seek>(reader: &mut R, count: usize) -> StreamResult<Self>;
257}
258
259pub trait VecWritable {
260    fn write_vec<W: Write + Seek>(self, writer: &mut W) -> StreamResult<()>;
261}
262
263impl<T: ReadableNoOptions> VecReadable for Vec<T> {
264    fn read_vec<R: Read + Seek>(reader: &mut R, count: usize) -> StreamResult<Self> {
265        let mut data = Vec::with_capacity(count);
266
267        for i in 0..count {
268            data.push(T::read_no_opts(reader).add_context(|| {
269                format!("reading item {} of vec of type {}", i, type_name::<T>())
270            })?);
271        }
272
273        Ok(data)
274    }
275}
276
277impl<T: WriteableNoOptions> VecWritable for Vec<T> {
278    fn write_vec<W: Write + Seek>(self, writer: &mut W) -> StreamResult<()> {
279        for (i, val) in self.into_iter().enumerate() {
280            val.write_no_opts(writer).add_context(|| {
281                format!("writing item {} of vec of type {}", i, type_name::<T>())
282            })?;
283        }
284
285        Ok(())
286    }
287}
288
289impl<T: ReadableNoOptions, const N: usize> Readable for [T; N] {
290    type Args = ();
291    fn read<R: Read + Seek>(reader: &mut R, _args: Self::Args) -> StreamResult<Self> {
292        let mut data = Vec::with_capacity(N);
293        for i in 0..N {
294            let val = T::read_no_opts(reader).add_context(|| {
295                format!("reading element {i} of type [{}; {N}] ", type_name::<T>())
296            })?;
297
298            data.push(val);
299        }
300
301        Ok(data.try_into().unwrap_or_else(|_| unreachable!()))
302    }
303}
304
305impl<T: WriteableNoOptions, const N: usize> Writeable for [T; N] {
306    type Args = ();
307    fn write<W: Write + Seek>(self, writer: &mut W, _args: Self::Args) -> StreamResult<()> {
308        for (i, val) in self.into_iter().enumerate() {
309            val.write_no_opts(writer)
310                .add_context(|| format!("writing element {i} of [{}; {N}]", type_name::<T>()))?;
311        }
312
313        Ok(())
314    }
315}
316
317impl Readable for bool {
318    type Args = ();
319    fn read<R: Read + Seek>(reader: &mut R, _args: Self::Args) -> StreamResult<Self> {
320        let data: u8 = u8::read_no_opts(reader).add_context(|| "read u8 for bool")?;
321
322        Ok(data != 0)
323    }
324}
325
326impl Writeable for bool {
327    type Args = ();
328    fn write<W: Write + Seek>(self, writer: &mut W, _args: Self::Args) -> StreamResult<()> {
329        let data: u8 = match self {
330            true => 1,
331            false => 0,
332        };
333        data.write_no_opts(writer)
334            .add_context(|| "write u8 for bool")
335    }
336}