vrl/stdlib/
parse_float.rs1use 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}