use crate::types::UnitMap;
use rhai::{Array, EvalAltResult, Map, Position};
use std::{collections::BTreeMap, str::FromStr};
use zfuel::fuel::ZFuel;
pub fn parse_float(s: String) -> f64 {
s.parse::<f64>().unwrap_or(0.0)
}
pub fn add_units(a: Map, b: Map) -> Result<Map, Box<EvalAltResult>> {
let mut a = parse_amount(a)?;
let b = parse_amount(b)?;
a.add(b).map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
e.to_string().into(),
Position::NONE,
))
})?;
Ok(a.to_map())
}
pub fn sub_units(a: Map, b: Map) -> Result<Map, Box<EvalAltResult>> {
let mut a = parse_amount(a)?;
let b = parse_amount(b)?;
a.sub(b).map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(
e.to_string().into(),
Position::NONE,
))
})?;
Ok(a.to_map())
}
pub fn extract_indexes(amount: Map, indexes: Array) -> Result<Map, Box<EvalAltResult>> {
let units = parse_amount(amount)?;
let indexes: Vec<String> = indexes.into_iter().map(|index| index.to_string()).collect();
let mut extracted_amount = Map::new();
for (key, value) in units.into_iter() {
if indexes.contains(&key) {
extracted_amount.insert(key.into(), value.to_string().into());
}
}
Ok(extracted_amount)
}
fn parse_amount(amount: Map) -> Result<UnitMap, Box<EvalAltResult>> {
let mut units = BTreeMap::new();
for (key, value) in amount.iter() {
units.insert(
key.to_string(),
ZFuel::from_str(value.to_string().as_str()).map_err(|_| {
Box::new(EvalAltResult::ErrorRuntime(
format!(
"Failed to parse unit amount: {}",
value.to_string().as_str()
)
.into(),
Position::NONE,
))
})?,
);
}
Ok(UnitMap::load(units))
}
pub fn add_fuel(a: String, b: String) -> Result<String, Box<EvalAltResult>> {
let a = ZFuel::from_str(&a).map_err(|_| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to parse unit a amount: {}", a).into(),
Position::NONE,
))
})?;
let b = ZFuel::from_str(&b).map_err(|_| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to parse fuel b amount: {}", b).into(),
Position::NONE,
))
})?;
let c = (a + b).map_err(|_| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to add fuel amounts: {} + {}", a, b).into(),
Position::NONE,
))
})?;
Ok(c.to_string())
}
pub fn sub_fuel(a: String, b: String) -> Result<String, Box<EvalAltResult>> {
let a = ZFuel::from_str(&a).map_err(|_| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to parse fuel amount: {}", a).into(),
Position::NONE,
))
})?;
let b = ZFuel::from_str(&b).map_err(|_| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to parse fuel amount: {}", b).into(),
Position::NONE,
))
})?;
let c = (a - b).map_err(|_| {
Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to subtract fuel amounts: {} - {}", a, b).into(),
Position::NONE,
))
})?;
Ok(c.to_string())
}
pub fn is_greater_than_eq(a: String, b: String) -> Result<bool, Box<EvalAltResult>> {
let a = ZFuel::from_str(&a).map_err(|_| {
Box::new(EvalAltResult::ErrorRuntime(
"Failed to parse fuel amount".into(),
Position::NONE,
))
})?;
let b = ZFuel::from_str(&b).map_err(|_| {
Box::new(EvalAltResult::ErrorRuntime(
"Failed to parse fuel amount".into(),
Position::NONE,
))
})?;
Ok(a >= b)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_float_positive() {
assert_eq!(parse_float("2.99".to_string()), 2.99);
assert_eq!(parse_float("100.5".to_string()), 100.5);
assert_eq!(parse_float("0.5".to_string()), 0.5);
}
#[test]
fn test_parse_float_negative() {
assert_eq!(parse_float("-2.99".to_string()), -2.99);
assert_eq!(parse_float("-100.5".to_string()), -100.5);
assert_eq!(parse_float("-0.5".to_string()), -0.5);
}
#[test]
fn test_parse_float_integers() {
assert_eq!(parse_float("42".to_string()), 42.0);
assert_eq!(parse_float("-42".to_string()), -42.0);
assert_eq!(parse_float("0".to_string()), 0.0);
}
#[test]
fn test_parse_float_leading_decimal() {
assert_eq!(parse_float(".99".to_string()), 0.99);
assert_eq!(parse_float(".5".to_string()), 0.5);
}
#[test]
fn test_parse_float_invalid() {
assert_eq!(parse_float("invalid".to_string()), 0.0);
assert_eq!(parse_float("".to_string()), 0.0);
assert_eq!(parse_float("abc123".to_string()), 0.0);
}
#[test]
fn test_parse_float_edge_cases() {
assert_eq!(parse_float("0.0".to_string()), 0.0);
assert_eq!(parse_float("-0.0".to_string()), -0.0);
assert_eq!(parse_float(" 2.99 ".to_string()), 0.0); }
#[test]
fn test_parse_float_with_trim() {
let with_whitespace = " 2.99 ";
assert_eq!(parse_float(with_whitespace.trim().to_string()), 2.99);
let with_leading_space = " .99";
assert_eq!(parse_float(with_leading_space.trim().to_string()), 0.99);
}
#[test]
fn test_parse_float_substring_scenario() {
let negative_amount = "-2.99";
let positive_amount = "2.99";
let result_neg = parse_float(negative_amount[1..].to_string());
assert_eq!(result_neg, 2.99);
let result_pos = parse_float(positive_amount[1..].to_string());
assert_eq!(result_pos, 0.99); }
}