xsd_types/lexical/
float.rs1use super::{lexical_form, Decimal, Integer, NonNegativeInteger, NonPositiveInteger, Overflow};
2use std::borrow::{Borrow, ToOwned};
3use std::fmt;
4use std::hash::Hash;
5
6lexical_form! {
7 ty: Float,
11
12 buffer: FloatBuf,
16
17 new,
22
23 new_unchecked,
29
30 value: crate::Float,
31 error: InvalidFloat,
32 as_ref: as_float,
33 parent_forms: {}
34}
35
36pub const NAN: &Float = unsafe { Float::new_unchecked_from_slice(b"NaN") };
37pub const POSITIVE_INFINITY: &Float = unsafe { Float::new_unchecked_from_slice(b"INF") };
38pub const NEGATIVE_INFINITY: &Float = unsafe { Float::new_unchecked_from_slice(b"-INF") };
39
40impl Float {
41 pub fn is_infinite(&self) -> bool {
42 matches!(&self.0, b"INF" | b"-INF")
43 }
44
45 pub fn is_finite(&self) -> bool {
46 !matches!(&self.0, b"INF" | b"-INF" | b"NaN")
47 }
48
49 pub fn is_nan(&self) -> bool {
50 &self.0 == b"NaN"
51 }
52
53 fn exponent_separator_index(&self) -> Option<usize> {
54 for (i, c) in self.0.iter().enumerate() {
55 if matches!(c, b'e' | b'E') {
56 return Some(i);
57 }
58 }
59
60 None
61 }
62
63 pub fn mantissa(&self) -> Option<&Decimal> {
64 if self.is_finite() {
65 Some(match self.exponent_separator_index() {
66 Some(e) => unsafe { Decimal::new_unchecked(&self[..e]) },
67 None => unsafe { Decimal::new_unchecked(self) },
68 })
69 } else {
70 None
71 }
72 }
73
74 pub fn exponent(&self) -> Option<&Integer> {
75 if self.is_finite() {
76 self.exponent_separator_index()
77 .map(|e| unsafe { Integer::new_unchecked(&self[(e + 1)..]) })
78 } else {
79 None
80 }
81 }
82
83 pub fn value(&self) -> crate::Float {
84 self.into()
85 }
86}
87
88impl PartialEq for Float {
89 fn eq(&self, other: &Self) -> bool {
90 self.as_bytes() == other.as_bytes()
91 }
92}
93
94impl Eq for Float {}
95
96impl Hash for Float {
97 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
98 self.as_bytes().hash(state)
99 }
100}
101
102macro_rules! integer_conversion {
103 { $($ty:ty),* } => {
104 $(
105 impl From<$ty> for FloatBuf {
106 fn from(i: $ty) -> Self {
107 unsafe { FloatBuf::new_unchecked(i.to_string()) }
108 }
109 }
110
111 impl<'a> TryFrom<&'a Float> for $ty {
112 type Error = Overflow;
113
114 fn try_from(i: &'a Float) -> Result<Self, Overflow> {
115 i.as_str().parse().map_err(|_| Overflow)
116 }
117 }
118
119 impl TryFrom<FloatBuf> for $ty {
120 type Error = Overflow;
121
122 fn try_from(i: FloatBuf) -> Result<Self, Overflow> {
123 i.as_str().parse().map_err(|_| Overflow)
124 }
125 }
126 )*
127 };
128}
129
130integer_conversion! {
131 u8,
132 i8,
133 u16,
134 i16,
135 u32,
136 i32,
137 u64,
138 i64,
139 usize,
140 isize
141}
142
143const DTOA_CONFIG: pretty_dtoa::FmtFloatConfig = pretty_dtoa::FmtFloatConfig::default();
144
145impl From<f32> for FloatBuf {
146 fn from(i: f32) -> Self {
147 if i.is_finite() {
148 unsafe { FloatBuf::new_unchecked(pretty_dtoa::ftoa(i, DTOA_CONFIG)) }
149 } else if i.is_nan() {
150 FloatBuf::nan()
151 } else if i.is_sign_positive() {
152 FloatBuf::positive_infinity()
153 } else {
154 FloatBuf::negative_infinity()
155 }
156 }
157}
158
159impl<'a> From<&'a Float> for f32 {
160 fn from(i: &'a Float) -> Self {
161 i.as_str().parse().unwrap()
162 }
163}
164
165impl From<FloatBuf> for f32 {
166 fn from(i: FloatBuf) -> Self {
167 i.as_str().parse().unwrap()
168 }
169}
170
171impl From<f64> for FloatBuf {
172 fn from(i: f64) -> Self {
173 if i.is_finite() {
174 unsafe { FloatBuf::new_unchecked(pretty_dtoa::dtoa(i, DTOA_CONFIG)) }
175 } else if i.is_nan() {
176 FloatBuf::nan()
177 } else if i.is_sign_positive() {
178 FloatBuf::positive_infinity()
179 } else {
180 FloatBuf::negative_infinity()
181 }
182 }
183}
184
185impl<'a> From<&'a Integer> for &'a Float {
186 #[inline(always)]
187 fn from(d: &'a Integer) -> Self {
188 unsafe { Float::new_unchecked(d) }
189 }
190}
191
192impl<'a> From<&'a NonNegativeInteger> for &'a Float {
193 #[inline(always)]
194 fn from(d: &'a NonNegativeInteger) -> Self {
195 unsafe { Float::new_unchecked(d) }
196 }
197}
198
199impl<'a> From<&'a NonPositiveInteger> for &'a Float {
200 #[inline(always)]
201 fn from(d: &'a NonPositiveInteger) -> Self {
202 unsafe { Float::new_unchecked(d) }
203 }
204}
205
206impl FloatBuf {
207 #[inline(always)]
208 pub fn nan() -> Self {
209 NAN.to_owned()
210 }
211
212 #[inline(always)]
213 pub fn positive_infinity() -> Self {
214 POSITIVE_INFINITY.to_owned()
215 }
216
217 #[inline(always)]
218 pub fn negative_infinity() -> Self {
219 NEGATIVE_INFINITY.to_owned()
220 }
221}
222
223fn check_bytes(s: &[u8]) -> bool {
224 s == b"INF" || s == b"-INF" || s == b"NaN" || check_normal(s.iter().cloned())
225}
226
227fn check_normal<C: Iterator<Item = u8>>(mut chars: C) -> bool {
228 enum State {
229 Initial,
230 NonEmptyInteger,
231 Integer,
232 NonEmptyDecimal,
233 Decimal,
234 ExponentSign,
235 NonEmptyExponent,
236 Exponent,
237 }
238
239 let mut state = State::Initial;
240
241 loop {
242 state = match state {
243 State::Initial => match chars.next() {
244 Some(b'+') => State::NonEmptyInteger,
245 Some(b'-') => State::NonEmptyInteger,
246 Some(b'.') => State::NonEmptyDecimal,
247 Some(b'0'..=b'9') => State::Integer,
248 _ => break false,
249 },
250 State::NonEmptyInteger => match chars.next() {
251 Some(b'0'..=b'9') => State::Integer,
252 Some(b'.') => State::Decimal,
253 _ => break false,
254 },
255 State::Integer => match chars.next() {
256 Some(b'0'..=b'9') => State::Integer,
257 Some(b'.') => State::Decimal,
258 Some(b'e' | b'E') => State::ExponentSign,
259 Some(_) => break false,
260 None => break true,
261 },
262 State::NonEmptyDecimal => match chars.next() {
263 Some(b'0'..=b'9') => State::Decimal,
264 _ => break false,
265 },
266 State::Decimal => match chars.next() {
267 Some(b'0'..=b'9') => State::Decimal,
268 Some(b'e' | b'E') => State::ExponentSign,
269 Some(_) => break false,
270 None => break true,
271 },
272 State::ExponentSign => match chars.next() {
273 Some(b'+' | b'-') => State::NonEmptyExponent,
274 Some(b'0'..=b'9') => State::Exponent,
275 _ => break false,
276 },
277 State::NonEmptyExponent => match chars.next() {
278 Some(b'0'..=b'9') => State::Exponent,
279 _ => break false,
280 },
281 State::Exponent => match chars.next() {
282 Some(b'0'..=b'9') => State::Exponent,
283 Some(_) => break false,
284 None => break true,
285 },
286 }
287 }
288}
289
290#[cfg(test)]
291mod tests {
292 use super::*;
293
294 #[test]
295 fn parse_01() {
296 Float::new("0").unwrap();
297 }
298
299 #[test]
300 #[should_panic]
301 fn parse_02() {
302 Float::new("+").unwrap();
303 }
304
305 #[test]
306 #[should_panic]
307 fn parse_03() {
308 Float::new("-").unwrap();
309 }
310
311 #[test]
312 #[should_panic]
313 fn parse_04() {
314 Float::new("012+").unwrap();
315 }
316
317 #[test]
318 fn parse_05() {
319 Float::new("+42").unwrap();
320 }
321
322 #[test]
323 fn parse_06() {
324 Float::new("-42").unwrap();
325 }
326
327 #[test]
328 #[should_panic]
329 fn parse_07() {
330 Float::new(".").unwrap();
331 }
332
333 #[test]
334 fn parse_08() {
335 Float::new(".0").unwrap();
336 }
337
338 #[test]
339 fn parse_09() {
340 Float::new("0.").unwrap();
341 }
342
343 #[test]
344 fn parse_10() {
345 Float::new("42.0").unwrap();
346 }
347
348 #[test]
349 fn parse_11() {
350 Float::new("INF").unwrap();
351 }
352
353 #[test]
354 fn parse_12() {
355 Float::new("-INF").unwrap();
356 }
357
358 #[test]
359 fn parse_13() {
360 Float::new("NaN").unwrap();
361 }
362
363 #[test]
364 fn parse_14() {
365 Float::new(".0e1").unwrap();
366 }
367
368 #[test]
369 fn parse_15() {
370 Float::new("0.e1").unwrap();
371 }
372
373 #[test]
374 fn parse_16() {
375 Float::new("42E10").unwrap();
376 }
377
378 #[test]
379 fn parse_17() {
380 Float::new("-42E+10").unwrap();
381 }
382
383 #[test]
384 fn parse_18() {
385 Float::new("-42E-10").unwrap();
386 }
387
388 #[test]
389 #[should_panic]
390 fn parse_19() {
391 Float::new("+42E-10e").unwrap();
392 }
393
394 #[test]
395 fn parse_20() {
396 Float::new("+42E-10").unwrap();
397 }
398
399 #[test]
400 fn parse_21() {
401 let d = Float::new("+01234E-56789").unwrap();
402 assert_eq!(d.mantissa(), Some(Decimal::new("+01234").unwrap()));
403 assert_eq!(d.exponent(), Some(Integer::new("-56789").unwrap()));
404 }
405
406 #[test]
407 fn parse_22() {
408 let a = FloatBuf::new("+01234E-56789".to_string()).unwrap();
409 let b = Float::new("+01234E-56789").unwrap();
410 assert_eq!(a, b)
411 }
412
413 #[test]
414 fn format_01() {
415 assert_eq!(FloatBuf::from(1.0e10f32).to_string(), "1.0e10")
416 }
417}