Skip to main content

openjd_expr/functions/
conversion.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// Copyright by contributors to this project.
3// SPDX-License-Identifier: (Apache-2.0 OR MIT)
4
5//! Type conversion function implementations.
6
7use crate::error::ExpressionError;
8use crate::function_library::EvalContext;
9use crate::value::{ExprValue, Float64};
10
11type R = Result<ExprValue, ExpressionError>;
12type Ctx<'a> = &'a mut dyn EvalContext;
13
14pub fn string_fn(_: Ctx, a: &[ExprValue]) -> R {
15    Ok(ExprValue::String(a[0].to_display_string()))
16}
17
18pub fn int_from_int(_: Ctx, a: &[ExprValue]) -> R {
19    match &a[0] {
20        ExprValue::Int(i) => Ok(ExprValue::Int(*i)),
21        _ => Err(ExpressionError::type_error("type error")),
22    }
23}
24
25pub fn int_from_float(_: Ctx, a: &[ExprValue]) -> R {
26    match &a[0] {
27        ExprValue::Float(f) => {
28            if f.value().fract() != 0.0 {
29                return Err(ExpressionError::new(format!(
30                    "Cannot convert {f} to int: not a whole number"
31                )));
32            }
33            if f.value() >= i64::MAX as f64 || f.value() < i64::MIN as f64 {
34                return Err(ExpressionError::integer_overflow());
35            }
36            Ok(ExprValue::Int(f.value() as i64))
37        }
38        _ => Err(ExpressionError::type_error("type error")),
39    }
40}
41
42pub fn int_from_bool(_: Ctx, a: &[ExprValue]) -> R {
43    match &a[0] {
44        ExprValue::Bool(b) => Ok(ExprValue::Int(if *b { 1 } else { 0 })),
45        _ => Err(ExpressionError::type_error("type error")),
46    }
47}
48
49pub fn int_from_string(_: Ctx, a: &[ExprValue]) -> R {
50    match &a[0] {
51        ExprValue::String(s) => {
52            let v: i64 = s
53                .trim()
54                .parse()
55                .map_err(|_| ExpressionError::new(format!("Cannot convert '{s}' to int")))?;
56            Ok(ExprValue::Int(v))
57        }
58        _ => Err(ExpressionError::type_error("type error")),
59    }
60}
61
62pub fn float_from_float(_: Ctx, a: &[ExprValue]) -> R {
63    match &a[0] {
64        ExprValue::Float(f) => Ok(ExprValue::Float(Float64::new(f.value())?)),
65        _ => Err(ExpressionError::type_error("type error")),
66    }
67}
68
69pub fn float_from_int(_: Ctx, a: &[ExprValue]) -> R {
70    match &a[0] {
71        ExprValue::Int(i) => Ok(ExprValue::Float(Float64::new(*i as f64)?)),
72        _ => Err(ExpressionError::type_error("type error")),
73    }
74}
75
76pub fn float_from_string(_: Ctx, a: &[ExprValue]) -> R {
77    match &a[0] {
78        ExprValue::String(s) => {
79            let lower = s.trim().to_lowercase();
80            if lower == "inf" || lower == "infinity" || lower == "-inf" || lower == "-infinity" {
81                return Err(ExpressionError::float_error(
82                    "Cannot convert to float: infinity",
83                ));
84            }
85            if lower == "nan" {
86                return Err(ExpressionError::float_error("Cannot convert to float: NaN"));
87            }
88            let v: f64 = s
89                .trim()
90                .parse()
91                .map_err(|_| ExpressionError::new(format!("Cannot convert '{s}' to float")))?;
92            Ok(ExprValue::Float(Float64::new(v)?))
93        }
94        _ => Err(ExpressionError::type_error("type error")),
95    }
96}
97
98pub fn bool_from_bool(_: Ctx, a: &[ExprValue]) -> R {
99    match &a[0] {
100        ExprValue::Bool(b) => Ok(ExprValue::Bool(*b)),
101        _ => Err(ExpressionError::type_error("type error")),
102    }
103}
104
105pub fn bool_from_int(_: Ctx, a: &[ExprValue]) -> R {
106    match &a[0] {
107        ExprValue::Int(i) => Ok(ExprValue::Bool(*i != 0)),
108        _ => Err(ExpressionError::type_error("type error")),
109    }
110}
111
112pub fn bool_from_float(_: Ctx, a: &[ExprValue]) -> R {
113    match &a[0] {
114        ExprValue::Float(f) => Ok(ExprValue::Bool(*f != 0.0)),
115        _ => Err(ExpressionError::type_error("type error")),
116    }
117}
118
119pub fn bool_from_null(_: Ctx, _a: &[ExprValue]) -> R {
120    Ok(ExprValue::Bool(false))
121}
122
123pub fn bool_from_string(_: Ctx, a: &[ExprValue]) -> R {
124    match &a[0] {
125        ExprValue::String(s) => match s.to_lowercase().as_str() {
126            "true" | "yes" | "on" | "1" => Ok(ExprValue::Bool(true)),
127            "false" | "no" | "off" | "0" => Ok(ExprValue::Bool(false)),
128            _ => Err(ExpressionError::new(format!(
129                "Cannot convert '{s}' to bool. Expected one of: 1, true, on, yes, 0, false, off, no"
130            ))),
131        },
132        _ => Err(ExpressionError::type_error("type error")),
133    }
134}
135
136pub fn bool_from_path(_: Ctx, _a: &[ExprValue]) -> R {
137    Err(ExpressionError::new("Cannot convert path to bool"))
138}
139
140pub fn bool_from_list(_: Ctx, _a: &[ExprValue]) -> R {
141    Err(ExpressionError::new("Cannot convert list to bool"))
142}