somen_language/numeric/
float.rs1use somen::prelude::*;
3
4use super::integer::fold_digits;
5use super::{digits, digits_trailing_zeros, signed};
6use crate::character::{character, Character};
7
8#[doc(no_inline)]
9pub use compute_float::compute_float;
10
11#[cfg(any(feature = "std", feature = "libm"))]
19#[inline]
20pub fn float<'a, N, I, C>(neg: bool) -> impl Parser<I, Output = N> + 'a
21where
22 N: compute_float::Float + num_traits::Float + 'a,
23 I: Input<Ok = C> + ?Sized + 'a,
24 C: Character + 'a,
25{
26 float_inner().map(move |(man, exp10)| {
27 compute_float(neg, man, exp10).unwrap_or_else(|| {
28 let res = N::from(man).unwrap() * N::from(10u8).unwrap().powi(exp10);
29 if neg {
30 -res
31 } else {
32 res
33 }
34 })
35 })
36}
37
38#[inline]
39#[cfg(not(any(feature = "std", feature = "libm")))]
40pub fn float<'a, N, I, C>(neg: bool) -> impl Parser<I, Output = N> + 'a
41where
42 N: compute_float::Float + 'a,
43 I: Input<Ok = C> + ?Sized + 'a,
44 C: Character + 'a,
45{
46 float_inner().try_map(move |(man, exp10)| {
47 compute_float(neg, man, exp10).ok_or("a valid floating point number")
48 })
49}
50
51fn float_inner<'a, I, C>() -> impl Parser<I, Output = (u64, i32)> + 'a
52where
53 I: Input<Ok = C> + ?Sized + 'a,
54 C: Character + 'a,
55{
56 fold_digits::<u64, _, _, _>(digits(10), 0, 10, false)
57 .then(|(int, _, overflowed)| {
58 if overflowed {
59 value((int, 0, true)).left()
60 } else {
61 character(b'.')
62 .prefix(fold_digits(digits_trailing_zeros(10), int, 10, false))
63 .or(value((int, 0, false)))
64 .right()
65 }
66 })
67 .and(
68 character(b'e')
69 .or(character(b'E'))
70 .prefix(signed(
71 |neg| fold_digits(digits_trailing_zeros(10), 0i32, 10, neg),
72 true,
73 ))
74 .or(value((0, 0, false))),
75 )
76 .map(
77 |((mantissa, count, man_overflowed), (exp, _, exp_overflowed))| {
78 (
79 if man_overflowed { u64::MAX } else { mantissa },
80 if exp_overflowed {
81 if exp < 0 {
82 i32::MIN
83 } else {
84 i32::MAX
85 }
86 } else {
87 exp.saturating_sub(count as i32)
88 },
89 )
90 },
91 )
92}