pint_abi/
decode.rs

1use crate::{
2    read::Read,
3    types::essential::{convert::bool_from_word, Word},
4};
5use core::fmt::{Debug, Display};
6use thiserror::Error;
7
8/// A trait for decoding types from Essential `Word`s in a manner compatible with Pint's ABI.
9pub trait Decode: Sized {
10    /// Any error that might occur during decoding.
11    type Error: Error;
12    /// Decode an instance of `Self` from words read from the given reader.
13    fn decode<R: Read>(r: &mut R) -> Result<Self, Self::Error>;
14}
15
16/// Requirements for the `Error` type in a `Decode` implementation.
17pub trait Error: Debug + Display {}
18
19/// Construct a decode `Error` from a `Read` implementation error.
20pub trait FromReadError {
21    /// Forward an error produced by the `Read`er.
22    fn from_read_error<E: Debug + Display>(err: E) -> Self;
23}
24
25/// An error occurring during decoding where the `Read` implementation fails to
26/// read enough words.
27#[derive(Debug, Error)]
28#[error("failed to read enough bytes: expected `{expected}`, found `{found}`")]
29pub struct NotEnoughWords {
30    /// The expected number of words.
31    pub expected: usize,
32    /// The actual number of words read.
33    pub found: usize,
34}
35
36/// The `Read` implementation error formatted into a `String` using the `Display` impl.
37#[derive(Debug, Error)]
38#[error("reader error: {0}")]
39pub struct ReadError(String);
40
41/// A general-use error for types with a known size in words.
42#[derive(Debug, Error)]
43pub enum SizedError {
44    /// The `Read` implementation returned an error.
45    #[error("{0}")]
46    Reader(#[from] ReadError),
47    /// Failed to read enough bytes from the reader.
48    #[error("{0}")]
49    NotEnoughWords(#[from] NotEnoughWords),
50}
51
52/// The read `Word` was invalid.
53#[derive(Debug, Error)]
54#[error("`bool` expected `0` or `1`, found `{0}`")]
55pub struct BoolInvalid(pub Word);
56
57/// An error occurring when decoding a `bool`.
58#[derive(Debug, Error)]
59pub enum BoolError {
60    /// Failed to read the word.
61    #[error("{0}")]
62    Sized(#[from] SizedError),
63    /// The read `Word` was invalid.
64    #[error("{0}")]
65    Invalid(#[from] BoolInvalid),
66}
67
68/// Failed to decode a pair in the form of a tuple.
69#[derive(Debug, Error)]
70pub enum PairError<A, B> {
71    #[error("{0}")]
72    Left(A),
73    #[error("{0}")]
74    Right(B),
75}
76
77impl<T: Debug + Display> Error for T {}
78
79impl FromReadError for ReadError {
80    fn from_read_error<E: Debug + Display>(err: E) -> Self {
81        ReadError(format!("{err}"))
82    }
83}
84
85impl FromReadError for SizedError {
86    fn from_read_error<E: Debug + Display>(err: E) -> Self {
87        Self::Reader(ReadError::from_read_error(err))
88    }
89}
90
91impl FromReadError for BoolError {
92    fn from_read_error<E: Debug + Display>(err: E) -> Self {
93        Self::Sized(SizedError::from_read_error(err))
94    }
95}
96
97impl Decode for Word {
98    type Error = SizedError;
99    fn decode<R: Read>(r: &mut R) -> Result<Self, Self::Error> {
100        let [w] = read_exact(r)?;
101        Ok(w)
102    }
103}
104
105impl Decode for bool {
106    type Error = BoolError;
107    fn decode<R: Read>(r: &mut R) -> Result<Self, Self::Error> {
108        let [w] = read_exact(r)?;
109        bool_from_word(w).ok_or(BoolInvalid(w)).map_err(From::from)
110    }
111}
112
113impl<T> Decode for Option<T>
114where
115    T: Decode,
116{
117    type Error = PairError<T::Error, SizedError>;
118
119    fn decode<R: Read>(r: &mut R) -> Result<Self, Self::Error> {
120        T::decode(r) // Decode the inner value of Option<T>
121            .map_err(PairError::Left)
122            .and_then(|val| {
123                read_exact(r) // Read the tag
124                    .map_err(PairError::Right)
125                    .map(|[tag]| if tag == 0 { None } else { Some(val) }) // Match the tag
126            })
127    }
128}
129
130impl<const N: usize, T> Decode for [T; N]
131where
132    T: Decode,
133{
134    type Error = T::Error;
135    fn decode<R: Read>(r: &mut R) -> Result<Self, Self::Error> {
136        // TODO: Use `core::array::try_from_fn` once stabilized rather than `Vec`.
137        let mut vec = Vec::with_capacity(N);
138        for _ in 0..N {
139            vec.push(T::decode(r)?);
140        }
141        let mut elems = vec.into_iter();
142        Ok(core::array::from_fn(|_| {
143            elems.next().expect("Vec gauranteed to have len `N`")
144        }))
145    }
146}
147
148/// A macro for implementing `Decode` for non-pair tuples.
149macro_rules! impl_decode_for_tuple {
150    (A, $($T:ident),+) => {
151        #[allow(unused_parens)]
152        impl<A: Decode, $($T: Decode),+> Decode for (A, $($T),+) {
153            type Error = PairError<A::Error, <($($T),+) as Decode>::Error>;
154            fn decode<R: Read>(r: &mut R) -> Result<Self, Self::Error> {
155                let a: A = <_>::decode(r).map_err(PairError::Left)?;
156                #[allow(non_snake_case)]
157                let ($($T),+): ($($T),+) = <_>::decode(r).map_err(PairError::Right)?;
158                Ok((a, $($T),+))
159            }
160        }
161    };
162}
163
164impl_decode_for_tuple!(A, B);
165impl_decode_for_tuple!(A, B, C);
166impl_decode_for_tuple!(A, B, C, D);
167impl_decode_for_tuple!(A, B, C, D, E);
168impl_decode_for_tuple!(A, B, C, D, E, F);
169impl_decode_for_tuple!(A, B, C, D, E, F, G);
170impl_decode_for_tuple!(A, B, C, D, E, F, G, H);
171impl_decode_for_tuple!(A, B, C, D, E, F, G, H, I);
172impl_decode_for_tuple!(A, B, C, D, E, F, G, H, I, J);
173impl_decode_for_tuple!(A, B, C, D, E, F, G, H, I, J, K);
174impl_decode_for_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
175
176fn read_exact<const N: usize, R: Read>(r: &mut R) -> Result<[Word; N], SizedError> {
177    let mut arr = [0; N];
178    let amt = r.read(&mut arr).map_err(SizedError::from_read_error)?;
179    if amt != N {
180        let err = NotEnoughWords {
181            expected: N,
182            found: amt,
183        };
184        return Err(err.into());
185    }
186    Ok(arr)
187}