1use quoth::{
2 Parsable, ParsableExt, ParseStream, Span, Spanned,
3 parsable::{Exact, Nothing},
4};
5
6use crate::SafeInt;
7
8extern crate alloc;
9
10use alloc::vec::Vec;
11
12#[derive(Clone, Debug, PartialEq, Eq, Hash, ParsableExt)]
16pub struct ParsedSafeDec<const D: usize> {
17 pub raw: SafeInt,
19 pub decimals: usize,
21 pub span: Span,
23}
24
25impl<const D: usize> Spanned for ParsedSafeDec<D> {
26 fn span(&self) -> Span {
27 self.span.clone()
28 }
29}
30
31impl<const D: usize> Parsable for ParsedSafeDec<D> {
32 fn parse(stream: &mut ParseStream) -> quoth::Result<Self> {
33 let start_position = stream.position;
34 let is_neg = if stream.next_char()? == '-' {
35 stream.consume(1)?;
36 true
37 } else {
38 false
39 };
40 let mut major_digits = Vec::new();
41 major_digits.push(stream.parse_digit()?);
42 while let Ok(digit) = stream.parse_digit() {
43 major_digits.push(digit);
44 }
45 stream.parse_value(Exact::from("."))?;
46 let mut minor_digits = Vec::new();
47 minor_digits.push(stream.parse_digit()?);
48 while let Ok(digit) = stream.parse_digit() {
49 minor_digits.push(digit);
50 }
51 while minor_digits.len() < D {
52 minor_digits.push(0);
53 }
54 if minor_digits.len() > D {
55 return Err(quoth::Error::new(
56 stream.current_span(),
57 "unexpected extra digit",
58 ));
59 }
60
61 let num_minor_digits = minor_digits.len();
62
63 let mut digits = Vec::new();
64 digits.append(&mut major_digits);
65 digits.append(&mut minor_digits);
66 let mut raw = SafeInt::from(0);
67 for &d in &digits {
68 raw *= 10;
69 raw += d;
70 }
71 if is_neg {
72 raw = -raw;
73 }
74 stream.parse::<Nothing>()?;
75 Ok(ParsedSafeDec {
76 raw,
77 decimals: num_minor_digits,
78 span: Span::new(stream.source().clone(), start_position..stream.position),
79 })
80 }
81}
82
83#[derive(Clone, Debug, PartialEq, Eq, Hash, ParsableExt)]
87pub struct ParsedSafeInt {
88 pub value: SafeInt,
90 pub span: Span,
92}
93
94impl Spanned for ParsedSafeInt {
95 fn span(&self) -> Span {
96 self.span.clone()
97 }
98}
99
100impl Parsable for ParsedSafeInt {
101 fn parse(stream: &mut ParseStream) -> quoth::Result<Self> {
102 let start_position = stream.position;
103 let is_neg = if stream.next_char()? == '-' {
104 stream.consume(1)?;
105 true
106 } else {
107 false
108 };
109 let mut digits = Vec::new();
110 digits.push(stream.parse_digit()?);
111 while let Ok(digit) = stream.parse_digit() {
112 digits.push(digit);
113 }
114 let mut raw = SafeInt::from(0);
115 for &d in &digits {
116 raw *= 10;
117 raw += d;
118 }
119 if is_neg {
120 raw = -raw;
121 }
122 stream.parse::<Nothing>()?;
123 Ok(ParsedSafeInt {
124 value: raw,
125 span: Span::new(stream.source().clone(), start_position..stream.position),
126 })
127 }
128}
129
130#[test]
131fn test_parse_safe_dec_valid_same_digits() {
132 let mut stream = ParseStream::from("-3487834.885");
133 let parsed = stream.parse::<ParsedSafeDec<3>>().unwrap();
134 assert_eq!(parsed.raw, -3487834885i64);
135}
136
137#[test]
138fn test_parse_safe_dec_invalid_extra_char() {
139 let mut stream = ParseStream::from("-3487834.885a");
140 stream.parse::<ParsedSafeDec<3>>().unwrap_err();
141 let mut stream = ParseStream::from("-3487a834.885");
142 stream.parse::<ParsedSafeDec<3>>().unwrap_err();
143 let mut stream = ParseStream::from("-a3487834.885");
144 stream.parse::<ParsedSafeDec<3>>().unwrap_err();
145 let mut stream = ParseStream::from("a-3487834.885");
146 stream.parse::<ParsedSafeDec<3>>().unwrap_err();
147}
148
149#[test]
150fn test_parse_safe_dec_valid_less_digits_a() {
151 let mut stream = ParseStream::from("7488793498789.9");
152 let parsed = stream.parse::<ParsedSafeDec<7>>().unwrap();
153 assert_eq!(parsed.raw, 74887934987899000000u128);
154}
155
156#[test]
157fn test_parse_safe_dec_valid_less_digits_b() {
158 let mut stream = ParseStream::from("123.456");
159 let parsed = stream.parse::<ParsedSafeDec<6>>().unwrap();
160 assert_eq!(parsed.raw, 123456000);
161}
162
163#[test]
164fn test_parse_safe_dec_invalid_more_digits() {
165 let mut stream = ParseStream::from("7488793498789.00487347878");
166 stream.parse::<ParsedSafeDec<3>>().unwrap_err();
167}
168
169#[test]
170fn test_parse_safe_dec_invalid_no_dot() {
171 let mut stream = ParseStream::from("748879349878900487347878");
172 stream.parse::<ParsedSafeDec<44>>().unwrap_err();
173}
174
175#[test]
176fn test_parse_safe_dec_invalid_no_minor_digits() {
177 let mut stream = ParseStream::from("7488793498789.");
178 stream.parse::<ParsedSafeDec<3>>().unwrap_err();
179 let mut stream = ParseStream::from("7488793498789.");
180 stream.parse::<ParsedSafeDec<0>>().unwrap_err();
181}
182
183#[test]
184fn test_parse_safe_int_valid_positive() {
185 assert_eq!(
186 ParseStream::from("123456")
187 .parse::<ParsedSafeInt>()
188 .unwrap()
189 .value,
190 123456
191 );
192 assert_eq!(
193 *ParseStream::from(
194 "112233445566778829879879823749798798982893947293749823798729387293849234"
195 )
196 .parse::<ParsedSafeInt>()
197 .unwrap()
198 .value
199 .raw(),
200 "112233445566778829879879823749798798982893947293749823798729387293849234"
201 .parse::<num_bigint::BigInt>()
202 .unwrap()
203 );
204 assert_eq!(
205 ParseStream::from("0")
206 .parse::<ParsedSafeInt>()
207 .unwrap()
208 .value,
209 0
210 );
211}
212
213#[test]
214fn test_parse_safe_int_valid_negative() {
215 assert_eq!(
216 ParseStream::from("-0")
217 .parse::<ParsedSafeInt>()
218 .unwrap()
219 .value,
220 0
221 );
222 assert_eq!(
223 ParseStream::from("-1")
224 .parse::<ParsedSafeInt>()
225 .unwrap()
226 .value,
227 -1
228 );
229 assert_eq!(
230 ParseStream::from("-98439874987948333035")
231 .parse::<ParsedSafeInt>()
232 .unwrap()
233 .value,
234 -98439874987948333035i128
235 );
236}
237
238#[test]
239fn test_parse_safe_int_invalid_decimal() {
240 ParseStream::from("123.456")
241 .parse::<ParsedSafeInt>()
242 .unwrap_err();
243}
244
245#[test]
246fn test_parse_safe_int_invalid_non_alpha() {
247 ParseStream::from("123a456")
248 .parse::<ParsedSafeInt>()
249 .unwrap_err();
250}