use helios_fhirpath_support::{EvaluationError, EvaluationResult};
use rust_decimal::Decimal;
use rust_decimal::prelude::ToPrimitive;
#[allow(unused_imports)]
use std::str::FromStr;
pub fn to_decimal_function(
invocation_base: &EvaluationResult,
) -> Result<EvaluationResult, EvaluationError> {
if invocation_base.count() > 1 {
return Err(EvaluationError::SingletonEvaluationError(
"toDecimal requires a singleton input".to_string(),
));
}
Ok(match invocation_base {
EvaluationResult::Empty => EvaluationResult::Empty,
EvaluationResult::Boolean(b, _, _) => {
EvaluationResult::decimal(if *b { Decimal::ONE } else { Decimal::ZERO })
}
EvaluationResult::Integer(i, _, _) => EvaluationResult::decimal(Decimal::from(*i)),
#[cfg(not(any(feature = "R4", feature = "R4B")))]
EvaluationResult::Integer64(i, _, _) => EvaluationResult::decimal(Decimal::from(*i)),
EvaluationResult::Decimal(d, _, _) => EvaluationResult::decimal(*d),
EvaluationResult::String(s, _, _) => {
s.parse::<Decimal>()
.map(EvaluationResult::decimal)
.unwrap_or(EvaluationResult::Empty) }
EvaluationResult::Quantity(val, _, _, _) => EvaluationResult::decimal(*val),
EvaluationResult::Collection { .. } => unreachable!(),
_ => EvaluationResult::Empty,
})
}
pub fn to_integer_function(
invocation_base: &EvaluationResult,
) -> Result<EvaluationResult, EvaluationError> {
if invocation_base.count() > 1 {
return Err(EvaluationError::SingletonEvaluationError(
"toInteger requires a singleton input".to_string(),
));
}
Ok(match invocation_base {
EvaluationResult::Empty => EvaluationResult::Empty,
EvaluationResult::Boolean(b, _, _) => EvaluationResult::integer(if *b { 1 } else { 0 }),
EvaluationResult::Integer(i, _, _) => EvaluationResult::integer(*i),
#[cfg(not(any(feature = "R4", feature = "R4B")))]
EvaluationResult::Integer64(i, _, _) => EvaluationResult::integer(*i),
EvaluationResult::String(s, _, _) => {
s.parse::<i64>()
.map(EvaluationResult::integer)
.unwrap_or(EvaluationResult::Empty) }
EvaluationResult::Decimal(_, _, _) => EvaluationResult::Empty,
EvaluationResult::Quantity(val, _, _, _) => {
if val.is_integer() {
val.to_i64()
.map(EvaluationResult::integer)
.unwrap_or(EvaluationResult::Empty)
} else {
EvaluationResult::Empty
}
}
EvaluationResult::Collection { .. } => unreachable!(),
_ => EvaluationResult::Empty,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_to_decimal_empty() {
let empty = EvaluationResult::Empty;
let result = to_decimal_function(&empty).unwrap();
assert_eq!(result, EvaluationResult::Empty);
}
#[test]
fn test_to_decimal_boolean() {
let true_val = EvaluationResult::boolean(true);
let result = to_decimal_function(&true_val).unwrap();
assert_eq!(result, EvaluationResult::decimal(Decimal::ONE));
let false_val = EvaluationResult::boolean(false);
let result = to_decimal_function(&false_val).unwrap();
assert_eq!(result, EvaluationResult::decimal(Decimal::ZERO));
}
#[test]
fn test_to_decimal_integer() {
let int_val = EvaluationResult::integer(42);
let result = to_decimal_function(&int_val).unwrap();
assert_eq!(result, EvaluationResult::decimal(Decimal::from(42)));
}
#[test]
fn test_to_decimal_decimal() {
let decimal = Decimal::from_str("3.14159").unwrap();
let decimal_val = EvaluationResult::decimal(decimal);
let result = to_decimal_function(&decimal_val).unwrap();
assert_eq!(result, decimal_val);
}
#[test]
fn test_to_decimal_string_valid() {
let string_val = EvaluationResult::string("3.14159".to_string());
let result = to_decimal_function(&string_val).unwrap();
assert_eq!(
result,
EvaluationResult::decimal(Decimal::from_str("3.14159").unwrap())
);
}
#[test]
fn test_to_decimal_string_invalid() {
let string_val = EvaluationResult::string("not a number".to_string());
let result = to_decimal_function(&string_val).unwrap();
assert_eq!(result, EvaluationResult::Empty);
}
#[test]
fn test_to_decimal_quantity() {
let decimal = Decimal::from_str("3.14159").unwrap();
let quantity_val = EvaluationResult::quantity(decimal, "m".to_string());
let result = to_decimal_function(&quantity_val).unwrap();
assert_eq!(result, EvaluationResult::decimal(decimal));
}
#[test]
fn test_to_decimal_collection() {
let collection = EvaluationResult::Collection {
items: vec![EvaluationResult::integer(1), EvaluationResult::integer(2)],
has_undefined_order: false,
type_info: None,
};
let result = to_decimal_function(&collection);
assert!(result.is_err());
}
#[test]
fn test_to_integer_empty() {
let empty = EvaluationResult::Empty;
let result = to_integer_function(&empty).unwrap();
assert_eq!(result, EvaluationResult::Empty);
}
#[test]
fn test_to_integer_boolean() {
let true_val = EvaluationResult::boolean(true);
let result = to_integer_function(&true_val).unwrap();
assert_eq!(result, EvaluationResult::integer(1));
let false_val = EvaluationResult::boolean(false);
let result = to_integer_function(&false_val).unwrap();
assert_eq!(result, EvaluationResult::integer(0));
}
#[test]
fn test_to_integer_integer() {
let int_val = EvaluationResult::integer(42);
let result = to_integer_function(&int_val).unwrap();
assert_eq!(result, int_val);
}
#[test]
fn test_to_integer_decimal() {
let decimal = Decimal::from_str("3.14159").unwrap();
let decimal_val = EvaluationResult::decimal(decimal);
let result = to_integer_function(&decimal_val).unwrap();
assert_eq!(result, EvaluationResult::Empty);
}
#[test]
fn test_to_integer_string_valid() {
let string_val = EvaluationResult::string("42".to_string());
let result = to_integer_function(&string_val).unwrap();
assert_eq!(result, EvaluationResult::integer(42));
}
#[test]
fn test_to_integer_string_invalid() {
let string_val = EvaluationResult::string("not a number".to_string());
let result = to_integer_function(&string_val).unwrap();
assert_eq!(result, EvaluationResult::Empty);
let decimal_string = EvaluationResult::string("3.14".to_string());
let result = to_integer_function(&decimal_string).unwrap();
assert_eq!(result, EvaluationResult::Empty);
}
#[test]
fn test_to_integer_quantity_integer() {
let decimal = Decimal::from(42);
let quantity_val = EvaluationResult::quantity(decimal, "units".to_string());
let result = to_integer_function(&quantity_val).unwrap();
assert_eq!(result, EvaluationResult::integer(42));
}
#[test]
fn test_to_integer_quantity_decimal() {
let decimal = Decimal::from_str("3.14159").unwrap();
let quantity_val = EvaluationResult::quantity(decimal, "units".to_string());
let result = to_integer_function(&quantity_val).unwrap();
assert_eq!(result, EvaluationResult::Empty);
}
#[test]
fn test_to_integer_collection() {
let collection = EvaluationResult::Collection {
items: vec![EvaluationResult::integer(1), EvaluationResult::integer(2)],
has_undefined_order: false,
type_info: None,
};
let result = to_integer_function(&collection);
assert!(result.is_err());
}
}