1#![deny(missing_docs)]
2
3use thiserror::Error;
9
10pub trait Context {
15 #[cfg(feature = "radix-parsing")]
16 #[inline]
17 fn radix(&self) -> u32 {
19 10
20 }
21}
22
23impl Context for () {}
24
25#[derive(Debug, Error)]
27pub enum Error {
28 #[error("Not enough elements: {0} more expected")]
30 NotEnoughElements(usize),
31
32 #[error("Too many elements: {0} less expected")]
34 TooManyElements(usize),
35
36 #[error("List not allowed")]
38 ListNotAllowed,
39
40 #[error("Symbol not allowed")]
42 SymbolNotAllowed,
43
44 #[error("String parsing error")]
46 StringParsing,
47
48 #[error("Invalid element")]
50 InvalidElement,
51}
52
53pub type Result<T> = std::result::Result<T, Error>;
55
56pub enum Unit {
58 Symbol(Box<str>),
60 Parser(Parser),
62}
63
64impl Unit {
65 pub fn symbol(self) -> Result<Box<str>> {
67 use Unit::*;
68 match self {
69 Symbol(name) => Ok(name),
70 Parser(_) => Err(Error::ListNotAllowed),
71 }
72 }
73
74 pub fn parser(self) -> Result<Parser> {
76 use Unit::*;
77 match self {
78 Symbol(_) => Err(Error::SymbolNotAllowed),
79 Parser(parser) => Ok(parser),
80 }
81 }
82}
83
84pub trait Parsable<C: Context>: Sized {
86 fn parse_symbol(_name: Box<str>, _context: &C) -> Result<Self> {
88 Err(Error::SymbolNotAllowed)
89 }
90
91 fn parse_list(_parser: &mut Parser, _context: &C) -> Result<Self> {
93 Err(Error::ListNotAllowed)
94 }
95}
96
97fn parse<C: Context, P: Parsable<C>>(unit: Unit, context: &C) -> Result<P> {
98 use Unit::*;
99 match unit {
100 Symbol(name) => Parsable::parse_symbol(name, context),
101 Parser(mut parser) => parser.parse_rest(context),
102 }
103}
104
105impl<C: Context, T: Parsable<C>> Parsable<C> for Box<T> {
106 fn parse_symbol(name: Box<str>, context: &C) -> Result<Self> {
107 Ok(Self::new(Parsable::parse_symbol(name, context)?))
108 }
109
110 fn parse_list(parser: &mut Parser, context: &C) -> Result<Self> {
111 Ok(Self::new(parser.parse_list(context)?))
112 }
113}
114
115impl<C: Context, T: Parsable<C>> Parsable<C> for Vec<T> {
116 fn parse_list(parser: &mut Parser, context: &C) -> Result<Self> {
117 let Parser { form, count } = parser;
118 form.drain(..)
119 .rev()
120 .map(|unit| {
121 *count += 1;
122 parse(unit, context)
123 })
124 .collect()
125 }
126}
127
128impl<C: Context> Parsable<C> for String {
129 fn parse_symbol(name: Box<str>, _context: &C) -> Result<Self> {
130 Ok(name.into())
131 }
132}
133
134impl<C: Context> Parsable<C> for Box<str> {
135 fn parse_symbol(name: Box<str>, _context: &C) -> Result<Self> {
136 Ok(name)
137 }
138}
139
140#[macro_export]
141macro_rules! derive_symbol_parsable {
143 ($t:ty) => {
144 impl<C: $crate::Context> $crate::Parsable<C> for $t {
145 fn parse_symbol(name: Box<str>, _context: &C) -> $crate::Result<Self> {
146 if let Ok(value) = name.parse() {
147 Ok(value)
148 } else {
149 Err($crate::Error::StringParsing)
150 }
151 }
152 }
153 };
154 ($t:ty, $($rest:ty),+) => {
155 derive_symbol_parsable!($t);
156 derive_symbol_parsable!($($rest),+);
157 };
158}
159
160#[cfg(not(feature = "radix-parsing"))]
161mod numbers;
162derive_symbol_parsable!(bool);
163
164pub struct Parser {
166 form: Vec<Unit>,
167 count: usize,
168}
169
170impl Parser {
171 pub fn new<I: IntoIterator>(form: I) -> Self
173 where
174 I::Item: Into<Unit>,
175 {
176 let mut form: Vec<_> = form.into_iter().map(I::Item::into).collect();
177 form.reverse();
178 Self { form, count: 0 }
179 }
180
181 pub fn parse_next<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
183 self.count += 1;
184 if let Some(token) = self.form.pop() {
185 parse(token, context)
186 } else {
187 Result::Err(Error::NotEnoughElements(self.count))
188 }
189 }
190
191 pub fn parse_rest<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
194 let result = self.parse_list(context);
195 let count = self.form.len();
196 if count > 0 {
197 self.form.clear();
198 Err(Error::TooManyElements(count))
199 } else {
200 result
201 }
202 }
203
204 pub fn parse_list<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
206 Parsable::parse_list(self, context)
207 }
208}
209
210impl Iterator for Parser {
211 type Item = Result<Self>;
212
213 fn next(&mut self) -> Option<Result<Self>> {
214 self.count += 1;
215 Some(self.form.pop()?.parser())
216 }
217}
218
219#[cfg(feature = "radix-parsing")]
220pub mod radix;