vrl/stdlib/
parse_float.rs

1use crate::compiler::prelude::*;
2use crate::stdlib::to_float::bytes_to_float;
3
4fn parse_float(value: Value) -> Resolved {
5    bytes_to_float(value.try_bytes()?)
6}
7
8#[derive(Clone, Copy, Debug)]
9pub struct ParseFloat;
10
11impl Function for ParseFloat {
12    fn identifier(&self) -> &'static str {
13        "parse_float"
14    }
15
16    fn usage(&self) -> &'static str {
17        "Parses the string `value` representing a floating point number in base 10 to a float."
18    }
19
20    fn category(&self) -> &'static str {
21        Category::String.as_ref()
22    }
23
24    fn internal_failure_reasons(&self) -> &'static [&'static str] {
25        &["`value` is not a string."]
26    }
27
28    fn return_kind(&self) -> u16 {
29        kind::FLOAT
30    }
31
32    fn parameters(&self) -> &'static [Parameter] {
33        const PARAMETERS: &[Parameter] = &[Parameter::required(
34            "value",
35            kind::BYTES,
36            "The string to parse.",
37        )];
38        PARAMETERS
39    }
40
41    fn examples(&self) -> &'static [Example] {
42        &[
43            example! {
44                title: "Parse negative integer",
45                source: r#"parse_float!("-42")"#,
46                result: Ok("-42.0"),
47            },
48            example! {
49                title: "Parse float",
50                source: r#"parse_float!("42.38")"#,
51                result: Ok("42.38"),
52            },
53            example! {
54                title: "Scientific notation",
55                source: r#"parse_float!("2.5e3")"#,
56                result: Ok("2500.0"),
57            },
58        ]
59    }
60
61    fn compile(
62        &self,
63        _state: &state::TypeState,
64        _ctx: &mut FunctionCompileContext,
65        arguments: ArgumentList,
66    ) -> Compiled {
67        let value = arguments.required("value");
68
69        Ok(ParseFloatFn { value }.as_expr())
70    }
71}
72
73#[derive(Debug, Clone)]
74struct ParseFloatFn {
75    value: Box<dyn Expression>,
76}
77
78impl FunctionExpression for ParseFloatFn {
79    fn resolve(&self, ctx: &mut Context) -> Resolved {
80        let value = self.value.resolve(ctx)?;
81
82        parse_float(value)
83    }
84
85    fn type_def(&self, _: &state::TypeState) -> TypeDef {
86        TypeDef::float().fallible()
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    test_function![
95        parse_float => ParseFloat;
96
97        integer {
98            args: func_args![value: "-42"],
99            want: Ok(-42.0),
100            tdef: TypeDef::float().fallible(),
101        }
102
103        float {
104            args: func_args![value: "42.38"],
105            want: Ok(42.38),
106            tdef: TypeDef::float().fallible(),
107        }
108
109        scientific_1 {
110            args: func_args![value: "2.5e3"],
111            want: Ok(2500.0),
112            tdef: TypeDef::float().fallible(),
113        }
114
115        scientific_2 {
116            args: func_args![value: "8.543e-2"],
117            want: Ok(0.08543),
118            tdef: TypeDef::float().fallible(),
119        }
120
121        positive_zero {
122            args: func_args![value: "+0"],
123            want: Ok(0.0),
124            tdef: TypeDef::float().fallible(),
125        }
126
127        negative_zero {
128            args: func_args![value: "-0"],
129            want: Ok(-0.0),
130            tdef: TypeDef::float().fallible(),
131        }
132
133        positive_infinity {
134            args: func_args![value: "inf"],
135            want: Ok(f64::INFINITY),
136            tdef: TypeDef::float().fallible(),
137        }
138
139        negative_infinity {
140            args: func_args![value: "-inf"],
141            want: Ok(f64::NEG_INFINITY),
142            tdef: TypeDef::float().fallible(),
143        }
144
145        nan {
146            args: func_args![value: "Nan"],
147            want: Err("NaN number not supported \"Nan\"".to_string()),
148            tdef: TypeDef::float().fallible(),
149        }
150
151        min {
152            args: func_args![value: "-1.7976931348623157e+308"],
153            want: Ok(f64::MIN),
154            tdef: TypeDef::float().fallible(),
155        }
156
157        max {
158            args: func_args![value: "1.7976931348623157e+308"],
159            want: Ok(f64::MAX),
160            tdef: TypeDef::float().fallible(),
161        }
162
163        large_string {
164            args: func_args![value: "9".repeat(9999)],
165            want: Ok(f64::INFINITY),
166            tdef: TypeDef::float().fallible(),
167        }
168    ];
169}