crystal_cif_io/grammar/numeric_values/
float.rs1use std::fmt::Display;
2
3use winnow::{
4 ascii::{digit0, digit1},
5 combinator::{alt, repeat, separated_pair, terminated},
6 error::StrContext,
7 PResult, Parser,
8};
9
10use crate::grammar::{SyntacticUnit, Value};
11
12use super::{exponent::Exponent, integer::Integer, Number, Numeric};
13
14#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
15pub struct Float(pub f32);
16
17impl Display for Float {
18 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 <f32 as Display>::fmt(&self.0, fmt)
20 }
21}
22
23impl std::ops::Deref for Float {
24 type Target = f32;
25
26 fn deref(&self) -> &Self::Target {
27 &self.0
28 }
29}
30
31fn sign_zero_or_one(input: &mut &str) -> PResult<String> {
32 repeat(0..=1, alt(('+', '-')))
33 .context(StrContext::Label("{'+'|'-'}?"))
34 .parse_next(input)
35}
36
37fn exponent_zero_or_one(input: &mut &str) -> PResult<String> {
38 repeat(0..=1, Exponent::parser.map(|e| e.formatted_output()))
39 .context(StrContext::Label("{<Exponent>}?"))
40 .map(|exps: Vec<String>| exps.concat())
41 .parse_next(input)
42}
43
44fn float_1(input: &mut &str) -> PResult<f32> {
45 (Integer::parser, Exponent::parser)
46 .map(|(i, e)| *i as f32 * 10_f32.powi(*e))
47 .context(StrContext::Label("<Integer><Exponent>"))
48 .parse_next(input)
49}
50
51fn float_2(input: &mut &str) -> PResult<f32> {
52 (
53 sign_zero_or_one,
54 alt((
55 separated_pair(digit0, '.', digit1).map(|(i, decimal)| format!("{i}.{decimal}")),
56 terminated(digit1, '.').map(|d| format!("{d}.")),
57 )),
58 exponent_zero_or_one,
59 )
60 .map(|(sign, float, exp)| {
61 format!("{sign}{float}{exp}")
62 .parse::<f32>()
63 .expect("Failed to parse as f32")
64 })
65 .parse_next(input)
66}
67
68impl SyntacticUnit for Float {
69 type ParseResult = Self;
70
71 type FormatOutput = f32;
72
73 fn parser(input: &mut &str) -> winnow::prelude::PResult<Self::ParseResult> {
74 alt((float_1, float_2)).map(Float).parse_next(input)
75 }
76
77 fn formatted_output(&self) -> Self::FormatOutput {
78 self.0
79 }
80}
81
82impl From<f64> for Float {
83 fn from(value: f64) -> Self {
84 Float(value as f32)
85 }
86}
87
88impl From<Float> for Number {
89 fn from(value: Float) -> Self {
90 Number::Float(value)
91 }
92}
93
94impl From<Float> for Numeric {
95 fn from(value: Float) -> Self {
96 Self::new(Number::from(value), None)
97 }
98}
99
100impl From<Float> for Value {
101 fn from(value: Float) -> Self {
102 Value::Numeric(Numeric::from(value))
103 }
104}
105
106impl From<Float> for f64 {
107 fn from(value: Float) -> Self {
108 *value as f64
109 }
110}
111
112#[cfg(test)]
113mod test {
114 use crate::grammar::{Float, SyntacticUnit};
115
116 #[test]
117 fn float_parsing() {
118 let mut input = "0.0033";
119 dbg!(Float::parser(&mut input).unwrap());
120 dbg!(Float::parser(&mut ".4254").unwrap());
121 }
122}