1use crate::parse::error::{
2 throw_err,
3 ParseError,
4 ParseErrorKind,
5};
6
7use crate::parse::span::Span;
8
9use multibase::Base;
10
11use nom::{
12 branch::alt,
13 bytes::complete::{
14 tag,
15 take_till,
16 take_till1,
17 },
18 character::complete::satisfy,
19 combinator::value,
20 error::context,
21 IResult,
22 InputTakeAtPosition,
23};
24
25use sp_std::{
26 borrow::ToOwned,
27 boxed::Box,
28 vec::Vec,
29};
30
31use alloc::string::String;
32
33#[derive(PartialEq, Eq, Clone, Copy, Debug)]
34pub enum LitBase {
35 Bin,
36 Oct,
37 Dec,
38 Hex,
39}
40
41impl Default for LitBase {
42 fn default() -> Self { Self::Hex }
43}
44
45impl LitBase {
46 pub fn parse_code(i: Span) -> IResult<Span, Self, ParseError<Span>> {
47 alt((
48 value(Self::Bin, tag("b")),
49 value(Self::Oct, tag("o")),
50 value(Self::Dec, tag("d")),
51 value(Self::Hex, tag("x")),
52 ))(i)
53 }
54
55 pub fn code(&self) -> char {
57 match self {
58 Self::Bin => 'b',
59 Self::Oct => 'o',
60 Self::Dec => 'd',
61 Self::Hex => 'x',
62 }
63 }
64
65 pub fn base_digits(&self) -> &str {
66 match self {
67 Self::Bin => "01",
68 Self::Oct => "01234567",
69 Self::Dec => "0123456789",
70 Self::Hex => "0123456789abcdef",
71 }
72 }
73
74 pub fn radix(&self) -> u32 {
75 match self {
76 Self::Bin => 2,
77 Self::Oct => 8,
78 Self::Dec => 10,
79 Self::Hex => 16,
80 }
81 }
82
83 pub fn is_digit(&self, x: char) -> bool {
84 self.base_digits().chars().any(|y| x == y)
85 }
86
87 pub fn encode<I: AsRef<[u8]>>(&self, input: I) -> String {
88 base_x::encode(self.base_digits(), input.as_ref())
89 }
90
91 pub fn decode<'a>(
92 &self,
93 input: Span<'a>,
94 ) -> IResult<Span<'a>, Vec<u8>, ParseError<Span<'a>>> {
95 let (i, o) = input.split_at_position_complete(|x| !self.is_digit(x))?;
96 match base_x::decode(self.base_digits(), o.fragment()) {
97 Ok(bytes) => Ok((i, bytes)),
98 Err(_) => Err(nom::Err::Error(ParseError::new(
99 i,
100 ParseErrorKind::InvalidBaseEncoding(*self),
101 ))),
102 }
103 }
104
105 pub fn decode1<'a>(
106 &self,
107 input: Span<'a>,
108 ) -> IResult<Span<'a>, Vec<u8>, ParseError<Span<'a>>> {
109 let (i, o) = input.split_at_position1_complete(
110 |x| !self.is_digit(x),
111 nom::error::ErrorKind::Digit,
112 )?;
113 match base_x::decode(self.base_digits(), o.fragment()) {
114 Ok(bytes) => Ok((i, bytes)),
115 Err(_) => Err(nom::Err::Error(ParseError::new(
116 i,
117 ParseErrorKind::InvalidBaseEncoding(*self),
118 ))),
119 }
120 }
121}
122
123pub fn parse_bin_digits()
124-> impl Fn(Span) -> IResult<Span, String, ParseError<Span>> {
125 move |from: Span| {
126 let (i, d) =
127 context("binary digit", satisfy(|x| LitBase::Bin.is_digit(x)))(from)?;
128 let (i, ds) = context(
129 "binary digits",
130 take_till(|x| !(LitBase::Bin.is_digit(x) || x == '_')),
131 )(i)?;
132 let ds: String = sp_std::iter::once(d)
133 .chain((*ds.fragment()).to_owned().chars())
134 .filter(|x| *x != '_')
135 .collect();
136 Ok((i, ds))
137 }
138}
139
140pub fn parse_oct_digits()
141-> impl Fn(Span) -> IResult<Span, String, ParseError<Span>> {
142 move |from: Span| {
143 let (i, d) =
144 context("octal digit", satisfy(|x| LitBase::Oct.is_digit(x)))(from)?;
145 let (i, ds) = context(
146 "octal digits",
147 take_till(|x| !(LitBase::Oct.is_digit(x) || x == '_')),
148 )(i)?;
149 let ds: String = sp_std::iter::once(d)
150 .chain((*ds.fragment()).to_owned().chars())
151 .filter(|x| *x != '_')
152 .collect();
153 Ok((i, ds))
154 }
155}
156
157pub fn parse_dec_digits()
158-> impl Fn(Span) -> IResult<Span, String, ParseError<Span>> {
159 move |from: Span| {
160 let (i, d) =
161 context("decimal digit", satisfy(|x| LitBase::Dec.is_digit(x)))(from)?;
162 let (i, ds) = context(
163 "decimal digits",
164 take_till(|x| !(LitBase::Dec.is_digit(x) || x == '_')),
165 )(i)?;
166 let ds: String = sp_std::iter::once(d)
167 .chain((*ds.fragment()).to_owned().chars())
168 .filter(|x| *x != '_')
169 .collect();
170 Ok((i, ds))
171 }
172}
173
174pub fn parse_hex_digits()
175-> impl Fn(Span) -> IResult<Span, String, ParseError<Span>> {
176 move |from: Span| {
177 let (i, d) = context(
178 "hexadecimal digit",
179 satisfy(|x| LitBase::Hex.is_digit(x)),
180 )(from)?;
181 let (i, ds) = context(
182 "hexadecimal digits",
183 take_till(|x| !(LitBase::Hex.is_digit(x) || x == '_')),
184 )(i)?;
185 let ds: String = sp_std::iter::once(d)
186 .chain((*ds.fragment()).to_owned().chars())
187 .filter(|x| *x != '_')
188 .collect();
189 Ok((i, ds))
190 }
191}
192
193pub fn parse_litbase_code()
194-> impl Fn(Span) -> IResult<Span, LitBase, ParseError<Span>> {
195 move |from: Span| {
196 throw_err(
197 alt((
198 value(LitBase::Bin, tag("b")),
199 value(LitBase::Oct, tag("o")),
200 value(LitBase::Dec, tag("d")),
201 value(LitBase::Hex, tag("x")),
202 ))(from),
203 |_| ParseError::new(from, ParseErrorKind::UnknownBaseCode),
204 )
205 }
206}
207pub fn parse_litbase_bits_code()
208-> impl Fn(Span) -> IResult<Span, LitBase, ParseError<Span>> {
209 move |from: Span| {
210 throw_err(
211 alt((value(LitBase::Bin, tag("b")), value(LitBase::Hex, tag("x"))))(from),
212 |_| ParseError::new(from, ParseErrorKind::UnknownBaseCode),
213 )
214 }
215}
216
217pub fn parse_litbase_digits(
218 base: LitBase,
219) -> Box<dyn Fn(Span) -> IResult<Span, String, ParseError<Span>>> {
220 Box::new(move |from: Span| match base {
221 LitBase::Bin => parse_bin_digits()(from),
222 LitBase::Oct => parse_oct_digits()(from),
223 LitBase::Dec => parse_dec_digits()(from),
224 LitBase::Hex => parse_hex_digits()(from),
225 })
226}
227
228pub fn parse_litbase_bytes(
229 base: LitBase,
230) -> impl Fn(Span) -> IResult<Span, Vec<u8>, ParseError<Span>> {
231 move |from: Span| {
232 let (i, o) = parse_litbase_digits(base)(from)?;
233 match base_x::decode(base.base_digits(), &o) {
234 Ok(bytes) => Ok((i, bytes)),
235 Err(_) => Err(nom::Err::Error(ParseError::new(
236 i,
237 ParseErrorKind::InvalidBaseEncoding(base),
238 ))),
239 }
240 }
241}
242
243pub const MULTIBASE_DIGITS: &str =
244 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/-_";
245
246pub fn is_multibase_digit(x: char) -> bool {
247 MULTIBASE_DIGITS.chars().any(|y| x == y)
248}
249
250pub fn parse_multibase_digits()
251-> impl Fn(Span) -> IResult<Span, Span, ParseError<Span>> {
252 move |from: Span| {
253 context("multibase digits", take_till1(|x| !is_multibase_digit(x)))(from)
254 }
255}
256
257pub fn parse_multibase()
258-> impl Fn(Span) -> IResult<Span, (Base, Vec<u8>), ParseError<Span>> {
259 move |from: Span| {
260 let (i, o) = parse_multibase_digits()(from)?;
261 match multibase::decode(o.fragment()) {
262 Ok((base, bytes)) => Ok((i, (base, bytes))),
263 Err(e) => Err(nom::Err::Error(ParseError::new(
264 i,
265 ParseErrorKind::MultibaseError(e),
266 ))),
267 }
268 }
269}