wasm_reader_traits/
lib.rs

1#![cfg_attr(feature = "nightly", feature(specialization))]
2
3mod iter;
4mod reader;
5
6pub use frunk_core::hlist;
7pub use iter::{IntoParserIter, ParserIter};
8pub use reader::{Reader, ReaderBuild, ReaderBuildIter, ReaderRead};
9
10use std::{
11    fmt,
12    io::{self, Read, Seek},
13};
14
15#[derive(Debug, PartialEq, Eq)]
16pub enum Error<E> {
17    Error { error: E, offset: Option<u64> },
18    Eof,
19}
20
21impl<E: fmt::Display> fmt::Display for Error<E> {
22    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23        match self {
24            Error::Error { error, offset } => {
25                if let Some(o) = offset {
26                    write!(f, "@{}: {}", o, error)
27                } else {
28                    write!(f, "@???: {}", error)
29                }
30            }
31            Error::Eof => write!(f, "@eof"),
32        }
33    }
34}
35
36impl<E> Error<E> {
37    pub fn new<I: Into<E>>(error: I, offset: Option<u64>) -> Self {
38        Error::Error {
39            error: error.into(),
40            offset,
41        }
42    }
43}
44
45/// Helper trait to allow users to _possibly_ get a location in the stream, where
46/// types that cannot report this information fall back to reporting `None`.
47pub trait MaybePosition {
48    fn position(&mut self) -> Option<u64>;
49}
50
51#[cfg(feature = "nightly")]
52impl<T> MaybePosition for T {
53    default fn position(&mut self) -> Option<u64> {
54        None
55    }
56}
57
58impl<T: Seek> MaybePosition for T {
59    fn position(&mut self) -> Option<u64> {
60        self.seek(std::io::SeekFrom::Current(0)).ok()
61    }
62}
63
64pub type ParseResult<T, N, E> = Result<(T, N), E>;
65
66pub struct JustResult<T, E> {
67    inner: Result<T, E>,
68}
69
70impl<T, E> JustResult<T, E> {
71    pub fn new(inner: Result<T, E>) -> Self {
72        JustResult { inner }
73    }
74}
75
76impl<T, E> Parser for JustResult<T, E> {
77    type Item = T;
78    type Next = ();
79    type Error = Error<E>;
80
81    fn next<R: Read>(self, _reader: &mut R) -> ParseResult<Self::Item, Self::Next, Self::Error> {
82        #[cfg(feature = "nightly")]
83        {
84            self.inner
85                .map(|v| (v, ()))
86                .map_err(|e| Error::new(e, _reader.position()))
87        }
88        #[cfg(not(feature = "nightly"))]
89        {
90            self.inner.map(|v| (v, ())).map_err(|e| Error::new(e, None))
91        }
92    }
93}
94
95pub trait ParseOne: Parser<Next = ()> {
96    fn parse<R: Read>(self, reader: &mut R) -> Result<Self::Item, Self::Error>;
97}
98
99impl<T> ParseOne for T
100where
101    T: Parser<Next = ()>,
102{
103    fn parse<R: Read>(self, reader: &mut R) -> Result<Self::Item, Self::Error> {
104        Parser::next(self, reader).map(|(v, ())| v)
105    }
106}
107
108pub trait IntoParser {
109    type Item;
110    type Next;
111    type Error;
112    type Parser: Parser<Item = Self::Item, Next = Self::Next, Error = Self::Error>;
113
114    fn into(self) -> Self::Parser;
115}
116
117impl<T> IntoParser for T
118where
119    T: Parser,
120{
121    type Item = <Self as Parser>::Item;
122    type Next = <Self as Parser>::Next;
123    type Error = <Self as Parser>::Error;
124    type Parser = Self;
125
126    fn into(self) -> Self::Parser {
127        self
128    }
129}
130
131impl<T, E> IntoParser for Result<T, E> {
132    type Item = T;
133    type Next = ();
134    type Error = Error<E>;
135    type Parser = JustResult<T, E>;
136
137    fn into(self) -> Self::Parser {
138        JustResult { inner: self }
139    }
140}
141
142pub trait Parser {
143    type Item;
144    type Next;
145    type Error;
146
147    fn next<R: Read>(self, reader: &mut R) -> ParseResult<Self::Item, Self::Next, Self::Error>;
148}
149
150macro_rules! tuple_parser {
151    () => {};
152    ($first:ident $(, $rest:ident)*) => {
153        #[allow(unused_parens)]
154        impl<$first, $($rest,)*> Parser for ((), $first, $($rest,)*)
155        where
156            ($first $(, $rest)*): Parser
157        {
158            type Item = <($first $(, $rest)*) as Parser>::Item;
159            type Next = <($first $(, $rest)*) as Parser>::Next;
160            type Error = <($first $(, $rest)*) as Parser>::Error;
161
162            #[allow(non_snake_case)]
163            fn next<R: Read>(self, reader: &mut R) -> ParseResult<Self::Item, Self::Next, Self::Error> {
164                let ((), $first, $($rest,)*) = self;
165                ($first $(, $rest)*).next(reader)
166            }
167        }
168
169        impl<$first: Parser, $($rest: Parser<Error = $first::Error>,)*> Parser for ($first, $($rest,)*) {
170            type Item = $first::Item;
171            type Next = ($first::Next, $($rest,)*);
172            type Error = $first::Error;
173
174            #[allow(non_snake_case)]
175            fn next<R: Read>(self, reader: &mut R) -> ParseResult<Self::Item, Self::Next, Self::Error> {
176                let ($first, $($rest,)*) = self;
177                $first.next(reader).map(move |(i, n)| (i, (n, $($rest,)*)))
178            }
179        }
180
181        tuple_parser!($($rest),*);
182    }
183}
184
185tuple_parser!(A, B, C, D, E, F, G, H);
186
187pub trait CollectHelper<E> {
188    type Item;
189
190    fn collect<R: Read>(self, reader: &mut R) -> Result<Self::Item, E>;
191}
192
193impl<E> CollectHelper<E> for () {
194    type Item = ();
195
196    fn collect<R: Read>(self, _reader: &mut R) -> Result<Self::Item, E> {
197        Ok(())
198    }
199}
200
201fn make_eof_unexpected<T, E>(r: Result<T, Error<E>>, pos: Option<u64>) -> Result<T, Error<E>>
202where
203    E: From<io::Error>,
204{
205    match r {
206        Err(Error::Eof) => Err(Error::Error {
207            error: io::Error::from(io::ErrorKind::UnexpectedEof).into(),
208            offset: pos,
209        }),
210        other => other,
211    }
212}
213
214impl<P, E> CollectHelper<P::Error> for P
215where
216    P: Parser<Error = Error<E>>,
217    P::Next: CollectHelper<P::Error>,
218    E: From<io::Error>,
219{
220    type Item = (P::Item, <P::Next as CollectHelper<P::Error>>::Item);
221
222    fn collect<R: Read>(self, reader: &mut R) -> Result<Self::Item, P::Error> {
223        let (cur, next) = self.next(reader)?;
224
225        #[cfg(not(feature = "nightly"))]
226        let pos = None;
227        #[cfg(feature = "nightly")]
228        let pos = reader.position();
229
230        // We want to either consume the full reader or nothing at all, so we fail if we
231        // hit an EOF halfway through.
232        let rest = make_eof_unexpected(next.collect(reader), pos)?;
233
234        Ok((cur, rest))
235    }
236}