From 15d503b396a3a7fb9280447c019c2a7795f62a27 Mon Sep 17 00:00:00 2001 From: Ziyang Hu Date: Sat, 27 Aug 2022 19:09:46 +0800 Subject: [PATCH] op 'to_float' --- README.md | 2 +- src/data/expr.rs | 16 ++++++++++++++++ src/data/json.rs | 39 ++++++++++++++++++++++++++++++++++----- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0e2f55cc..33d3a241 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ * [ ] graph algorithms * [x] bfs * [x] dfs - * [ ] shortest path + * [ ] shortest path, SSSP * [ ] A* * [ ] Yen's k-shortest * [ ] all-pairs shortest path diff --git a/src/data/expr.rs b/src/data/expr.rs index a93e6dec..848a5b5e 100644 --- a/src/data/expr.rs +++ b/src/data/expr.rs @@ -3,6 +3,7 @@ use std::collections::{BTreeMap, BTreeSet}; use std::fmt::{Debug, Formatter}; use std::mem; use std::ops::{Div, Rem}; +use std::str::FromStr; use anyhow::{anyhow, bail, ensure, Result}; use itertools::Itertools; @@ -1501,6 +1502,20 @@ fn op_decode_base64(args: &[DataValue]) -> Result { } } +define_op!(OP_TO_FLOAT, 1, false, false); +fn op_to_float(args: &[DataValue]) -> Result { + Ok(match &args[0] { + DataValue::Number(n) => n.get_float().into(), + DataValue::String(t) => match t as &str { + "NAN" => f64::NAN.into(), + "INFINITY" => f64::INFINITY.into(), + "NEGATIVE_INFINITY" => f64::NEG_INFINITY.into(), + s => f64::from_str(s)?.into(), + }, + v => bail!("'to_float' cannot be applied to {:?}", v), + }) +} + pub(crate) fn get_op(name: &str) -> Option<&'static Op> { Some(match name { "list" => &OP_LIST, @@ -1595,6 +1610,7 @@ pub(crate) fn get_op(name: &str) -> Option<&'static Op> { "chunks" => &OP_CHUNKS, "chunks_exact" => &OP_CHUNKS_EXACT, "windows" => &OP_WINDOWS, + "to_float" => &OP_TO_FLOAT, _ => return None, }) } diff --git a/src/data/json.rs b/src/data/json.rs index 8032e521..14cfe229 100644 --- a/src/data/json.rs +++ b/src/data/json.rs @@ -63,7 +63,21 @@ impl From for JsonValue { DataValue::Null => JsonValue::Null, DataValue::Bool(b) => JsonValue::Bool(b), DataValue::Number(Number::Int(i)) => JsonValue::Number(i.into()), - DataValue::Number(Number::Float(f)) => json!(f), + DataValue::Number(Number::Float(f)) => { + if f.is_finite() { + json!(f) + } else if f.is_nan() { + json!(()) + } else if f.is_infinite() { + if f.is_sign_negative() { + json!("NEGATIVE_INFINITY") + } else { + json!("INFINITY") + } + } else { + unreachable!() + } + } DataValue::String(t) => JsonValue::String(t.into()), DataValue::Bytes(bytes) => JsonValue::String(base64::encode(bytes)), DataValue::List(l) => { @@ -77,10 +91,9 @@ impl From for JsonValue { } DataValue::Regex(r) => { json!(r.0.as_str()) - } - // DataValue::Map(m) => { - // JsonValue::Array(m.into_iter().map(|(k, v)| json!([k, v])).collect()) - // } + } // DataValue::Map(m) => { + // JsonValue::Array(m.into_iter().map(|(k, v)| json!([k, v])).collect()) + // } } } } @@ -215,3 +228,19 @@ impl TryFrom<&'_ JsonValue> for TxId { Ok(TxId(v)) } } + +#[cfg(test)] +mod tests { + use serde_json::json; + use crate::data::json::JsonValue; + + use crate::data::value::DataValue; + + #[test] + fn bad_values() { + println!("{}", json!(f64::INFINITY)); + println!("{}", JsonValue::from(DataValue::from(f64::INFINITY))); + println!("{}", JsonValue::from(DataValue::from(f64::NEG_INFINITY))); + println!("{}", JsonValue::from(DataValue::from(f64::NAN))); + } +}