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 let result = form
119 .drain(..)
120 .rev()
121 .map(|unit| {
122 *count += 1;
123 parse(unit, context)
124 })
125 .collect();
126 result
127 }
128}
129
130impl<C: Context> Parsable<C> for String {
131 fn parse_symbol(name: Box<str>, _context: &C) -> Result<Self> {
132 Ok(name.into())
133 }
134}
135
136impl<C: Context> Parsable<C> for Box<str> {
137 fn parse_symbol(name: Box<str>, _context: &C) -> Result<Self> {
138 Ok(name)
139 }
140}
141
142#[macro_export]
143macro_rules! derive_symbol_parsable {
145 ($t:ty) => {
146 impl<C: $crate::Context> $crate::Parsable<C> for $t {
147 fn parse_symbol(name: Box<str>, _context: &C) -> $crate::Result<Self> {
148 if let Ok(value) = name.parse() {
149 Ok(value)
150 } else {
151 Err($crate::Error::StringParsing)
152 }
153 }
154 }
155 };
156 ($t:ty, $($rest:ty),+) => {
157 derive_symbol_parsable!($t);
158 derive_symbol_parsable!($($rest),+);
159 };
160}
161
162#[cfg(not(feature = "radix-parsing"))]
163mod numbers;
164derive_symbol_parsable!(bool);
165
166pub struct Parser {
168 form: Vec<Unit>,
169 count: usize,
170}
171
172impl Parser {
173 pub fn new<I: IntoIterator>(form: I) -> Self
175 where
176 I::Item: Into<Unit>,
177 {
178 let mut form: Vec<_> = form.into_iter().map(I::Item::into).collect();
179 form.reverse();
180 Self { form, count: 0 }
181 }
182
183 pub fn parse_next<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
185 self.count += 1;
186 if let Some(token) = self.form.pop() {
187 parse(token, context)
188 } else {
189 Result::Err(Error::NotEnoughElements(self.count))
190 }
191 }
192
193 pub fn parse_rest<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
196 let result = self.parse_list(context);
197 let count = self.form.len();
198 if count > 0 {
199 self.form.clear();
200 Err(Error::TooManyElements(count))
201 } else {
202 result
203 }
204 }
205
206 pub fn parse_list<C: Context, T: Parsable<C>>(&mut self, context: &C) -> Result<T> {
208 Parsable::parse_list(self, context)
209 }
210}
211
212impl Iterator for Parser {
213 type Item = Result<Self>;
214
215 fn next(&mut self) -> Option<Result<Self>> {
216 self.count += 1;
217 Some(self.form.pop()?.parser())
218 }
219}
220
221#[cfg(feature = "radix-parsing")]
222pub mod radix;