diff --git a/valuable/Cargo.toml b/valuable/Cargo.toml index 4d7818a2..ff4bacdb 100644 --- a/valuable/Cargo.toml +++ b/valuable/Cargo.toml @@ -18,8 +18,12 @@ std = ["alloc"] # Provide imps for types in Rust's `alloc` library. alloc = [] +# Provides serde_json::Value instrument for valuable +json = ["serde_json"] + [dependencies] valuable-derive = { version = "0.1.0", optional = true, path = "../valuable-derive" } +serde_json = { version = "1.0.46", optional = true } [dev-dependencies] criterion = "0.3" diff --git a/valuable/src/json.rs b/valuable/src/json.rs new file mode 100644 index 00000000..a451dc0b --- /dev/null +++ b/valuable/src/json.rs @@ -0,0 +1,78 @@ +use serde_json::{Map, Value as Json}; + +use crate::{Mappable, Valuable, Value, Visit}; + +impl Valuable for Json { + fn as_value(&self) -> Value<'_> { + match self { + Json::Array(ref array) => array.as_value(), + Json::Bool(ref value) => value.as_value(), + Json::Number(ref num) => { + if num.is_f64() { + Value::F64(num.as_f64().unwrap()) + } else if num.is_i64() { + Value::I64(num.as_i64().unwrap()) + } else { + unreachable!() + } + } + Json::Null => Value::Unit, + Json::String(ref s) => s.as_value(), + Json::Object(ref object) => object.as_value(), + } + } + + fn visit(&self, visit: &mut dyn Visit) { + match self { + Json::Array(ref array) => array.visit(visit), + Json::Bool(ref value) => value.visit(visit), + Json::Number(ref num) => { + if num.is_f64() { + num.as_f64().unwrap().visit(visit) + } else if num.is_i64() { + num.as_i64().unwrap().visit(visit) + } else { + unreachable!() + } + } + Json::Null => Value::Unit.visit(visit), + Json::String(ref s) => s.visit(visit), + Json::Object(ref object) => object.visit(visit), + } + } +} + +impl Valuable for Map { + fn as_value(&self) -> Value<'_> { + Value::Mappable(self) + } + + fn visit(&self, visit: &mut dyn Visit) { + for (k, v) in self.iter() { + visit.visit_entry(k.as_value(), v.as_value()); + } + } +} + +impl Mappable for Map { + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } +} + +#[cfg(test)] +mod test { + use crate::{Valuable, Value}; + use serde_json::json; + + #[test] + fn test_json() { + let j = json!({"a": 100, "b": 1.0, "c": -1}); + let jv = j.as_value(); + + assert!(matches!(jv, Value::Mappable(_))); + + assert!(matches!(json!(100).as_value(), Value::I64(_))); + } +} diff --git a/valuable/src/lib.rs b/valuable/src/lib.rs index 7e61b5a5..26c84e0f 100644 --- a/valuable/src/lib.rs +++ b/valuable/src/lib.rs @@ -135,3 +135,6 @@ pub use visit::{visit, Visit}; #[cfg(feature = "derive")] pub use valuable_derive::*; + +#[cfg(feature = "json")] +mod json;