nu_command/conversions/into/
float.rs1use nu_cmd_base::input_handler::{CellPathOnlyArgs, operate};
2use nu_engine::command_prelude::*;
3
4#[derive(Clone)]
5pub struct IntoFloat;
6
7impl Command for IntoFloat {
8 fn name(&self) -> &str {
9 "into float"
10 }
11
12 fn signature(&self) -> Signature {
13 Signature::build("into float")
14 .input_output_types(vec![
15 (Type::Int, Type::Float),
16 (Type::String, Type::Float),
17 (Type::Bool, Type::Float),
18 (Type::Float, Type::Float),
19 (Type::table(), Type::table()),
20 (Type::record(), Type::record()),
21 (
22 Type::List(Box::new(Type::Any)),
23 Type::List(Box::new(Type::Float)),
24 ),
25 ])
26 .rest(
27 "rest",
28 SyntaxShape::CellPath,
29 "For a data structure input, convert data at the given cell paths.",
30 )
31 .allow_variants_without_examples(true)
32 .category(Category::Conversions)
33 }
34
35 fn description(&self) -> &str {
36 "Convert data into floating point number."
37 }
38
39 fn search_terms(&self) -> Vec<&str> {
40 vec!["convert", "number", "floating", "decimal"]
41 }
42
43 fn run(
44 &self,
45 engine_state: &EngineState,
46 stack: &mut Stack,
47 call: &Call,
48 input: PipelineData,
49 ) -> Result<PipelineData, ShellError> {
50 let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
51 let args = CellPathOnlyArgs::from(cell_paths);
52 operate(action, args, input, call.head, engine_state.signals())
53 }
54
55 fn examples(&self) -> Vec<Example> {
56 vec![
57 Example {
58 description: "Convert string to float in table",
59 example: "[[num]; ['5.01']] | into float num",
60 result: Some(Value::test_list(vec![Value::test_record(record! {
61 "num" => Value::test_float(5.01),
62 })])),
63 },
64 Example {
65 description: "Convert string to floating point number",
66 example: "'1.345' | into float",
67 result: Some(Value::test_float(1.345)),
68 },
69 Example {
70 description: "Coerce list of ints and floats to float",
71 example: "[4 -5.9] | into float",
72 result: Some(Value::test_list(vec![
73 Value::test_float(4.0),
74 Value::test_float(-5.9),
75 ])),
76 },
77 Example {
78 description: "Convert boolean to float",
79 example: "true | into float",
80 result: Some(Value::test_float(1.0)),
81 },
82 ]
83 }
84}
85
86fn action(input: &Value, _args: &CellPathOnlyArgs, head: Span) -> Value {
87 let span = input.span();
88 match input {
89 Value::Float { .. } => input.clone(),
90 Value::String { val: s, .. } => {
91 let other = s.trim();
92
93 match other.parse::<f64>() {
94 Ok(x) => Value::float(x, head),
95 Err(reason) => Value::error(
96 ShellError::CantConvert {
97 to_type: "float".to_string(),
98 from_type: reason.to_string(),
99 span,
100 help: None,
101 },
102 span,
103 ),
104 }
105 }
106 Value::Int { val: v, .. } => Value::float(*v as f64, span),
107 Value::Bool { val: b, .. } => Value::float(
108 match b {
109 true => 1.0,
110 false => 0.0,
111 },
112 span,
113 ),
114 Value::Error { .. } => input.clone(),
116 other => Value::error(
117 ShellError::OnlySupportsThisInputType {
118 exp_input_type: "string, int or bool".into(),
119 wrong_type: other.get_type().to_string(),
120 dst_span: head,
121 src_span: other.span(),
122 },
123 head,
124 ),
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use nu_protocol::Type::Error;
132
133 #[test]
134 fn test_examples() {
135 use crate::test_examples;
136
137 test_examples(IntoFloat {})
138 }
139
140 #[test]
141 #[allow(clippy::approx_constant)]
142 fn string_to_float() {
143 let word = Value::test_string("3.1415");
144 let expected = Value::test_float(3.1415);
145
146 let actual = action(&word, &CellPathOnlyArgs::from(vec![]), Span::test_data());
147 assert_eq!(actual, expected);
148 }
149
150 #[test]
151 fn communicates_parsing_error_given_an_invalid_floatlike_string() {
152 let invalid_str = Value::test_string("11.6anra");
153
154 let actual = action(
155 &invalid_str,
156 &CellPathOnlyArgs::from(vec![]),
157 Span::test_data(),
158 );
159
160 assert_eq!(actual.get_type(), Error);
161 }
162
163 #[test]
164 fn int_to_float() {
165 let input_int = Value::test_int(10);
166 let expected = Value::test_float(10.0);
167 let actual = action(
168 &input_int,
169 &CellPathOnlyArgs::from(vec![]),
170 Span::test_data(),
171 );
172
173 assert_eq!(actual, expected);
174 }
175}