From 696b5423df5beaea63b29dccf2e21f2c2fd019df Mon Sep 17 00:00:00 2001 From: Louis Maddox Date: Sun, 12 Oct 2025 20:04:59 +0100 Subject: [PATCH 1/6] feat(preserve_order): integrate IndexMap support across Value types and deserializers --- Cargo.toml | 8 +- src/serde/value/borrowed.rs | 2 + src/serde/value/borrowed/de.rs | 1 + src/serde/value/borrowed/ordered.rs | 19 + src/serde/value/borrowed/ordered/de.rs | 1024 +++++++++++++++++++++++ src/serde/value/borrowed/ordered/se.rs | 798 ++++++++++++++++++ src/serde/value/borrowed/se.rs | 21 +- src/serde/value/owned.rs | 2 + src/serde/value/owned/de.rs | 1 + src/serde/value/owned/ordered.rs | 19 + src/serde/value/owned/ordered/de.rs | 969 +++++++++++++++++++++ src/serde/value/owned/ordered/se.rs | 749 +++++++++++++++++ src/serde/value/owned/se.rs | 21 +- src/tests.rs | 6 +- src/tests/serde.rs | 2 +- src/value.rs | 41 +- src/value/borrowed.rs | 21 + src/value/borrowed/from.rs | 26 +- src/value/borrowed/ordered.rs | 988 ++++++++++++++++++++++ src/value/borrowed/ordered/cmp.rs | 188 +++++ src/value/borrowed/ordered/from.rs | 144 ++++ src/value/borrowed/ordered/serialize.rs | 273 ++++++ src/value/lazy/object.rs | 9 + src/value/owned.rs | 18 + src/value/owned/from.rs | 25 +- src/value/owned/ordered.rs | 1013 ++++++++++++++++++++++ src/value/owned/ordered/cmp.rs | 198 +++++ src/value/owned/ordered/from.rs | 187 +++++ src/value/owned/ordered/serialize.rs | 275 ++++++ 29 files changed, 7015 insertions(+), 33 deletions(-) create mode 100644 src/serde/value/borrowed/ordered.rs create mode 100644 src/serde/value/borrowed/ordered/de.rs create mode 100644 src/serde/value/borrowed/ordered/se.rs create mode 100644 src/serde/value/owned/ordered.rs create mode 100644 src/serde/value/owned/ordered/de.rs create mode 100644 src/serde/value/owned/ordered/se.rs create mode 100644 src/value/borrowed/ordered.rs create mode 100644 src/value/borrowed/ordered/cmp.rs create mode 100644 src/value/borrowed/ordered/from.rs create mode 100644 src/value/borrowed/ordered/serialize.rs create mode 100644 src/value/owned/ordered.rs create mode 100644 src/value/owned/ordered/cmp.rs create mode 100644 src/value/owned/ordered/from.rs create mode 100644 src/value/owned/ordered/serialize.rs diff --git a/Cargo.toml b/Cargo.toml index 3283cf7e..f1dfb2fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ rust-version = "1.88" [dependencies] simdutf8 = { version = "0.1.4", features = ["public_imp", "aarch64_neon"] } -value-trait = { version = "0.12" } +value-trait = { version = "0.12.1" } beef = { version = "0.5", optional = true } halfbrown = "0.4" # ahash known key @@ -25,6 +25,9 @@ ahash = { version = "0.8", optional = true } serde = { version = "1", features = ["derive"], optional = true } serde_json = { version = "1", optional = true } +# preserve insertion order +indexmap = { version = "2.0", optional = true } + # perf testing alloc_counter = { version = "0.0.4", optional = true } colored = { version = "3.0", optional = true } @@ -62,6 +65,9 @@ default = ["swar-number-parsing", "serde_impl", "runtime-detection"] arraybackend = ["halfbrown/arraybackend"] +# preserve insertion order +preserve_order = ["dep:indexmap", "value-trait/indexmap"] + # Forces the `owned::Value` and `borrowed::Value` to deduplicate duplicated keys by letting consecutive keys overwrite previous ones. This comes at a # performance cost. By default duplicate keys will not be overwritten and feeding json objects with duplicated # keys to either of the `Value`s will result in undefined behavior. diff --git a/src/serde/value/borrowed.rs b/src/serde/value/borrowed.rs index 7d7609c1..619b09bd 100644 --- a/src/serde/value/borrowed.rs +++ b/src/serde/value/borrowed.rs @@ -1,5 +1,7 @@ mod de; mod se; +#[cfg(feature = "preserve_order")] +pub mod ordered; use crate::{BorrowedValue, Result}; use serde_ext::de::Deserialize; diff --git a/src/serde/value/borrowed/de.rs b/src/serde/value/borrowed/de.rs index d282df3b..ea963f8c 100644 --- a/src/serde/value/borrowed/de.rs +++ b/src/serde/value/borrowed/de.rs @@ -220,6 +220,7 @@ struct ObjectRefAccess<'de> { i: halfbrown::Iter<'de, Cow<'de, str>, Value<'de>>, v: Option<&'de Value<'de>>, } + impl<'de> ObjectRefAccess<'de> { fn new(i: halfbrown::Iter<'de, Cow<'de, str>, Value<'de>>) -> Self { Self { i, v: None } diff --git a/src/serde/value/borrowed/ordered.rs b/src/serde/value/borrowed/ordered.rs new file mode 100644 index 00000000..06fda9ca --- /dev/null +++ b/src/serde/value/borrowed/ordered.rs @@ -0,0 +1,19 @@ +mod de; +mod se; + +use crate::value::borrowed::ordered::Value; +use crate::Result; +use serde_ext::ser::Serialize; + +/// Tries to convert a struct that implements serde's serialize into +/// an ordered `BorrowedValue` +/// +/// # Errors +/// +/// Will return `Err` if value fails to be turned into a borrowed ordered value +pub fn to_value<'se, T>(value: T) -> Result> +where + T: Serialize, +{ + value.serialize(se::Serializer::default()) +} diff --git a/src/serde/value/borrowed/ordered/de.rs b/src/serde/value/borrowed/ordered/de.rs new file mode 100644 index 00000000..b83544c5 --- /dev/null +++ b/src/serde/value/borrowed/ordered/de.rs @@ -0,0 +1,1024 @@ +// A lot of this logic is a re-implementation or copy of serde_json::Value +use crate::Error; +use crate::ObjectHasher; +use crate::{ErrorType, cow::Cow}; +use crate::{ + prelude::*, + serde::value::shared::MapKeyDeserializer, + value::borrowed::ordered::{Object, Value}, +}; +use serde_ext::{ + de::{ + self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, IntoDeserializer, MapAccess, + SeqAccess, VariantAccess, Visitor, + }, + forward_to_deserialize_any, +}; +use std::fmt; + +impl<'de> de::Deserializer<'de> for Value<'de> { + type Error = Error; + + // Look at the input data to decide what Serde data model type to + // deserialize as. Not all data formats are able to support this operation. + // Formats that support `deserialize_any` are known as self-describing. + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Static(StaticNode::Null) => visitor.visit_unit(), + Value::Static(StaticNode::Bool(b)) => visitor.visit_bool(b), + Value::Static(StaticNode::I64(n)) => visitor.visit_i64(n), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::I128(n)) => visitor.visit_i128(n), + Value::Static(StaticNode::U64(n)) => visitor.visit_u64(n), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::U128(n)) => visitor.visit_u128(n), + #[allow(clippy::useless_conversion)] // .into() required by ordered-float + Value::Static(StaticNode::F64(n)) => visitor.visit_f64(n.into()), + #[cfg(feature = "beef")] + Value::String(s) => { + if s.is_borrowed() { + visitor.visit_borrowed_str(s.unwrap_borrowed()) + } else { + visitor.visit_string(s.into_owned()) + } + } + #[cfg(not(feature = "beef"))] + Value::String(s) => match s { + Cow::Borrowed(s) => visitor.visit_borrowed_str(s), + Cow::Owned(s) => visitor.visit_string(s), + }, + + Value::Array(a) => visitor.visit_seq(Array(a.into_iter())), + Value::Object(o) => visitor.visit_map(ObjectAccess::new(o.into_iter())), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + if self == Value::Static(StaticNode::Null) { + visitor.visit_unit() + } else { + visitor.visit_some(self) + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn deserialize_enum( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let (variant, value) = match self { + Value::Object(value) => { + let mut iter = value.into_iter(); + let Some((variant, value)) = iter.next() else { + return Err(crate::Deserializer::error(ErrorType::Eof)); + }; + // enums are encoded in json as maps with a single key:value pair + if iter.next().is_some() { + return Err(crate::Deserializer::error(ErrorType::TrailingData)); + } + (variant, Some(value)) + } + Value::String(variant) => (variant, None), + other => { + return Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + Some(other.value_type()), + ))); + } + }; + + visitor.visit_enum(EnumDeserializer { variant, value }) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn deserialize_newtype_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self { + // Give the visitor access to each element of the sequence. + Value::Array(a) => visitor.visit_seq(Array(a.into_iter())), + Value::Object(o) => visitor.visit_map(ObjectAccess::new(o.into_iter())), + other => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + Some(other.value_type()), + ))), + } + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf unit unit_struct seq tuple + tuple_struct map identifier ignored_any + } +} + +struct Array<'de>(std::vec::IntoIter>); + +// `SeqAccess` is provided to the `Visitor` to give it the ability to iterate +// through elements of the sequence. +impl<'de> SeqAccess<'de> for Array<'de> { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: DeserializeSeed<'de>, + { + self.0 + .next() + .map_or(Ok(None), |v| seed.deserialize(v).map(Some)) + } +} + +struct ArrayRef<'de>(std::slice::Iter<'de, Value<'de>>); + +// `SeqAccess` is provided to the `Visitor` to give it the ability to iterate +// through elements of the sequence. +impl<'de> SeqAccess<'de> for ArrayRef<'de> { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: DeserializeSeed<'de>, + { + self.0 + .next() + .map_or(Ok(None), |v| seed.deserialize(v).map(Some)) + } +} + +struct ObjectAccess<'de> { + i: indexmap::map::IntoIter, Value<'de>>, + v: Option>, +} + +impl<'de> ObjectAccess<'de> { + fn new(i: indexmap::map::IntoIter, Value<'de>>) -> Self { + Self { i, v: None } + } +} + +// `MapAccess` is provided to the `Visitor` to give it the ability to iterate +// through entries of the map. +impl<'de> MapAccess<'de> for ObjectAccess<'de> { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> + where + K: DeserializeSeed<'de>, + { + match self.i.next() { + Some((k, v)) => { + self.v = Some(v); + seed.deserialize(Value::String(k)).map(Some) + } + _ => Ok(None), + } + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: DeserializeSeed<'de>, + { + match self.v.take() { + Some(v) => seed.deserialize(v), + None => Err(crate::Deserializer::error(ErrorType::Eof)), + } + } +} + +struct ObjectRefAccess<'de> { + i: indexmap::map::Iter<'de, Cow<'de, str>, Value<'de>>, + v: Option<&'de Value<'de>>, +} + +impl<'de> ObjectRefAccess<'de> { + fn new(i: indexmap::map::Iter<'de, Cow<'de, str>, Value<'de>>) -> Self { + Self { i, v: None } + } +} + +// `MapAccess` is provided to the `Visitor` to give it the ability to iterate +// through entries of the map. +impl<'de> MapAccess<'de> for ObjectRefAccess<'de> { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> + where + K: DeserializeSeed<'de>, + { + if let Some((k, v)) = self.i.next() { + self.v = Some(v); + let s: &str = k; + seed.deserialize(MapKeyDeserializer::borrowed(s)).map(Some) + } else { + Ok(None) + } + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: DeserializeSeed<'de>, + { + match self.v.take() { + Some(v) => seed.deserialize(v), + None => Err(crate::Deserializer::error(ErrorType::Eof)), + } + } +} + +impl<'de> Deserialize<'de> for Value<'de> { + fn deserialize(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(ValueVisitor) + } +} + +struct ValueVisitor; + +impl<'de> Visitor<'de> for ValueVisitor { + type Value = Value<'de>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("an JSONesque value") + } + + /****************** unit ******************/ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_unit(self) -> Result { + Ok(Value::Static(StaticNode::Null)) + } + + /****************** bool ******************/ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_bool(self, value: bool) -> Result { + Ok(Value::Static(StaticNode::Bool(value))) + } + + /****************** Option ******************/ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_none(self) -> Result { + Ok(Value::Static(StaticNode::Null)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(self) + } + + /****************** enum ******************/ + /* + fn visit_enum(self, data: A) -> Result where + A: EnumAccess<'de>, + { + } + */ + + /****************** i64 ******************/ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_i8(self, value: i8) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::I64(i64::from(value)))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_i16(self, value: i16) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::I64(i64::from(value)))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_i32(self, value: i32) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::I64(i64::from(value)))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_i64(self, value: i64) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::I64(value))) + } + + #[cfg(feature = "128bit")] + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_i128(self, value: i128) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::I128(value))) + } + + /****************** u64 ******************/ + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_u8(self, value: u8) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::U64(u64::from(value)))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_u16(self, value: u16) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::U64(u64::from(value)))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_u32(self, value: u32) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::U64(u64::from(value)))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_u64(self, value: u64) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::U64(value))) + } + + #[cfg(feature = "128bit")] + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_u128(self, value: u128) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::U128(value))) + } + + /****************** f64 ******************/ + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_f32(self, value: f32) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::from(f64::from(value)))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_f64(self, value: f64) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::from(value))) + } + + /****************** stringy stuff ******************/ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_char(self, value: char) -> Result + where + E: de::Error, + { + Ok(Value::from(value.to_string())) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_borrowed_str(self, value: &'de str) -> Result + where + E: de::Error, + { + Ok(Value::from(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + Ok(Value::String(value.to_owned().into())) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_string(self, value: String) -> Result + where + E: de::Error, + { + Ok(Value::String(value.into())) + } + + /****************** byte stuff ******************/ + + /* + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_borrowed_bytes(self, value: &'de [u8]) -> Result + where + E: de::Error, + { + Ok(Value::String(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_str(self, value: &[u8]) -> Result + where + 'a: 'de + E: de::Error, + { + Ok(Value::String(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_string(self, value: Vec) -> Result + where + E: de::Error, + { + Ok(Value::String(&value)) + } + */ + /****************** nexted stuff ******************/ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let size = map.size_hint().unwrap_or_default(); + + let mut m = Object::with_capacity_and_hasher(size, ObjectHasher::default()); + while let Some(k) = map.next_key::<&str>()? { + let v = map.next_value()?; + m.insert(k.into(), v); + } + Ok(Value::from(m)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let size = seq.size_hint().unwrap_or_default(); + + let mut v = Vec::with_capacity(size); + while let Some(e) = seq.next_element()? { + v.push(e); + } + Ok(Value::Array(Box::new(v))) + } +} + +struct EnumDeserializer<'de> { + variant: Cow<'de, str>, + value: Option>, +} + +impl<'de> EnumAccess<'de> for EnumDeserializer<'de> { + type Error = Error; + type Variant = VariantDeserializer<'de>; + + fn variant_seed(self, seed: V) -> Result<(V::Value, VariantDeserializer<'de>), Error> + where + V: DeserializeSeed<'de>, + { + let variant = self.variant.into_deserializer(); + let visitor = VariantDeserializer { value: self.value }; + seed.deserialize(variant).map(|v| (v, visitor)) + } +} + +impl<'de> IntoDeserializer<'de, Error> for Value<'de> { + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +struct VariantDeserializer<'de> { + value: Option>, +} + +impl<'de> VariantAccess<'de> for VariantDeserializer<'de> { + type Error = Error; + + fn unit_variant(self) -> Result<(), Error> { + match self.value { + Some(value) => Deserialize::deserialize(value), + None => Ok(()), + } + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.value { + Some(value) => seed.deserialize(value), + None => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + None, + ))), + } + } + + fn tuple_variant(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(Value::Array(v)) => { + if v.is_empty() { + visitor.visit_unit() + } else { + visitor.visit_seq(Array(v.into_iter())) + } + } + Some(other) => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Array), + Some(other.value_type()), + ))), + None => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Array), + None, + ))), + } + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(Value::Object(o)) => visitor.visit_map(ObjectAccess::new(o.into_iter())), + Some(other) => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + Some(other.value_type()), + ))), + None => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + None, + ))), + } + } +} + +impl<'de> de::Deserializer<'de> for &'de Value<'de> { + type Error = Error; + + // Look at the input data to decide what Serde data model type to + // deserialize as. Not all data formats are able to support this operation. + // Formats that support `deserialize_any` are known as self-describing. + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Static(StaticNode::Null) => visitor.visit_unit(), + Value::Static(StaticNode::Bool(b)) => visitor.visit_bool(*b), + Value::Static(StaticNode::I64(n)) => visitor.visit_i64(*n), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::I128(n)) => visitor.visit_i128(*n), + Value::Static(StaticNode::U64(n)) => visitor.visit_u64(*n), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::U128(n)) => visitor.visit_u128(*n), + #[allow(clippy::useless_conversion)] // .into() required by ordered-float + Value::Static(StaticNode::F64(n)) => visitor.visit_f64((*n).into()), + Value::String(s) => visitor.visit_borrowed_str(s), + Value::Array(a) => visitor.visit_seq(ArrayRef(a.as_slice().iter())), + Value::Object(o) => visitor.visit_map(ObjectRefAccess::new(o.iter())), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + if self == &Value::Static(StaticNode::Null) { + visitor.visit_unit() + } else { + visitor.visit_some(self) + } + } + #[cfg_attr(not(feature = "no-inline"), inline)] + fn deserialize_newtype_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self { + // Give the visitor access to each element of the sequence. + Value::Array(a) => visitor.visit_seq(ArrayRef(a.as_slice().iter())), + Value::Object(o) => visitor.visit_map(ObjectRefAccess::new(o.iter())), + other => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + Some(other.value_type()), + ))), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn deserialize_enum( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let (variant, value) = match self { + Value::Object(value) => { + let mut iter = value.iter(); + let Some((variant, value)) = iter.next() else { + return Err(crate::Deserializer::error(ErrorType::Eof)); + }; + // enums are encoded in json as maps with a single key:value pair + if iter.next().is_some() { + return Err(crate::Deserializer::error(ErrorType::TrailingData)); + } + (variant, Some(value)) + } + Value::String(variant) => (variant, None), + other => { + return Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + Some(other.value_type()), + ))); + } + }; + + visitor.visit_enum(EnumRefDeserializer { variant, value }) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf unit unit_struct seq tuple + tuple_struct map identifier ignored_any + } +} + +struct EnumRefDeserializer<'de> { + variant: &'de Cow<'de, str>, + value: Option<&'de Value<'de>>, +} + +impl<'de> EnumAccess<'de> for EnumRefDeserializer<'de> { + type Error = Error; + type Variant = VariantRefDeserializer<'de>; + + #[cfg(feature = "beef")] + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Error> + where + V: DeserializeSeed<'de>, + { + let variant = self.variant.into_deserializer(); + let visitor = VariantRefDeserializer { value: self.value }; + seed.deserialize(variant).map(|v| (v, visitor)) + } + #[cfg(not(feature = "beef"))] + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Error> + where + V: DeserializeSeed<'de>, + { + let var: &str = self.variant; + let variant = var.into_deserializer(); + let visitor = VariantRefDeserializer { value: self.value }; + seed.deserialize(variant).map(|v| (v, visitor)) + } +} +struct VariantRefDeserializer<'de> { + value: Option<&'de Value<'de>>, +} + +impl<'de> VariantAccess<'de> for VariantRefDeserializer<'de> { + type Error = Error; + + fn unit_variant(self) -> Result<(), Error> { + match self.value { + Some(value) => Deserialize::deserialize(value), + None => Ok(()), + } + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.value { + Some(value) => seed.deserialize(value), + None => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + None, + ))), + } + } + + fn tuple_variant(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(Value::Array(v)) => { + if v.is_empty() { + visitor.visit_unit() + } else { + visitor.visit_seq(ArrayRef(v.as_slice().iter())) + } + } + Some(other) => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Array), + Some(other.value_type()), + ))), + None => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Array), + None, + ))), + } + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(Value::Object(o)) => visitor.visit_map(ObjectRefAccess::new(o.iter())), + Some(other) => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + Some(other.value_type()), + ))), + None => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + None, + ))), + } + } +} + +#[cfg(test)] +mod test { + use serde::Deserialize; + + use crate::{borrowed, json, prelude::*}; + + #[test] + fn option_field_absent_owned() { + #[derive(serde::Deserialize, Debug, PartialEq, Eq)] + pub struct Person { + pub name: String, + pub middle_name: Option, + pub friends: Vec, + } + let mut raw_json = r#"{"name":"bob","friends":[]}"#.to_string(); + let result: Result = + crate::to_borrowed_value(unsafe { raw_json.as_bytes_mut() }) + .and_then(crate::serde::value::borrowed::from_value); + assert_eq!( + result, + Ok(Person { + name: "bob".to_string(), + middle_name: None, + friends: vec![] + }) + ); + } + #[test] + fn option_field_present_owned() { + #[derive(serde::Deserialize, Debug, PartialEq, Eq)] + pub struct Point { + pub x: u64, + pub y: u64, + } + #[derive(serde::Deserialize, Debug, PartialEq, Eq)] + pub struct Person { + pub name: String, + pub middle_name: Option, + pub friends: Vec, + pub pos: Point, + } + + let mut raw_json = + r#"{"name":"bob","middle_name": "frank", "friends":[], "pos":[0,1]}"#.to_string(); + let result: Result = + crate::to_borrowed_value(unsafe { raw_json.as_bytes_mut() }) + .and_then(crate::serde::value::borrowed::from_value); + assert_eq!( + result, + Ok(Person { + name: "bob".to_string(), + middle_name: Some("frank".to_string()), + friends: vec![], + pos: Point { x: 0, y: 1 }, + }) + ); + } + + #[test] + fn deserialize() { + use halfbrown::{HashMap, hashmap}; + #[derive(serde::Deserialize, Debug, PartialEq, Eq)] + #[serde(rename_all = "lowercase")] + pub enum Rotate { + Left, + Right, + Up, + Down, + } + #[derive(serde::Deserialize, Debug, PartialEq)] + pub struct Point { + pub x: i64, + pub y: i64, + pub z: f64, + pub rotate: Rotate, + } + #[derive(serde::Deserialize, Debug, PartialEq)] + pub struct Person { + pub name: String, + pub middle_name: Option, + pub friends: Vec, + pub pos: Point, + pub age: u64, + } + #[derive(serde::Deserialize, Debug, PartialEq, Eq)] + pub struct TestStruct { + pub key: HashMap, + pub vec: Vec>>, + } + + let mut raw_json = + r#"{"name":"bob","middle_name": "frank", "friends":[], "pos": [-1, 2, -3.25, "up"], "age": 123}"#.to_string(); + let value = + crate::to_borrowed_value(unsafe { raw_json.as_bytes_mut() }).expect("to_owned_value"); + let result: Person = crate::serde::value::borrowed::from_refvalue(&value).expect("from_refvalue"); + let expected = Person { + name: "bob".to_string(), + middle_name: Some("frank".to_string()), + friends: Vec::new(), + pos: Point { + x: -1, + y: 2, + z: -3.25_f64, + rotate: Rotate::Up, + }, + age: 123, + }; + assert_eq!(result, expected); + + let mut raw_json = r#"{"key":{"subkey": "value"}, "vec":[[null], [1]]}"#.to_string(); + let value = + crate::to_borrowed_value(unsafe { raw_json.as_bytes_mut() }).expect("to_owned_value"); + let result: TestStruct = crate::serde::value::borrowed::from_refvalue(&value).expect("from_refvalue"); + let expected = TestStruct { + key: hashmap!("subkey".to_string() => "value".to_string()), + vec: vec![vec![None], vec![Some(1)]], + }; + assert_eq!(result, expected); + } + + #[cfg(feature = "128bit")] + #[test] + fn deserialize_128bit() { + let value = i64::MIN as i128 - 1; + let int128 = crate::BorrowedValue::Static(crate::StaticNode::I128(value)); + let res: i128 = crate::serde::value::borrowed::from_refvalue(&int128).expect("from_refvalue"); + assert_eq!(value, res); + + let value = u64::MAX as u128; + let int128 = crate::BorrowedValue::Static(crate::StaticNode::U128(value)); + let res: u128 = crate::serde::value::borrowed::from_refvalue(&int128).expect("from_refvalue"); + assert_eq!(value, res); + } + + #[test] + fn variant() { + struct NameAndConfig<'v> { + name: String, + config: Option>, + } + impl<'v> serde::Deserialize<'v> for NameAndConfig<'v> { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'v>, + { + #[derive(Deserialize)] + // This is ugly but it's needed for `serde::Deserialize` to not explode on lifetimes + // An error like this is otherwise produced: + // error: lifetime may not live long enough + // --> src/serde/value/borrowed/de.rs:960:25 + // | + // 953 | #[derive(Deserialize)] + // | ----------- lifetime `'de` defined here + // ... + // 956 | enum Variants<'v> { + // | -- lifetime `'v` defined here + // ... + // 960 | config: Option>, + // | ^^^^^^ requires that `'de` must outlive `'v` + // | + // = help: consider adding the following bound: `'de: 'v` + + // error: lifetime may not live long enough + // --> src/serde/value/borrowed/de.rs:960:25 + // | + // 953 | #[derive(Deserialize)] + // | ----------- lifetime `'de` defined here + // ... + // 956 | enum Variants<'v> { + // | -- lifetime `'v` defined here + // ... + // 960 | config: Option>, + // | ^^^^^^ requires that `'v` must outlive `'de` + // | + // = help: consider adding the following bound: `'v: 'de` + #[serde(bound(deserialize = "'de: 'v, 'v: 'de"), untagged)] + enum Variants<'v> { + Name(String), + NameAndConfig { + name: String, + config: Option>, + }, + } + + let var = Variants::deserialize(deserializer)?; + + match var { + Variants::Name(name) => Ok(NameAndConfig { name, config: None }), + Variants::NameAndConfig { name, config } => Ok(NameAndConfig { name, config }), + } + } + } + + let v = json!({"name": "name", "config": 42}); + let nac = NameAndConfig::deserialize(v).expect("could structurize two element struct"); + assert_eq!(nac.name, "name"); + assert_eq!(nac.config.as_u8(), Some(42)); + let v = json!({"name": "name"}); + let nac = NameAndConfig::deserialize(v).expect("could structurize one element struct"); + assert_eq!(nac.name, "name"); + assert_eq!(nac.config, None); + let v = json!("name"); + let nac = NameAndConfig::deserialize(v).expect("could structurize string"); + assert_eq!(nac.name, "name"); + assert_eq!(nac.config, None); + } +} diff --git a/src/serde/value/borrowed/ordered/se.rs b/src/serde/value/borrowed/ordered/se.rs new file mode 100644 index 00000000..ef22ad7c --- /dev/null +++ b/src/serde/value/borrowed/ordered/se.rs @@ -0,0 +1,798 @@ +use super::to_value; +use crate::{ + Error, ErrorType, Result, + cow::Cow, + macros::stry, + value::borrowed::ordered::{Object, Value}, +}; +use crate::{ObjectHasher, StaticNode}; +use serde_ext::ser::{ + self, Serialize, SerializeMap as SerializeMapTrait, SerializeSeq as SerializeSeqTrait, +}; +use std::marker::PhantomData; + +type Impossible = ser::Impossible; + +impl Serialize for Value<'_> { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: ser::Serializer, + { + match self { + Value::Static(StaticNode::Null) => serializer.serialize_unit(), + Value::Static(StaticNode::Bool(b)) => serializer.serialize_bool(*b), + #[allow(clippy::useless_conversion)] // .into() required by ordered-float + Value::Static(StaticNode::F64(f)) => serializer.serialize_f64((*f).into()), + Value::Static(StaticNode::U64(i)) => serializer.serialize_u64(*i), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::U128(i)) => serializer.serialize_u128(*i), + Value::Static(StaticNode::I64(i)) => serializer.serialize_i64(*i), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::I128(i)) => serializer.serialize_i128(*i), + Value::String(s) => serializer.serialize_str(s), + Value::Array(v) => { + let mut seq = serializer.serialize_seq(Some(v.len()))?; + for e in v.as_ref() { + seq.serialize_element(e)?; + } + seq.end() + } + Value::Object(m) => { + let mut map = serializer.serialize_map(Some(m.len()))?; + for (k, v) in m.iter() { + let k: &str = k; + map.serialize_entry(k, v)?; + } + map.end() + } + } + } +} + +pub struct Serializer<'se> { + marker: PhantomData<&'se u8>, +} + +impl Default for Serializer<'_> { + fn default() -> Self { + Self { + marker: PhantomData, + } + } +} + +impl<'se> serde::Serializer for Serializer<'se> { + type Ok = Value<'se>; + type Error = Error; + + type SerializeSeq = SerializeVec<'se>; + type SerializeTuple = SerializeVec<'se>; + type SerializeTupleStruct = SerializeVec<'se>; + type SerializeTupleVariant = SerializeTupleVariant<'se>; + type SerializeMap = SerializeMap<'se>; + type SerializeStruct = SerializeMap<'se>; + type SerializeStructVariant = SerializeStructVariant<'se>; + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_bool(self, value: bool) -> Result> { + Ok(Value::Static(StaticNode::Bool(value))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_i8(self, value: i8) -> Result> { + self.serialize_i64(i64::from(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_i16(self, value: i16) -> Result> { + self.serialize_i64(i64::from(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_i32(self, value: i32) -> Result> { + self.serialize_i64(i64::from(value)) + } + + fn serialize_i64(self, value: i64) -> Result> { + Ok(Value::Static(StaticNode::I64(value))) + } + + #[cfg(feature = "128bit")] + fn serialize_i128(self, value: i128) -> Result> { + Ok(Value::Static(StaticNode::I128(value))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_u8(self, value: u8) -> Result> { + self.serialize_u64(u64::from(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_u16(self, value: u16) -> Result> { + self.serialize_u64(u64::from(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_u32(self, value: u32) -> Result> { + self.serialize_u64(u64::from(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_u64(self, value: u64) -> Result> { + Ok(Value::Static(StaticNode::U64(value))) + } + + #[cfg(feature = "128bit")] + fn serialize_u128(self, value: u128) -> Result> { + Ok(Value::Static(StaticNode::U128(value))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_f32(self, value: f32) -> Result> { + self.serialize_f64(f64::from(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_f64(self, value: f64) -> Result> { + Ok(Value::Static(StaticNode::from(value))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_char(self, value: char) -> Result> { + let mut s = String::new(); + s.push(value); + self.serialize_str(&s) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_str(self, value: &str) -> Result> { + Ok(Value::from(value.to_owned())) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_bytes(self, value: &[u8]) -> Result> { + Ok(value.iter().copied().collect()) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_unit(self) -> Result> { + Ok(Value::Static(StaticNode::Null)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_unit_struct(self, _name: &'static str) -> Result> { + self.serialize_unit() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result> { + self.serialize_str(variant) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result> + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result> + where + T: ?Sized + Serialize, + { + let mut values = Object::with_capacity_and_hasher(1, ObjectHasher::default()); + let x = stry!(to_value(value)); + #[cfg(not(feature = "preserve_order"))] + unsafe { + values.insert_nocheck(variant.into(), x); + }; + #[cfg(feature = "preserve_order")] + values.insert(variant.into(), x); + Ok(Value::from(values)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_none(self) -> Result> { + self.serialize_unit() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_some(self, value: &T) -> Result> + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_seq(self, len: Option) -> Result { + Ok(SerializeVec { + vec: Vec::with_capacity(len.unwrap_or(0)), + }) + } + + fn serialize_tuple(self, len: usize) -> Result { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + Ok(SerializeTupleVariant { + name: variant, + vec: Vec::with_capacity(len), + }) + } + + fn serialize_map(self, len: Option) -> Result { + Ok(SerializeMap { + map: Object::with_capacity_and_hasher(len.unwrap_or(0), ObjectHasher::default()), + next_key: None, + }) + } + + fn serialize_struct(self, _name: &'static str, len: usize) -> Result { + self.serialize_map(Some(len)) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + Ok(SerializeStructVariant { + name: variant, + map: Object::with_capacity_and_hasher(len, ObjectHasher::default()), + }) + } +} + +pub struct SerializeVec<'se> { + vec: Vec>, +} + +pub struct SerializeTupleVariant<'se> { + name: &'se str, + vec: Vec>, +} + +pub struct SerializeMap<'se> { + map: Object<'se>, + next_key: Option>, +} + +pub struct SerializeStructVariant<'se> { + name: &'se str, + map: Object<'se>, +} + +impl<'se> serde::ser::SerializeSeq for SerializeVec<'se> { + type Ok = Value<'se>; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + self.vec.push(stry!(to_value(value))); + Ok(()) + } + + fn end(self) -> Result> { + Ok(Value::Array(Box::new(self.vec))) + } +} + +impl<'se> serde::ser::SerializeTuple for SerializeVec<'se> { + type Ok = Value<'se>; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + serde::ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result> { + serde::ser::SerializeSeq::end(self) + } +} + +impl<'se> serde::ser::SerializeTupleStruct for SerializeVec<'se> { + type Ok = Value<'se>; + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + serde::ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result> { + serde::ser::SerializeSeq::end(self) + } +} + +impl<'se> serde::ser::SerializeTupleVariant for SerializeTupleVariant<'se> { + type Ok = Value<'se>; + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + self.vec.push(stry!(to_value(value))); + Ok(()) + } + + fn end(self) -> Result> { + let mut object = Object::with_capacity_and_hasher(1, ObjectHasher::default()); + #[cfg(not(feature = "preserve_order"))] + unsafe { + object.insert_nocheck(self.name.into(), Value::Array(Box::new(self.vec))) + }; + #[cfg(feature = "preserve_order")] + object.insert(self.name.into(), Value::Array(Box::new(self.vec))); + + Ok(Value::Object(Box::new(object))) + } +} + +impl<'se> serde::ser::SerializeMap for SerializeMap<'se> { + type Ok = Value<'se>; + type Error = Error; + + fn serialize_key(&mut self, key: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + self.next_key = Some(stry!(key.serialize(MapKeySerializer { + marker: PhantomData + }))); + Ok(()) + } + + fn serialize_value(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + let key = self.next_key.take(); + // Panic because this indicates a bug in the program rather than an + // expected failure. + let key = key.expect("serialize_value called before serialize_key"); + self.map.insert(key, stry!(to_value(value))); + Ok(()) + } + + fn end(self) -> Result> { + Ok(Value::Object(Box::new(self.map))) + } +} + +struct MapKeySerializer<'se> { + marker: PhantomData<&'se u8>, +} + +fn key_must_be_a_string() -> Error { + Error::generic(ErrorType::KeyMustBeAString) +} + +impl<'se> serde_ext::Serializer for MapKeySerializer<'se> { + type Ok = Cow<'se, str>; + type Error = Error; + + type SerializeSeq = Impossible>; + type SerializeTuple = Impossible>; + type SerializeTupleStruct = Impossible>; + type SerializeTupleVariant = Impossible>; + type SerializeMap = Impossible>; + type SerializeStruct = Impossible>; + type SerializeStructVariant = Impossible>; + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result { + Ok(Cow::from(variant)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_bool(self, _value: bool) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_i8(self, value: i8) -> Result { + Ok(value.to_string().into()) + } + + fn serialize_i16(self, value: i16) -> Result { + Ok(value.to_string().into()) + } + + fn serialize_i32(self, value: i32) -> Result { + Ok(value.to_string().into()) + } + + fn serialize_i64(self, value: i64) -> Result { + Ok(value.to_string().into()) + } + + fn serialize_u8(self, value: u8) -> Result { + Ok(value.to_string().into()) + } + + fn serialize_u16(self, value: u16) -> Result { + Ok(value.to_string().into()) + } + + fn serialize_u32(self, value: u32) -> Result { + Ok(value.to_string().into()) + } + + fn serialize_u64(self, value: u64) -> Result { + Ok(value.to_string().into()) + } + + fn serialize_f32(self, _value: f32) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_f64(self, _value: f64) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_char(self, value: char) -> Result { + Ok({ + let mut s = String::new(); + s.push(value); + s.into() + }) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_str(self, value: &str) -> Result { + // TODO: we copy `value` here this is not idea but safe + Ok(Cow::from(value.to_string())) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_unit(self) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + Err(key_must_be_a_string()) + } + + fn serialize_none(self) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_some(self, _value: &T) -> Result + where + T: ?Sized + Serialize, + { + Err(key_must_be_a_string()) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } +} + +impl<'se> serde::ser::SerializeStruct for SerializeMap<'se> { + type Ok = Value<'se>; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + stry!(serde::ser::SerializeMap::serialize_key(self, key)); + serde::ser::SerializeMap::serialize_value(self, value) + } + + fn end(self) -> Result> { + serde::ser::SerializeMap::end(self) + } +} + +impl<'se> serde::ser::SerializeStructVariant for SerializeStructVariant<'se> { + type Ok = Value<'se>; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + self.map.insert(key.into(), stry!(to_value(value))); + Ok(()) + } + + fn end(self) -> Result> { + let mut object = Object::with_capacity_and_hasher(1, ObjectHasher::default()); + #[cfg(not(feature = "preserve_order"))] + unsafe { + object.insert_nocheck(self.name.into(), self.map.into()) + }; + #[cfg(feature = "preserve_order")] + object.insert(self.name.into(), self.map.into()); + Ok(Value::Object(Box::new(object))) + } +} + +#[cfg(test)] +mod test { + #![allow(clippy::ignored_unit_patterns)] + use super::Value; + use crate::{ObjectHasher, borrowed::Object, serde::from_slice}; + use serde::{Deserialize, Serialize}; + use value_trait::StaticNode; + + #[test] + fn null() { + let v = Value::Static(crate::StaticNode::Null); + let s = serde_json::to_string(&v).expect("Failed to serialize"); + assert_eq!(s, "null"); + } + + #[test] + fn bool_true() { + let v = Value::Static(StaticNode::Bool(true)); + let s = serde_json::to_string(&v).expect("Failed to serialize"); + assert_eq!(s, "true"); + } + + #[test] + fn bool_false() { + let v = Value::Static(StaticNode::Bool(false)); + let s = serde_json::to_string(&v).expect("Failed to serialize"); + assert_eq!(s, "false"); + } + + #[test] + fn float() { + let v = Value::Static(StaticNode::from(1.0)); + let s = serde_json::to_string(&v).expect("Failed to serialize"); + assert_eq!(s, "1.0"); + } + + #[test] + fn stringlike() { + let v = Value::from("snot".to_string()); + let s = serde_json::to_string(&v).expect("Failed to serialize"); + assert_eq!(s, "\"snot\""); + + let v = Value::from("snot"); + let s = serde_json::to_string(&v).expect("Failed to serialize"); + assert_eq!(s, "\"snot\""); + } + + #[test] + fn int() { + let v = Value::Static(StaticNode::I64(42)); + let s = serde_json::to_string(&v).expect("Failed to serialize"); + assert_eq!(s, "42"); + } + + #[test] + fn arr() { + let v = Value::Array(Box::new(vec![ + Value::Static(StaticNode::I64(42)), + Value::Static(StaticNode::I64(23)), + ])); + let s = serde_json::to_string(&v).expect("Failed to serialize"); + assert_eq!(s, "[42,23]"); + } + + #[test] + fn map() { + let mut m = Object::with_capacity_and_hasher(2, ObjectHasher::default()); + m.insert("a".into(), Value::from(42)); + m.insert("b".into(), Value::from(23)); + let v = Value::Object(Box::new(m)); + let mut s = serde_json::to_vec(&v).expect("Failed to serialize"); + let v2: Value = from_slice(&mut s).expect("failed to deserialize"); + assert_eq!(v, v2); + } + + #[derive(Deserialize, Serialize, PartialEq, Debug, Default)] + struct Map { + key: u32, + } + #[allow(clippy::struct_field_names)] + #[derive(Deserialize, Serialize, PartialEq, Debug, Default)] + struct Obj { + v_i128: i128, + v_i64: i64, + v_i32: i32, + v_i16: i16, + v_i8: i8, + v_u128: u128, + v_u64: u64, + v_usize: usize, + v_u32: u32, + v_u16: u16, + v_u8: u8, + v_bool: bool, + v_str: String, + v_char: char, + //v_enum: Enum, + v_map: Map, + v_arr: Vec, + v_null: (), + } + + #[test] + fn from_slice_to_object() { + let o = Obj::default(); + let mut vec = serde_json::to_vec(&o).expect("to_vec"); + let vec2 = crate::serde::to_vec(&o).expect("to_vec"); + assert_eq!(vec, vec2); + + println!("{}", serde_json::to_string_pretty(&o).expect("json")); + let de: Obj = from_slice(&mut vec).expect("from_slice"); + assert_eq!(o, de); + } + + #[cfg(not(target_arch = "wasm32"))] + use proptest::prelude::*; + #[cfg(not(target_arch = "wasm32"))] + prop_compose! { + fn obj_case()( + v_i128 in any::().prop_map(i128::from), + v_i64 in any::(), + v_i32 in any::(), + v_i16 in any::(), + v_i8 in any::(), + v_u128 in any::().prop_map(u128::from), + v_u64 in any::(), + v_usize in any::().prop_map(|v| v as usize), + v_u32 in any::(), + v_u16 in any::(), + v_u8 in any::(), + v_bool in any::(), + v_str in ".*", + v_char in any::(), + ) -> Obj { + Obj { + v_i128, + v_i64, + v_i32, + v_i16, + v_i8, + v_u128, + v_u64, + v_usize, + v_u32, + v_u16, + v_u8, + v_bool, + v_str, + v_char, + ..Obj::default() + } + } + } + + #[cfg(not(target_arch = "wasm32"))] + proptest! { + #![proptest_config(ProptestConfig { + .. ProptestConfig::default() + })] + + #[test] + fn prop_deserialize_obj(obj in obj_case()) { + let mut vec = serde_json::to_vec(&obj).expect("to_vec"); + let vec1 = vec.clone(); + let vec2 = vec.clone(); + println!("{}", serde_json::to_string_pretty(&obj).expect("json")); + let de: Obj = from_slice(&mut vec).expect("from_slice"); + prop_assert_eq!(&obj, &de); + + let borrowed: crate::BorrowedValue = serde_json::from_slice(& vec1).expect("from_slice"); + let owned: crate::OwnedValue = serde_json::from_slice(& vec2).expect("from_slice"); + prop_assert_eq!(&borrowed, &owned); + + let de: Obj = Obj::deserialize(borrowed).expect("deserialize"); + prop_assert_eq!(&obj, &de); + let de: Obj = Obj::deserialize(owned).expect("deserialize"); + prop_assert_eq!(&obj, &de); + + + } + } +} diff --git a/src/serde/value/borrowed/se.rs b/src/serde/value/borrowed/se.rs index b485b753..a9b653ba 100644 --- a/src/serde/value/borrowed/se.rs +++ b/src/serde/value/borrowed/se.rs @@ -194,7 +194,12 @@ impl<'se> serde::Serializer for Serializer<'se> { { let mut values = Object::with_capacity_and_hasher(1, ObjectHasher::default()); let x = stry!(to_value(value)); - unsafe { values.insert_nocheck(variant.into(), x) }; + #[cfg(not(feature = "preserve_order"))] + unsafe { + values.insert_nocheck(variant.into(), x); + }; + #[cfg(feature = "preserve_order")] + values.insert(variant.into(), x); Ok(Value::from(values)) } @@ -349,7 +354,12 @@ impl<'se> serde::ser::SerializeTupleVariant for SerializeTupleVariant<'se> { fn end(self) -> Result> { let mut object = Object::with_capacity_and_hasher(1, ObjectHasher::default()); - unsafe { object.insert_nocheck(self.name.into(), Value::Array(Box::new(self.vec))) }; + #[cfg(not(feature = "preserve_order"))] + unsafe { + object.insert_nocheck(self.name.into(), Value::Array(Box::new(self.vec))) + }; + #[cfg(feature = "preserve_order")] + object.insert(self.name.into(), Value::Array(Box::new(self.vec))); Ok(Value::Object(Box::new(object))) } @@ -594,7 +604,12 @@ impl<'se> serde::ser::SerializeStructVariant for SerializeStructVariant<'se> { fn end(self) -> Result> { let mut object = Object::with_capacity_and_hasher(1, ObjectHasher::default()); - unsafe { object.insert_nocheck(self.name.into(), self.map.into()) }; + #[cfg(not(feature = "preserve_order"))] + unsafe { + object.insert_nocheck(self.name.into(), self.map.into()) + }; + #[cfg(feature = "preserve_order")] + object.insert(self.name.into(), self.map.into()); Ok(Value::Object(Box::new(object))) } } diff --git a/src/serde/value/owned.rs b/src/serde/value/owned.rs index ce48a399..7e1e4fa4 100644 --- a/src/serde/value/owned.rs +++ b/src/serde/value/owned.rs @@ -1,5 +1,7 @@ mod de; mod se; +#[cfg(feature = "preserve_order")] +pub mod ordered; use crate::OwnedValue; use crate::Result; diff --git a/src/serde/value/owned/de.rs b/src/serde/value/owned/de.rs index ca92c759..9ce8f496 100644 --- a/src/serde/value/owned/de.rs +++ b/src/serde/value/owned/de.rs @@ -174,6 +174,7 @@ impl ObjectAccess { Self { i, v: None } } } + // `MapAccess` is provided to the `Visitor` to give it the ability to iterate // through entries of the map. impl<'de> MapAccess<'de> for ObjectAccess { diff --git a/src/serde/value/owned/ordered.rs b/src/serde/value/owned/ordered.rs new file mode 100644 index 00000000..ed906756 --- /dev/null +++ b/src/serde/value/owned/ordered.rs @@ -0,0 +1,19 @@ +mod de; +mod se; + +use crate::value::owned::ordered::Value; +use crate::Result; +use serde_ext::ser::Serialize; + +/// Tries to convert a struct that implements serde's serialize into +/// an ordered `OwnedValue` +/// +/// # Errors +/// +/// Will return `Err` if value fails to be turned into an owned ordered value +pub fn to_value(value: T) -> Result +where + T: Serialize, +{ + value.serialize(se::Serializer::default()) +} diff --git a/src/serde/value/owned/ordered/de.rs b/src/serde/value/owned/ordered/de.rs new file mode 100644 index 00000000..cc5f5c19 --- /dev/null +++ b/src/serde/value/owned/ordered/de.rs @@ -0,0 +1,969 @@ +// A lot of this logic is a re-implementation or copy of serde_json::Value +use crate::ErrorType; +use crate::{Error, ObjectHasher}; +use crate::{ + prelude::*, + serde::value::shared::MapKeyDeserializer, + value::owned::ordered::{Object, Value}, +}; +use serde_ext::{ + de::{ + self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, IntoDeserializer, MapAccess, + SeqAccess, VariantAccess, Visitor, + }, + forward_to_deserialize_any, +}; +use std::fmt; + +impl<'de> de::Deserializer<'de> for Value { + type Error = Error; + + // Look at the input data to decide what Serde data model type to + // deserialize as. Not all data formats are able to support this operation. + // Formats that support `deserialize_any` are known as self-describing. + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Static(StaticNode::Null) => visitor.visit_unit(), + Value::Static(StaticNode::Bool(b)) => visitor.visit_bool(b), + Value::Static(StaticNode::I64(n)) => visitor.visit_i64(n), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::I128(n)) => visitor.visit_i128(n), + Value::Static(StaticNode::U64(n)) => visitor.visit_u64(n), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::U128(n)) => visitor.visit_u128(n), + #[allow(clippy::useless_conversion)] // .into() required by ordered-float + Value::Static(StaticNode::F64(n)) => visitor.visit_f64(n.into()), + Value::String(s) => visitor.visit_string(s), + Value::Array(a) => visitor.visit_seq(Array(a.into_iter())), + Value::Object(o) => visitor.visit_map(ObjectAccess { + i: o.into_iter(), + v: None, + }), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + if self == Value::Static(StaticNode::Null) { + visitor.visit_unit() + } else { + visitor.visit_some(self) + } + } + #[cfg_attr(not(feature = "no-inline"), inline)] + fn deserialize_enum( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let (variant, value) = match self { + Value::Object(value) => { + let mut iter = value.into_iter(); + let Some((variant, value)) = iter.next() else { + return Err(crate::Deserializer::error(ErrorType::Eof)); + }; + // enums are encoded in json as maps with a single key:value pair + if iter.next().is_some() { + return Err(crate::Deserializer::error(ErrorType::TrailingData)); + } + (variant, Some(value)) + } + Value::String(variant) => (variant, None), + other => { + return Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + Some(other.value_type()), + ))); + } + }; + + visitor.visit_enum(EnumDeserializer { variant, value }) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn deserialize_newtype_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self { + // Give the visitor access to each element of the sequence. + Value::Array(a) => visitor.visit_seq(Array(a.into_iter())), + Value::Object(o) => visitor.visit_map(ObjectAccess::new(o.into_iter())), + other => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + Some(other.value_type()), + ))), + } + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf unit unit_struct seq tuple + tuple_struct map identifier ignored_any + } +} + +struct Array(std::vec::IntoIter); + +// `SeqAccess` is provided to the `Visitor` to give it the ability to iterate +// through elements of the sequence. +impl<'de> SeqAccess<'de> for Array { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: DeserializeSeed<'de>, + { + self.0 + .next() + .map_or(Ok(None), |v| seed.deserialize(v).map(Some)) + } +} + +struct ArrayRef<'de>(std::slice::Iter<'de, Value>); + +// `SeqAccess` is provided to the `Visitor` to give it the ability to iterate +// through elements of the sequence. +impl<'de> SeqAccess<'de> for ArrayRef<'de> { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: DeserializeSeed<'de>, + { + self.0 + .next() + .map_or(Ok(None), |v| seed.deserialize(v).map(Some)) + } +} + +struct ObjectAccess { + i: indexmap::map::IntoIter, + v: Option, +} + +impl ObjectAccess { + fn new(i: indexmap::map::IntoIter) -> Self { + Self { i, v: None } + } +} + +// `MapAccess` is provided to the `Visitor` to give it the ability to iterate +// through entries of the map. +impl<'de> MapAccess<'de> for ObjectAccess { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> + where + K: DeserializeSeed<'de>, + { + match self.i.next() { + Some((k, v)) => { + self.v = Some(v); + seed.deserialize(Value::String(k)).map(Some) + } + _ => Ok(None), + } + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: DeserializeSeed<'de>, + { + match self.v.take() { + Some(v) => seed.deserialize(v), + None => Err(crate::Deserializer::error(ErrorType::Eof)), + } + } +} + +struct ObjectRefAccess<'de> { + i: indexmap::map::Iter<'de, String, Value>, + v: Option<&'de Value>, +} + +impl<'de> ObjectRefAccess<'de> { + fn new(i: indexmap::map::Iter<'de, String, Value>) -> Self { + Self { i, v: None } + } +} + +// `MapAccess` is provided to the `Visitor` to give it the ability to iterate +// through entries of the map. +impl<'de> MapAccess<'de> for ObjectRefAccess<'de> { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> + where + K: DeserializeSeed<'de>, + { + if let Some((k, v)) = self.i.next() { + self.v = Some(v); + seed.deserialize(MapKeyDeserializer::borrowed(k)).map(Some) + } else { + Ok(None) + } + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: DeserializeSeed<'de>, + { + match self.v.take() { + Some(v) => seed.deserialize(v), + None => Err(crate::Deserializer::error(ErrorType::Eof)), + } + } +} + +impl<'de> Deserialize<'de> for Value { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(ValueVisitor) + } +} + +struct ValueVisitor; + +impl<'de> Visitor<'de> for ValueVisitor { + type Value = Value; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a JSONesque value") + } + + /****************** unit ******************/ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_unit(self) -> Result { + Ok(Value::Static(StaticNode::Null)) + } + + /****************** bool ******************/ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_bool(self, value: bool) -> Result { + Ok(Value::Static(StaticNode::Bool(value))) + } + + /****************** Option ******************/ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_none(self) -> Result { + Ok(Value::Static(StaticNode::Null)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(self) + } + + /****************** enum ******************/ + /* + fn visit_enum(self, data: A) -> Result where + A: EnumAccess<'de>, + { + } + */ + + /****************** i64 ******************/ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_i8(self, value: i8) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::I64(i64::from(value)))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_i16(self, value: i16) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::I64(i64::from(value)))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_i32(self, value: i32) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::I64(i64::from(value)))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_i64(self, value: i64) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::I64(value))) + } + + #[cfg(feature = "128bit")] + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_i128(self, value: i128) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::I128(value))) + } + + /****************** u64 ******************/ + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_u8(self, value: u8) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::U64(u64::from(value)))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_u16(self, value: u16) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::U64(u64::from(value)))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_u32(self, value: u32) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::U64(u64::from(value)))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_u64(self, value: u64) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::U64(value))) + } + + #[cfg(feature = "128bit")] + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_u128(self, value: u128) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::U128(value))) + } + /****************** f64 ******************/ + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_f32(self, value: f32) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::from(f64::from(value)))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_f64(self, value: f64) -> Result + where + E: de::Error, + { + Ok(Value::Static(StaticNode::from(value))) + } + + /****************** stringy stuff ******************/ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_char(self, value: char) -> Result + where + E: de::Error, + { + Ok(Value::from(value.to_string())) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_borrowed_str(self, value: &'de str) -> Result + where + E: de::Error, + { + Ok(Value::from(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + Ok(Value::String(value.to_owned())) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_string(self, value: String) -> Result + where + E: de::Error, + { + Ok(Value::String(value)) + } + + /****************** byte stuff ******************/ + + /* + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_borrowed_bytes(self, value: &'de [u8]) -> Result + where + E: de::Error, + { + Ok(Value::String(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_str(self, value: &[u8]) -> Result + where + 'a: 'de + E: de::Error, + { + Ok(Value::String(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_string(self, value: Vec) -> Result + where + E: de::Error, + { + Ok(Value::String(&value)) + } + */ + /****************** nexted stuff ******************/ + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let size = map.size_hint().unwrap_or_default(); + + let mut m = Object::with_capacity_and_hasher(size, ObjectHasher::default()); + while let Some(k) = map.next_key()? { + let v = map.next_value()?; + m.insert(k, v); + } + Ok(Value::from(m)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let size = seq.size_hint().unwrap_or_default(); + + let mut v = Vec::with_capacity(size); + while let Some(e) = seq.next_element()? { + v.push(e); + } + Ok(Value::Array(Box::new(v))) + } +} + +struct EnumDeserializer { + variant: String, + value: Option, +} + +impl<'de> EnumAccess<'de> for EnumDeserializer { + type Error = Error; + type Variant = VariantDeserializer; + + fn variant_seed(self, seed: V) -> Result<(V::Value, VariantDeserializer), Error> + where + V: DeserializeSeed<'de>, + { + let variant = self.variant.into_deserializer(); + let visitor = VariantDeserializer { value: self.value }; + seed.deserialize(variant).map(|v| (v, visitor)) + } +} + +impl IntoDeserializer<'_, Error> for Value { + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +struct VariantDeserializer { + value: Option, +} + +impl<'de> VariantAccess<'de> for VariantDeserializer { + type Error = Error; + + fn unit_variant(self) -> Result<(), Error> { + match self.value { + Some(value) => Deserialize::deserialize(value), + None => Ok(()), + } + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.value { + Some(value) => seed.deserialize(value), + None => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + None, + ))), + } + } + + fn tuple_variant(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(Value::Array(v)) => { + if v.is_empty() { + visitor.visit_unit() + } else { + visitor.visit_seq(Array(v.into_iter())) + } + } + Some(other) => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Array), + Some(other.value_type()), + ))), + None => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Array), + None, + ))), + } + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(Value::Object(o)) => visitor.visit_map(ObjectAccess::new(o.into_iter())), + Some(other) => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + Some(other.value_type()), + ))), + None => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + None, + ))), + } + } +} + +impl<'de> de::Deserializer<'de> for &'de Value { + type Error = Error; + + // Look at the input data to decide what Serde data model type to + // deserialize as. Not all data formats are able to support this operation. + // Formats that support `deserialize_any` are known as self-describing. + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Static(StaticNode::Null) => visitor.visit_unit(), + Value::Static(StaticNode::Bool(b)) => visitor.visit_bool(*b), + Value::Static(StaticNode::I64(n)) => visitor.visit_i64(*n), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::I128(n)) => visitor.visit_i128(*n), + Value::Static(StaticNode::U64(n)) => visitor.visit_u64(*n), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::U128(n)) => visitor.visit_u128(*n), + #[allow(clippy::useless_conversion)] // .into() required by ordered-float + Value::Static(StaticNode::F64(n)) => visitor.visit_f64((*n).into()), + Value::String(s) => visitor.visit_borrowed_str(s), + Value::Array(a) => visitor.visit_seq(ArrayRef(a.as_slice().iter())), + Value::Object(o) => visitor.visit_map(ObjectRefAccess::new(o.iter())), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + if self == &Value::Static(StaticNode::Null) { + visitor.visit_unit() + } else { + visitor.visit_some(self) + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn deserialize_newtype_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self { + // Give the visitor access to each element of the sequence. + Value::Array(a) => visitor.visit_seq(ArrayRef(a.as_slice().iter())), + Value::Object(o) => visitor.visit_map(ObjectRefAccess::new(o.iter())), + other => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + Some(other.value_type()), + ))), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn deserialize_enum( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let (variant, value) = match self { + Value::Object(value) => { + let mut iter = value.iter(); + let Some((variant, value)) = iter.next() else { + return Err(crate::Deserializer::error(ErrorType::Eof)); + }; + // enums are encoded in json as maps with a single key:value pair + if iter.next().is_some() { + return Err(crate::Deserializer::error(ErrorType::TrailingData)); + } + (variant, Some(value)) + } + Value::String(variant) => (variant, None), + other => { + return Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + Some(other.value_type()), + ))); + } + }; + + visitor.visit_enum(EnumRefDeserializer { variant, value }) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf unit unit_struct seq tuple + tuple_struct map identifier ignored_any + } +} + +struct EnumRefDeserializer<'de> { + variant: &'de str, + value: Option<&'de Value>, +} + +impl<'de> EnumAccess<'de> for EnumRefDeserializer<'de> { + type Error = Error; + type Variant = VariantRefDeserializer<'de>; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Error> + where + V: DeserializeSeed<'de>, + { + let variant = self.variant.into_deserializer(); + let visitor = VariantRefDeserializer { value: self.value }; + seed.deserialize(variant).map(|v| (v, visitor)) + } +} +struct VariantRefDeserializer<'de> { + value: Option<&'de Value>, +} + +impl<'de> VariantAccess<'de> for VariantRefDeserializer<'de> { + type Error = Error; + + fn unit_variant(self) -> Result<(), Error> { + match self.value { + Some(value) => Deserialize::deserialize(value), + None => Ok(()), + } + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.value { + Some(value) => seed.deserialize(value), + None => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + None, + ))), + } + } + + fn tuple_variant(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(Value::Array(v)) => { + if v.is_empty() { + visitor.visit_unit() + } else { + visitor.visit_seq(ArrayRef(v.as_slice().iter())) + } + } + Some(other) => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Array), + Some(other.value_type()), + ))), + None => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Array), + None, + ))), + } + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(Value::Object(o)) => visitor.visit_map(ObjectRefAccess::new(o.iter())), + Some(other) => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + Some(other.value_type()), + ))), + None => Err(crate::Deserializer::error(ErrorType::Unexpected( + Some(ValueType::Object), + None, + ))), + } + } +} + +#[cfg(test)] +mod test { + use crate::{json, owned, prelude::*}; + use serde::Deserialize; + + #[test] + fn option_field_absent_owned() { + #[derive(serde::Deserialize, Debug, PartialEq, Eq)] + pub struct Person { + pub name: String, + pub middle_name: Option, + pub friends: Vec, + } + let mut raw_json = r#"{"name":"bob","friends":[]}"#.to_string(); + let result: Result = crate::to_owned_value(unsafe { raw_json.as_bytes_mut() }) + .and_then(crate::serde::value::owned::from_value); + assert_eq!( + result, + Ok(Person { + name: "bob".to_string(), + middle_name: None, + friends: vec![] + }) + ); + } + #[test] + fn option_field_present_owned() { + #[derive(serde::Deserialize, Debug, PartialEq, Eq)] + pub struct Point { + pub x: u64, + pub y: u64, + } + #[derive(serde::Deserialize, Debug, PartialEq, Eq)] + pub struct Person { + pub name: String, + pub middle_name: Option, + pub friends: Vec, + pub pos: Point, + } + let mut raw_json = + r#"{"name":"bob","middle_name": "frank", "friends":[], "pos": [1,2]}"#.to_string(); + let result: Result = crate::to_owned_value(unsafe { raw_json.as_bytes_mut() }) + .and_then(crate::serde::value::owned::from_value); + assert_eq!( + result, + Ok(Person { + name: "bob".to_string(), + middle_name: Some("frank".to_string()), + friends: vec![], + pos: Point { x: 1, y: 2 } + }) + ); + } + + #[test] + fn deserialize() { + use halfbrown::{HashMap, hashmap}; + #[derive(serde::Deserialize, Debug, PartialEq, Eq)] + #[serde(rename_all = "lowercase")] + pub enum Rotate { + Left, + Right, + Up, + Down, + } + #[derive(serde::Deserialize, Debug, PartialEq)] + pub struct Point { + pub x: i64, + pub y: i64, + pub z: f64, + pub rotate: Rotate, + } + #[derive(serde::Deserialize, Debug, PartialEq)] + pub struct Person { + pub name: String, + pub middle_name: Option, + pub friends: Vec, + pub pos: Point, + pub age: u64, + } + #[derive(serde::Deserialize, Debug, PartialEq, Eq)] + pub struct TestStruct { + pub key: HashMap, + pub vec: Vec>>, + } + + let mut raw_json = + r#"{"name":"bob","middle_name": "frank", "friends":[], "pos": [-1, 2, -3.25, "up"], "age": 123}"#.to_string(); + let serde_result: Person = serde_json::from_str(&raw_json).expect("serde_json::from_str"); + let value = + crate::to_owned_value(unsafe { raw_json.as_bytes_mut() }).expect("to_owned_value"); + let result: Person = crate::serde::value::owned::from_refvalue(&value).expect("from_refvalue"); + let expected = Person { + name: "bob".to_string(), + middle_name: Some("frank".to_string()), + friends: Vec::new(), + pos: Point { + x: -1, + y: 2, + z: -3.25_f64, + rotate: Rotate::Up, + }, + age: 123, + }; + assert_eq!(result, expected); + assert_eq!(result, serde_result); + + let mut raw_json = r#"{"key":{"subkey": "value"}, "vec":[[null], [1]]}"#.to_string(); + let value = + crate::to_owned_value(unsafe { raw_json.as_bytes_mut() }).expect("to_owned_value"); + let result: TestStruct = crate::serde::value::owned::from_refvalue(&value).expect("from_refvalue"); + let expected = TestStruct { + key: hashmap!("subkey".to_string() => "value".to_string()), + vec: vec![vec![None], vec![Some(1)]], + }; + assert_eq!(result, expected); + } + + #[cfg(feature = "128bit")] + #[test] + fn deserialize_128bit() { + let value = i64::MIN as i128 - 1; + let int128 = crate::OwnedValue::Static(crate::StaticNode::I128(value)); + let res: i128 = crate::serde::value::owned::from_refvalue(&int128).expect("from_refvalue"); + assert_eq!(value, res); + + let value = u64::MAX as u128; + let int128 = crate::OwnedValue::Static(crate::StaticNode::U128(value)); + let res: u128 = crate::serde::value::owned::from_refvalue(&int128).expect("from_refvalue"); + assert_eq!(value, res); + } + #[test] + fn variant() { + struct NameAndConfig { + name: String, + config: Option, + } + impl<'v> serde::Deserialize<'v> for NameAndConfig { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'v>, + { + #[derive(Deserialize)] + #[serde(untagged)] + enum Variants { + Name(String), + NameAndConfig { + name: String, + config: Option, + }, + } + + let var = Variants::deserialize(deserializer)?; + + match var { + Variants::Name(name) => Ok(NameAndConfig { name, config: None }), + Variants::NameAndConfig { name, config } => Ok(NameAndConfig { name, config }), + } + } + } + + let v = json!({"name": "name", "config": 42}); + let nac = NameAndConfig::deserialize(v).expect("could structurize two element struct"); + assert_eq!(nac.name, "name"); + assert_eq!(nac.config.as_u8(), Some(42)); + let v = json!({"name": "name"}); + let nac = NameAndConfig::deserialize(v).expect("could structurize one element struct"); + assert_eq!(nac.name, "name"); + assert_eq!(nac.config, None); + let v = json!("name"); + let nac = NameAndConfig::deserialize(v).expect("could structurize string"); + assert_eq!(nac.name, "name"); + assert_eq!(nac.config, None); + } +} diff --git a/src/serde/value/owned/ordered/se.rs b/src/serde/value/owned/ordered/se.rs new file mode 100644 index 00000000..1e1eb762 --- /dev/null +++ b/src/serde/value/owned/ordered/se.rs @@ -0,0 +1,749 @@ +use super::to_value; +use crate::{ + Error, ErrorType, ObjectHasher, Result, StaticNode, + macros::stry, + value::owned::ordered::{Object, Value}, +}; +use serde_ext::ser::{ + self, Serialize, SerializeMap as SerializeMapTrait, SerializeSeq as SerializeSeqTrait, +}; + +type Impossible = ser::Impossible; + +impl Serialize for Value { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: ser::Serializer, + { + match self { + Value::Static(StaticNode::Null) => serializer.serialize_unit(), + Value::Static(StaticNode::Bool(b)) => serializer.serialize_bool(*b), + #[allow(clippy::useless_conversion)] // .into() required by ordered-float + Value::Static(StaticNode::F64(f)) => serializer.serialize_f64((*f).into()), + Value::Static(StaticNode::U64(i)) => serializer.serialize_u64(*i), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::U128(i)) => serializer.serialize_u128(*i), + Value::Static(StaticNode::I64(i)) => serializer.serialize_i64(*i), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::I128(i)) => serializer.serialize_i128(*i), + Value::String(s) => serializer.serialize_str(s), + Value::Array(v) => { + let mut seq = serializer.serialize_seq(Some(v.len()))?; + for e in v.as_ref() { + seq.serialize_element(e)?; + } + seq.end() + } + Value::Object(m) => { + let mut map = serializer.serialize_map(Some(m.len()))?; + for (k, v) in m.iter() { + map.serialize_entry(k, v)?; + } + map.end() + } + } + } +} + +#[derive(Default)] +pub struct Serializer {} + +impl serde::Serializer for Serializer { + type Ok = Value; + type Error = Error; + + type SerializeSeq = SerializeVec; + type SerializeTuple = SerializeVec; + type SerializeTupleStruct = SerializeVec; + type SerializeTupleVariant = SerializeTupleVariant; + type SerializeMap = SerializeMap; + type SerializeStruct = SerializeMap; + type SerializeStructVariant = SerializeStructVariant; + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_bool(self, value: bool) -> Result { + Ok(Value::Static(StaticNode::Bool(value))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_i8(self, value: i8) -> Result { + self.serialize_i64(i64::from(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_i16(self, value: i16) -> Result { + self.serialize_i64(i64::from(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_i32(self, value: i32) -> Result { + self.serialize_i64(i64::from(value)) + } + + fn serialize_i64(self, value: i64) -> Result { + Ok(Value::Static(StaticNode::I64(value))) + } + + #[cfg(feature = "128bit")] + fn serialize_i128(self, value: i128) -> Result { + Ok(Value::Static(StaticNode::I128(value))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_u8(self, value: u8) -> Result { + self.serialize_u64(u64::from(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_u16(self, value: u16) -> Result { + self.serialize_u64(u64::from(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_u32(self, value: u32) -> Result { + self.serialize_u64(u64::from(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_u64(self, value: u64) -> Result { + Ok(Value::Static(StaticNode::U64(value))) + } + + #[cfg(feature = "128bit")] + fn serialize_u128(self, value: u128) -> Result { + Ok(Value::Static(StaticNode::U128(value))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_f32(self, value: f32) -> Result { + self.serialize_f64(f64::from(value)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_f64(self, value: f64) -> Result { + Ok(Value::Static(StaticNode::from(value))) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_char(self, value: char) -> Result { + let mut s = String::new(); + s.push(value); + self.serialize_str(&s) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_str(self, value: &str) -> Result { + Ok(Value::from(value.to_owned())) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_bytes(self, value: &[u8]) -> Result { + Ok(value.iter().copied().collect()) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_unit(self) -> Result { + Ok(Value::Static(StaticNode::Null)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_unit_struct(self, _name: &'static str) -> Result { + self.serialize_unit() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result { + self.serialize_str(variant) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + let mut values = Object::with_capacity_and_hasher(1, ObjectHasher::default()); + #[cfg(not(feature = "preserve_order"))] + unsafe { + values.insert_nocheck(variant.into(), stry!(to_value(value))) + }; + #[cfg(feature = "preserve_order")] + values.insert(variant.into(), stry!(to_value(value))); + Ok(Value::from(values)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_none(self) -> Result { + self.serialize_unit() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_some(self, value: &T) -> Result + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_seq(self, len: Option) -> Result { + Ok(SerializeVec { + vec: Vec::with_capacity(len.unwrap_or(0)), + }) + } + + fn serialize_tuple(self, len: usize) -> Result { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + Ok(SerializeTupleVariant { + name: variant.to_owned(), + vec: Vec::with_capacity(len), + }) + } + + fn serialize_map(self, len: Option) -> Result { + Ok(SerializeMap { + map: Object::with_capacity_and_hasher(len.unwrap_or(0), ObjectHasher::default()), + next_key: None, + }) + } + + fn serialize_struct(self, _name: &'static str, len: usize) -> Result { + self.serialize_map(Some(len)) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + Ok(SerializeStructVariant { + name: variant.to_owned(), + map: Object::with_capacity_and_hasher(len, ObjectHasher::default()), + }) + } +} + +pub struct SerializeVec { + vec: Vec, +} + +pub struct SerializeTupleVariant { + name: String, + vec: Vec, +} + +pub struct SerializeMap { + map: Object, + next_key: Option, +} + +pub struct SerializeStructVariant { + name: String, + map: Object, +} + +impl serde::ser::SerializeSeq for SerializeVec { + type Ok = Value; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + self.vec.push(stry!(to_value(value))); + Ok(()) + } + + fn end(self) -> Result { + Ok(Value::Array(Box::new(self.vec))) + } +} + +impl serde::ser::SerializeTuple for SerializeVec { + type Ok = Value; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + serde::ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result { + serde::ser::SerializeSeq::end(self) + } +} + +impl serde::ser::SerializeTupleStruct for SerializeVec { + type Ok = Value; + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + serde::ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result { + serde::ser::SerializeSeq::end(self) + } +} + +impl serde::ser::SerializeTupleVariant for SerializeTupleVariant { + type Ok = Value; + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + self.vec.push(stry!(to_value(value))); + Ok(()) + } + + fn end(self) -> Result { + let mut object = Object::with_capacity_and_hasher(1, ObjectHasher::default()); + #[cfg(not(feature = "preserve_order"))] + unsafe { + object.insert_nocheck(self.name, Value::Array(Box::new(self.vec))) + }; + #[cfg(feature = "preserve_order")] + object.insert(self.name, Value::Array(Box::new(self.vec))); + Ok(Value::from(object)) + } +} + +impl serde::ser::SerializeMap for SerializeMap { + type Ok = Value; + type Error = Error; + + fn serialize_key(&mut self, key: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + self.next_key = Some(stry!(key.serialize(MapKeySerializer {}))); + Ok(()) + } + + fn serialize_value(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + let key = self.next_key.take(); + // Panic because this indicates a bug in the program rather than an + // expected failure. + let key = key.expect("serialize_value called before serialize_key"); + self.map.insert(key, stry!(to_value(value))); + Ok(()) + } + + fn end(self) -> Result { + Ok(Value::from(self.map)) + } +} + +struct MapKeySerializer {} + +fn key_must_be_a_string() -> Error { + Error::generic(ErrorType::KeyMustBeAString) +} + +impl serde_ext::Serializer for MapKeySerializer { + type Ok = String; + type Error = Error; + + type SerializeSeq = Impossible; + type SerializeTuple = Impossible; + type SerializeTupleStruct = Impossible; + type SerializeTupleVariant = Impossible; + type SerializeMap = Impossible; + type SerializeStruct = Impossible; + type SerializeStructVariant = Impossible; + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result { + Ok(variant.to_owned()) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_bool(self, _value: bool) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_i8(self, value: i8) -> Result { + Ok(value.to_string()) + } + + fn serialize_i16(self, value: i16) -> Result { + Ok(value.to_string()) + } + + fn serialize_i32(self, value: i32) -> Result { + Ok(value.to_string()) + } + + fn serialize_i64(self, value: i64) -> Result { + Ok(value.to_string()) + } + + fn serialize_u8(self, value: u8) -> Result { + Ok(value.to_string()) + } + + fn serialize_u16(self, value: u16) -> Result { + Ok(value.to_string()) + } + + fn serialize_u32(self, value: u32) -> Result { + Ok(value.to_string()) + } + + fn serialize_u64(self, value: u64) -> Result { + Ok(value.to_string()) + } + + fn serialize_f32(self, _value: f32) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_f64(self, _value: f64) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_char(self, value: char) -> Result { + Ok({ + let mut s = String::new(); + s.push(value); + s + }) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn serialize_str(self, value: &str) -> Result { + Ok(value.to_owned()) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_unit(self) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + Err(key_must_be_a_string()) + } + + fn serialize_none(self) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_some(self, _value: &T) -> Result + where + T: ?Sized + Serialize, + { + Err(key_must_be_a_string()) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } +} + +impl serde::ser::SerializeStruct for SerializeMap { + type Ok = Value; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + stry!(serde::ser::SerializeMap::serialize_key(self, key)); + serde::ser::SerializeMap::serialize_value(self, value) + } + + fn end(self) -> Result { + serde::ser::SerializeMap::end(self) + } +} + +impl serde::ser::SerializeStructVariant for SerializeStructVariant { + type Ok = Value; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + self.map.insert(key.into(), stry!(to_value(value))); + Ok(()) + } + + fn end(self) -> Result { + let mut object = Object::with_capacity_and_hasher(1, ObjectHasher::default()); + #[cfg(not(feature = "preserve_order"))] + unsafe { + object.insert_nocheck(self.name, Value::from(self.map)) + }; + #[cfg(feature = "preserve_order")] + object.insert(self.name, Value::from(self.map)); + Ok(Value::from(object)) + } +} + +#[cfg(test)] +mod test { + #![allow(clippy::ignored_unit_patterns)] + use crate::serde::from_slice; + #[cfg(not(target_arch = "wasm32"))] + use crate::serde::{from_str, to_string}; + use serde::{Deserialize, Serialize}; + + #[derive(Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)] + struct UnitStruct; + // newtype_struct are not deserializable yet + // #[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + // struct NewTypeStruct(u8); + #[derive(Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)] + struct TupleStruct(u8, u8); + #[derive(Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)] + struct TestStruct { + key: u32, + } + /* + skipped due to https://github.com/simd-lite/simd-json/issues/65 + Enums are not deserializable yet + #[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] + enum E { + NewTypeVariant(u8), + UnitVariant, + StructVariant { r: u8, g: u8, b: u8 }, + StructVariant2 { r: u8, g: u8, b: u8 }, + TupleVariant(u8, u8, u8), + } + impl Default for E { + fn default() -> Self { + E::UnitVariant + } + } + */ + + #[allow(clippy::struct_field_names)] + #[derive(Deserialize, Serialize, PartialEq, Debug, Default)] + struct Obj { + v_i128: i128, + v_i64: i64, + v_i32: i32, + v_i16: i16, + v_i8: i8, + v_u128: u128, + v_u64: u64, + v_usize: usize, + v_u32: u32, + v_u16: u16, + v_u8: u8, + v_bool: bool, + v_str: String, + v_char: char, + //v_enum: Enum, + v_unit_struct: UnitStruct, + // v_newtype_struct: NewTypeStruct, + v_tuple_struct: TupleStruct, + v_struct: TestStruct, + // v_enum: E, + v_option: Option, + v_arr: Vec, + v_null: (), + } + #[test] + fn from_slice_to_object() { + let o = Obj::default(); + let mut vec = serde_json::to_vec(&o).expect("to_vec"); + let vec2 = crate::serde::to_vec(&o).expect("to_vec"); + assert_eq!(vec, vec2); + + println!("{}", serde_json::to_string_pretty(&o).expect("json")); + let de: Obj = from_slice(&mut vec).expect("from_slice"); + assert_eq!(o, de); + } + + #[cfg(not(target_arch = "wasm32"))] + use proptest::prelude::*; + #[cfg(not(target_arch = "wasm32"))] + prop_compose! { + fn obj_case()( + v_i128 in any::().prop_map(i128::from), + v_i64 in any::(), + v_i32 in any::(), + v_i16 in any::(), + v_i8 in any::(), + v_u128 in any::().prop_map(u128::from), + v_u64 in any::(), + v_usize in any::().prop_map(|v| v as usize), + v_u32 in any::(), + v_u16 in any::(), + v_u8 in any::(), + v_bool in any::(), + v_str in ".*", + v_char in any::(), + v_tuple_struct in any::<(u8, u8)>().prop_map(|(a, b)| TupleStruct(a, b)), + v_struct in any::().prop_map(|key| TestStruct{key}), + v_option in any::>(), + v_arr in any::>(), + ) -> Obj { + Obj { + v_i128, + v_i64, + v_i32, + v_i16, + v_i8, + v_u128, + v_u64, + v_usize, + v_u32, + v_u16, + v_u8, + v_bool, + v_str, + v_char, + v_tuple_struct, + v_struct, + v_option, + v_arr, + ..Obj::default() + } + } + } + + #[cfg(not(target_arch = "wasm32"))] + proptest! { + #![proptest_config(ProptestConfig { + .. ProptestConfig::default() + })] + + #[test] + fn prop_deserialize_obj(obj in obj_case()) { + let mut vec = serde_json::to_vec(&obj).expect("to_vec"); + let vec1 = vec.clone(); + let vec2 = vec.clone(); + println!("{}", serde_json::to_string_pretty(&obj).expect("json")); + let de: Obj = from_slice(&mut vec).expect("from_slice"); + prop_assert_eq!(&obj, &de); + + let borrowed: crate::BorrowedValue = serde_json::from_slice(& vec1).expect("from_slice"); + let owned: crate::OwnedValue = serde_json::from_slice(& vec2).expect("from_slice"); + prop_assert_eq!(&borrowed, &owned); + let mut owned_str = to_string(&obj).expect("to_string"); + unsafe{from_str::(&mut owned_str).expect("from_str")}; + + let de: Obj = Obj::deserialize(borrowed).expect("deserialize"); + prop_assert_eq!(&obj, &de); + let de: Obj = Obj::deserialize(owned).expect("deserialize"); + prop_assert_eq!(&obj, &de); + + } + } +} diff --git a/src/serde/value/owned/se.rs b/src/serde/value/owned/se.rs index 4ecd87c0..572702c6 100644 --- a/src/serde/value/owned/se.rs +++ b/src/serde/value/owned/se.rs @@ -180,7 +180,12 @@ impl serde::Serializer for Serializer { T: ?Sized + Serialize, { let mut values = Object::with_capacity_and_hasher(1, ObjectHasher::default()); - unsafe { values.insert_nocheck(variant.into(), stry!(to_value(value))) }; + #[cfg(not(feature = "preserve_order"))] + unsafe { + values.insert_nocheck(variant.into(), stry!(to_value(value))) + }; + #[cfg(feature = "preserve_order")] + values.insert(variant.into(), stry!(to_value(value))); Ok(Value::from(values)) } @@ -335,7 +340,12 @@ impl serde::ser::SerializeTupleVariant for SerializeTupleVariant { fn end(self) -> Result { let mut object = Object::with_capacity_and_hasher(1, ObjectHasher::default()); - unsafe { object.insert_nocheck(self.name, Value::Array(Box::new(self.vec))) }; + #[cfg(not(feature = "preserve_order"))] + unsafe { + object.insert_nocheck(self.name, Value::Array(Box::new(self.vec))) + }; + #[cfg(feature = "preserve_order")] + object.insert(self.name, Value::Array(Box::new(self.vec))); Ok(Value::from(object)) } } @@ -574,7 +584,12 @@ impl serde::ser::SerializeStructVariant for SerializeStructVariant { fn end(self) -> Result { let mut object = Object::with_capacity_and_hasher(1, ObjectHasher::default()); - unsafe { object.insert_nocheck(self.name, Value::from(self.map)) }; + #[cfg(not(feature = "preserve_order"))] + unsafe { + object.insert_nocheck(self.name, Value::from(self.map)) + }; + #[cfg(feature = "preserve_order")] + object.insert(self.name, Value::from(self.map)); Ok(Value::from(object)) } } diff --git a/src/tests.rs b/src/tests.rs index 4ef3597c..5fa61a48 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -7,7 +7,7 @@ mod impls; #[cfg(not(target_arch = "wasm32"))] use crate::to_borrowed_value; -use crate::{Deserializer, owned::Value, tape::Node, to_owned_value}; +use crate::{cow::Cow, Deserializer, owned::Value, tape::Node, to_owned_value}; #[cfg(not(target_arch = "wasm32"))] use proptest::prelude::*; use value_trait::prelude::*; @@ -253,10 +253,10 @@ proptest! { { // we can't do 128 bit w/ serde use crate::{deserialize, BorrowedValue, OwnedValue}; let mut e = encoded.clone(); - let res: OwnedValue = deserialize(&mut e).expect("can't convert"); + let res: OwnedValue = deserialize::(&mut e).expect("can't convert"); assert_eq!(val, res); let mut e = encoded; - let res: BorrowedValue = deserialize(&mut e).expect("can't convert"); + let res: BorrowedValue = deserialize::>(&mut e).expect("can't convert"); assert_eq!(val, res); } } diff --git a/src/tests/serde.rs b/src/tests/serde.rs index fdb1f042..ee22ff83 100644 --- a/src/tests/serde.rs +++ b/src/tests/serde.rs @@ -1008,7 +1008,7 @@ proptest! { let v_simd_owned = to_owned_value(d2).expect("to_owned_value failed"); let v_simd_borrowed = to_borrowed_value(d3).expect("to_borrowed_value failed"); assert_eq!(v_simd_borrowed, v_simd_owned); - let v_deserialize: OwnedValue = deserialize(d4).expect("deserialize failed"); + let v_deserialize: OwnedValue = deserialize::(d4).expect("deserialize failed"); assert_eq!(v_deserialize, v_simd_owned); } diff --git a/src/value.rs b/src/value.rs index 2d854edc..43bcb579 100644 --- a/src/value.rs +++ b/src/value.rs @@ -63,12 +63,25 @@ pub use self::borrowed::{ Value as BorrowedValue, to_value as to_borrowed_value, to_value_with_buffers as to_borrowed_value_with_buffers, }; +#[cfg(feature = "preserve_order")] +pub use self::borrowed::ordered::{ + Value as OrderedBorrowedValue, to_value as to_ordered_borrowed_value, + to_value_with_buffers as to_ordered_borrowed_value_with_buffers, +}; pub use self::owned::{ Value as OwnedValue, to_value as to_owned_value, to_value_with_buffers as to_owned_value_with_buffers, }; +#[cfg(feature = "preserve_order")] +pub use self::owned::ordered::{ + Value as OrderedOwnedValue, to_value as to_ordered_owned_value, + to_value_with_buffers as to_ordered_owned_value_with_buffers, +}; use crate::{Buffers, Deserializer, Result}; +#[cfg(not(feature = "preserve_order"))] use halfbrown::HashMap; +#[cfg(feature = "preserve_order")] +use indexmap::IndexMap; use std::hash::Hash; use std::marker::PhantomData; use tape::Node; @@ -78,8 +91,18 @@ pub use value_trait::*; #[cfg(feature = "known-key")] pub type ObjectHasher = crate::known_key::NotSoRandomState; /// Hasher used for objects -#[cfg(not(feature = "known-key"))] +#[cfg(all(not(feature = "known-key"), not(feature = "preserve_order")))] pub type ObjectHasher = halfbrown::DefaultHashBuilder; +/// Hasher used for objects +#[cfg(all(not(feature = "known-key"), feature = "preserve_order"))] +pub type ObjectHasher = std::hash::RandomState; + +/// Hashmap used for objects +#[cfg(not(feature = "preserve_order"))] +type ObjectMap = HashMap; +/// Hashmap used for objects +#[cfg(feature = "preserve_order")] +type ObjectMap = IndexMap; /// Parses a slice of bytes into a Value dom. /// @@ -92,7 +115,7 @@ pub type ObjectHasher = halfbrown::DefaultHashBuilder; /// Will return `Err` if `s` is invalid JSON. pub fn deserialize<'de, Value, Key>(s: &'de mut [u8]) -> Result where - Value: ValueBuilder<'de> + From> + From> + 'de, + Value: ValueBuilder<'de> + From> + From> + 'de, Key: Hash + Eq + From<&'de str>, { match Deserializer::from_slice(s) { @@ -117,7 +140,7 @@ pub fn deserialize_with_buffers<'de, Value, Key>( buffers: &mut Buffers, ) -> Result where - Value: ValueBuilder<'de> + From> + From> + 'de, + Value: ValueBuilder<'de> + From> + From> + 'de, Key: Hash + Eq + From<&'de str>, { match Deserializer::from_slice_with_buffers(s, buffers) { @@ -128,7 +151,7 @@ where struct ValueDeserializer<'de, Value, Key> where - Value: ValueBuilder<'de> + From> + From> + 'de, + Value: ValueBuilder<'de> + From> + From> + 'de, Key: Hash + Eq + From<&'de str>, { de: Deserializer<'de>, @@ -140,7 +163,7 @@ where Value: ValueBuilder<'de> + From<&'de str> + From> - + From> + + From> + 'de, Key: Hash + Eq + From<&'de str>, { @@ -179,18 +202,18 @@ where #[cfg_attr(not(feature = "no-inline"), inline)] fn parse_map(&mut self, len: usize) -> Value { - let mut res: HashMap = - HashMap::with_capacity_and_hasher(len, ObjectHasher::default()); + let mut res: ObjectMap = + ObjectMap::with_capacity_and_hasher(len, ObjectHasher::default()); // Since we checked if it's empty we know that we at least have one // element so we eat this for _ in 0..len { if let Node::String(key) = unsafe { self.de.next_() } { - #[cfg(not(feature = "value-no-dup-keys"))] + #[cfg(all(not(feature = "value-no-dup-keys"), not(feature = "preserve_order")))] unsafe { res.insert_nocheck(key.into(), self.parse()); }; - #[cfg(feature = "value-no-dup-keys")] + #[cfg(any(feature = "value-no-dup-keys", feature = "preserve_order"))] res.insert(key.into(), self.parse()); } else { unreachable!("parse_map: key needs to be a string"); diff --git a/src/value/borrowed.rs b/src/value/borrowed.rs index b3f938fc..465f296a 100644 --- a/src/value/borrowed.rs +++ b/src/value/borrowed.rs @@ -23,6 +23,9 @@ mod cmp; mod from; mod serialize; +/// Ordered borrowed value handling. +#[cfg(feature = "preserve_order")] +pub mod ordered; use super::ObjectHasher; use crate::{Buffers, prelude::*}; @@ -34,6 +37,7 @@ use std::ops::{Index, IndexMut}; /// Representation of a JSON object pub type Object<'value> = HashMap, Value<'value>, ObjectHasher>; + /// Representation of a JSON array pub type Array<'value> = Vec>; @@ -1115,6 +1119,23 @@ mod test { assert_eq!(v, 42); } + #[test] + fn preserve_order_32_keys_baseline() { + // At exactly 32 keys, halfbrown still uses Vec - order preserved naturally + let keys: Vec = (0..32).map(|i| format!("key_{}", i)).collect(); + let json_pairs: Vec = keys.iter().map(|k| format!(r#""{}": {}"#, k, 1)).collect(); + let json = format!("{{{}}}", json_pairs.join(", ")); + let mut input = json.into_bytes(); + + let v = to_value(input.as_mut_slice()).expect("valid JSON"); + let obj = v.as_object().expect("is object"); + let result_keys: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect(); + let expected_keys: Vec<&str> = keys.iter().map(|s| s.as_str()).collect(); + + // This should pass even without preserve_order + assert_eq!(result_keys, expected_keys); + } + // #[test] // fn size() { // assert_eq!(std::mem::size_of::(), 24); diff --git a/src/value/borrowed/from.rs b/src/value/borrowed/from.rs index 7a3da31a..00570bf1 100644 --- a/src/value/borrowed/from.rs +++ b/src/value/borrowed/from.rs @@ -1,6 +1,5 @@ use super::{Object, Value}; -use crate::OwnedValue; -use crate::StaticNode; +use crate::{ObjectHasher, OwnedValue, StaticNode}; use crate::cow::Cow; impl From for Value<'_> { @@ -202,11 +201,13 @@ impl<'value, K: Into>, V: Into>> FromIterator<(K, { #[cfg_attr(not(feature = "no-inline"), inline)] fn from_iter>(iter: I) -> Self { - Value::Object(Box::new( - iter.into_iter() - .map(|(k, v)| (Into::into(k), Into::into(v))) - .collect(), - )) + let iter = iter.into_iter(); + let (lower, _) = iter.size_hint(); + let mut map = Object::with_capacity_and_hasher(lower, ObjectHasher::default()); + for (k, v) in iter { + map.insert(k.into(), v.into()); + } + Value::Object(Box::new(map)) } } @@ -216,3 +217,14 @@ impl<'value> From> for Value<'value> { Self::Object(Box::new(v)) } } + +#[cfg(feature = "preserve_order")] +impl<'value, K, S> From, S>> for Value<'value> +where + K: Into>, + S: std::hash::BuildHasher, +{ + fn from(v: indexmap::IndexMap, S>) -> Self { + Self::Object(Box::new(v.into_iter().map(|(k, v)| (k.into(), v)).collect())) + } +} diff --git a/src/value/borrowed/ordered.rs b/src/value/borrowed/ordered.rs new file mode 100644 index 00000000..c3cdf2a3 --- /dev/null +++ b/src/value/borrowed/ordered.rs @@ -0,0 +1,988 @@ +/// A dom object that references the raw input data to avoid allocations +/// it trades having lifetimes for a gain in performance. +/// +/// Access via array indexes is possible: +/// ```rust +/// use simd_json::{BorrowedValue, json}; +/// use simd_json::prelude::*; +/// let mut a = json!([1, 2, 3]); +/// assert_eq!(a[1], 2); +/// a[1] = 42.into(); +/// assert_eq!(a[1], 42); +/// ``` +/// +/// Access via object keys is possible as well: +/// ```rust +/// use simd_json::{BorrowedValue, json}; +/// use simd_json::prelude::*; +/// let mut a = json!({"key": "not the value"}); +/// assert_eq!(a["key"], "not the value"); +/// a["key"] = "value".into(); +/// assert_eq!(a["key"], "value"); +/// ``` +/// Partial equality comparison impls +pub mod cmp; +/// From converter impls +pub mod from; +/// Provide Writable trait +pub mod serialize; + +use crate::{Buffers, prelude::*}; +use crate::{Deserializer, Node, ObjectHasher, Result}; +use crate::cow::Cow; +use indexmap::IndexMap; +use std::fmt; +use std::ops::{Index, IndexMut}; + +/// Representation of a JSON object +pub type Object<'value> = IndexMap, Value<'value>, ObjectHasher>; + +/// Representation of a JSON array +pub type Array<'value> = Vec>; + +/// Parses a slice of bytes into a Value dom. +/// +/// This function will rewrite the slice to de-escape strings. +/// As we reference parts of the input slice the resulting dom +/// has the same lifetime as the slice it was created from. +/// +/// # Errors +/// +/// Will return `Err` if `s` is invalid JSON. +pub fn to_value(s: &mut [u8]) -> Result> { + match Deserializer::from_slice(s) { + Ok(de) => Ok(BorrowDeserializer::from_deserializer(de).parse()), + Err(e) => Err(e), + } +} + +/// Parses a slice of bytes into a Value dom. +/// +/// This function will rewrite the slice to de-escape strings. +/// As we reference parts of the input slice the resulting dom +/// has the same lifetime as the slice it was created from. +/// +/// Passes in reusable buffers to reduce allocations. +/// +/// # Errors +/// +/// Will return `Err` if `s` is invalid JSON. +pub fn to_value_with_buffers<'value>( + s: &'value mut [u8], + buffers: &mut Buffers, +) -> Result> { + match Deserializer::from_slice_with_buffers(s, buffers) { + Ok(de) => Ok(BorrowDeserializer::from_deserializer(de).parse()), + Err(e) => Err(e), + } +} + +/// Borrowed JSON-DOM Value, consider using the `ValueTrait` +/// to access its content +#[derive(Debug, Clone)] +#[cfg_attr(feature = "ordered-float", derive(Eq))] +pub enum Value<'value> { + /// Static values + Static(StaticNode), + /// string type + String(Cow<'value, str>), + /// array type + Array(Box>>), + /// object type + Object(Box>), +} + +impl<'value> Value<'value> { + fn as_static(&self) -> Option { + match self { + Self::Static(s) => Some(*s), + _ => None, + } + } + + /// Enforces static lifetime on a borrowed value, this will + /// force all strings to become owned COW's, the same applies for + /// Object keys. + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + pub fn into_static(self) -> Value<'static> { + match self { + // Ensure strings are static by turing the cow into a 'static + // This cow has static lifetime as it's owned, this information however is lost + // by the borrow checker so we need to transmute it to static. + // This invariant is guaranteed by the implementation of the cow, cloning an owned + // value will produce a owned value again see: + // https://docs.rs/beef/0.4.4/src/beef/generic.rs.html#379-391 + Self::String(s) => unsafe { + std::mem::transmute::, Value<'static>>(Self::String(Cow::from( + s.into_owned(), + ))) + }, + // For an array we turn every value into a static + Self::Array(arr) => Value::<'static>::Array(Box::new( + arr.into_iter().map(Value::into_static).collect() + )), + // For an object, we turn all keys into owned Cows and all values into 'static Values + Self::Object(obj) => Value::<'static>::Object(Box::new( + obj.into_iter() + .map(|(k, v)| (Cow::from(k.into_owned()), v.into_static())) + .collect() + )), + // Static nodes are always static + Value::Static(s) => Value::Static(s), + } + } + + /// Clones the current value and enforces a static lifetime, it works the same + /// as `into_static` but includes cloning logic + #[cfg_attr(not(feature = "no-inline"), inline)] + #[must_use] + pub fn clone_static(&self) -> Value<'static> { + match self { + // Ensure strings are static by turing the cow into a 'static + // This cow has static lifetime as it's owned, this information however is lost + // by the borrow checker so we need to transmute it to static. + // This invariant is guaranteed by the implementation of the cow, cloning an owned + // value will produce a owned value again see: + // https://docs.rs/beef/0.4.4/src/beef/generic.rs.html#379-391 + Self::String(s) => unsafe { + std::mem::transmute::, Value<'static>>(Self::String(Cow::from( + s.to_string(), + ))) + }, + // For an array we turn every value into a static + Self::Array(arr) => Value::<'static>::Array(Box::new( + arr.iter().cloned().map(Value::into_static).collect() + )), + // For an object, we turn all keys into owned Cows and all values into 'static Values + Self::Object(obj) => Value::<'static>::Object(Box::new( + obj.iter() + .map(|(k, v)| (Cow::from(k.to_string()), v.clone_static())) + .collect() + )), + + // Static nodes are always static + Value::Static(s) => Value::Static(*s), + } + } +} + +impl<'value> ValueBuilder<'value> for Value<'value> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn null() -> Self { + Self::Static(StaticNode::Null) + } + #[cfg_attr(not(feature = "no-inline"), inline)] + fn array_with_capacity(capacity: usize) -> Self { + Self::Array(Box::new(Vec::with_capacity(capacity))) + } + #[cfg_attr(not(feature = "no-inline"), inline)] + fn object_with_capacity(capacity: usize) -> Self { + Self::Object(Box::new(Object::with_capacity_and_hasher( + capacity, + ObjectHasher::default(), + ))) + } +} + +impl<'value> ValueAsMutArray for Value<'value> { + type Array = Array<'value>; + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_array_mut(&mut self) -> Option<&mut Vec>> { + match self { + Self::Array(a) => Some(a), + _ => None, + } + } +} +impl<'value> ValueAsMutObject for Value<'value> { + type Object = Object<'value>; + /// Get mutable access to a map. + /// + /// ```rust + /// use simd_json::*; + /// use value_trait::prelude::*; + /// + /// let mut object: BorrowedValue = json!({ + /// "answer": 23, + /// "key": 7 + /// }).into(); + /// assert_eq!(object["answer"], 23); + /// + /// if let Some(inner) = object.as_object_mut() { + /// inner.insert("value".into(), BorrowedValue::from(json!({"nested": 42}))); + /// } + /// assert_eq!(object["value"], json!({"nested": 42})); + /// + /// ``` + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_object_mut(&mut self) -> Option<&mut Object<'value>> { + match self { + Self::Object(m) => Some(m), + _ => None, + } + } +} + +impl TypedValue for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn value_type(&self) -> ValueType { + match self { + Self::Static(s) => s.value_type(), + Self::String(_) => ValueType::String, + Self::Array(_) => ValueType::Array, + Self::Object(_) => ValueType::Object, + } + } +} +impl ValueAsScalar for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_null(&self) -> Option<()> { + self.as_static()?.as_null() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_bool(&self) -> Option { + self.as_static()?.as_bool() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_i64(&self) -> Option { + self.as_static()?.as_i64() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_i128(&self) -> Option { + self.as_static()?.as_i128() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_u64(&self) -> Option { + self.as_static()?.as_u64() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_u128(&self) -> Option { + self.as_static()?.as_u128() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_f64(&self) -> Option { + self.as_static()?.as_f64() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn cast_f64(&self) -> Option { + self.as_static()?.cast_f64() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_str(&self) -> Option<&str> { + use std::borrow::Borrow; + match self { + Self::String(s) => Some(s.borrow()), + _ => None, + } + } +} +impl<'value> ValueAsArray for Value<'value> { + type Array = Array<'value>; + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_array(&self) -> Option<&Vec>> { + match self { + Self::Array(a) => Some(a), + _ => None, + } + } +} + +impl<'value> ValueAsObject for Value<'value> { + type Object = Object<'value>; + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_object(&self) -> Option<&Object<'value>> { + match self { + Self::Object(m) => Some(m), + _ => None, + } + } +} + +impl<'value> ValueIntoString for Value<'value> { + type String = Cow<'value, str>; + + fn into_string(self) -> Option<::String> { + match self { + Self::String(s) => Some(s), + _ => None, + } + } +} + +impl<'value> ValueIntoArray for Value<'value> { + type Array = Array<'value>; + + fn into_array(self) -> Option<::Array> { + match self { + Self::Array(a) => Some(*a), + _ => None, + } + } +} + +impl<'value> ValueIntoObject for Value<'value> { + type Object = Object<'value>; + + fn into_object(self) -> Option<::Object> { + match self { + Self::Object(a) => Some(*a), + _ => None, + } + } +} + +#[cfg(not(tarpaulin_include))] +impl fmt::Display for Value<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Static(s) => write!(f, "{s}"), + Self::String(s) => write!(f, "{s}"), + Self::Array(a) => write!(f, "{a:?}"), + Self::Object(o) => write!(f, "{o:?}"), + } + } +} + +impl<'value> Index<&str> for Value<'value> { + type Output = Value<'value>; + #[cfg_attr(not(feature = "no-inline"), inline)] + fn index(&self, index: &str) -> &Self::Output { + self.get(index).expect("index out of bounds") + } +} + +impl<'value> Index for Value<'value> { + type Output = Value<'value>; + #[cfg_attr(not(feature = "no-inline"), inline)] + fn index(&self, index: usize) -> &Self::Output { + self.get_idx(index).expect("index out of bounds") + } +} + +impl IndexMut<&str> for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn index_mut(&mut self, index: &str) -> &mut Self::Output { + self.get_mut(index).expect("index out of bounds") + } +} + +impl IndexMut for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.get_idx_mut(index).expect("index out of bounds") + } +} + +impl Default for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn default() -> Self { + Self::Static(StaticNode::Null) + } +} + +pub(super) struct BorrowDeserializer<'de>(Deserializer<'de>); + +impl<'de> BorrowDeserializer<'de> { + pub fn from_deserializer(de: Deserializer<'de>) -> Self { + Self(de) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn parse(&mut self) -> Value<'de> { + match unsafe { self.0.next_() } { + Node::Static(s) => Value::Static(s), + Node::String(s) => Value::from(s), + Node::Array { len, count: _ } => self.parse_array(len), + Node::Object { len, count: _ } => self.parse_map(len), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn parse_array(&mut self, len: usize) -> Value<'de> { + // Rust doesn't optimize the normal loop away here + // so we write our own avoiding the length + // checks during push + let mut res: Vec> = Vec::with_capacity(len); + let res_ptr = res.as_mut_ptr(); + unsafe { + for i in 0..len { + res_ptr.add(i).write(self.parse()); + } + res.set_len(len); + } + Value::Array(Box::new(res)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn parse_map(&mut self, len: usize) -> Value<'de> { + let mut res = Object::with_capacity_and_hasher(len, ObjectHasher::default()); + + // Since we checked if it's empty we know that we at least have one + // element so we eat this + for _ in 0..len { + if let Node::String(key) = unsafe { self.0.next_() } { + res.insert(key.into(), self.parse()); + } else { + unreachable!("parse_map: key not a string"); + } + } + Value::from(res) + } +} +// pub(super) struct BorrowSliceDeserializer<'tape, 'de> { +// tape: &'tape [Node<'de>], +// idx: usize, +// } +// impl<'tape, 'de> BorrowSliceDeserializer<'tape, 'de> { +// pub fn from_tape(de: &'tape [Node<'de>]) -> Self { +// Self { tape: de, idx: 0 } +// } +// #[cfg_attr(not(feature = "no-inline"), inline)] +// pub unsafe fn next_(&mut self) -> Node<'de> { +// let r = unsafe { *self.tape.get_kinda_unchecked(self.idx) }; +// self.idx += 1; +// r +// } +// +// #[cfg_attr(not(feature = "no-inline"), inline)] +// pub fn parse(&mut self) -> Value<'de> { +// match unsafe { self.next_() } { +// Node::Static(s) => Value::Static(s), +// Node::String(s) => Value::from(s), +// Node::Array { len, count: _ } => self.parse_array(len), +// Node::Object { len, count: _ } => self.parse_map(len), +// } +// } +// +// #[cfg_attr(not(feature = "no-inline"), inline)] +// fn parse_array(&mut self, len: usize) -> Value<'de> { +// // Rust doesn't optimize the normal loop away here +// // so we write our own avoiding the length +// // checks during push +// let mut res: Vec> = Vec::with_capacity(len); +// let res_ptr = res.as_mut_ptr(); +// unsafe { +// for i in 0..len { +// res_ptr.add(i).write(self.parse()); +// } +// res.set_len(len); +// } +// Value::Array(Box::new(res)) +// } +// +// #[cfg_attr(not(feature = "no-inline"), inline)] +// fn parse_map(&mut self, len: usize) -> Value<'de> { +// let mut res = Object::with_capacity_and_hasher(len, ObjectHasher::default()); +// +// // Since we checked if it's empty we know that we at least have one +// // element so we eat this +// for _ in 0..len { +// if let Node::String(key) = unsafe { self.next_() } { +// res.insert(key.into(), self.parse()); +// } else { +// unreachable!("parse_map: key needs to be a string"); +// } +// } +// Value::from(res) +// } +// } + +#[cfg(test)] +mod test { + #![allow(clippy::ignored_unit_patterns)] + #![allow(clippy::cognitive_complexity)] + use super::*; + use crate::ObjectHasher; + + #[test] + fn object_access() { + let mut v = Value::null(); + assert_eq!(v.insert("key", ()), Err(AccessError::NotAnObject)); + assert_eq!(v.remove("key"), Err(AccessError::NotAnObject)); + let mut v = Value::object(); + assert_eq!(v.insert("key", 1), Ok(None)); + assert_eq!(v["key"], Value::from(1)); + assert_eq!(v.insert("key", 2), Ok(Some(Value::from(1)))); + v["key"] = 3.into(); + assert_eq!(v.remove("key"), Ok(Some(Value::from(3)))); + } + + #[test] + fn array_access() { + let mut v = Value::null(); + assert_eq!(v.push("key"), Err(AccessError::NotAnArray)); + assert_eq!(v.pop(), Err(AccessError::NotAnArray)); + let mut v = Value::array(); + assert_eq!(v.push(1), Ok(())); + assert_eq!(v.push(2), Ok(())); + assert_eq!(v[0], Value::from(1)); + v[0] = 0.into(); + v[1] = 1.into(); + assert_eq!(v.pop(), Ok(Some(Value::from(1)))); + assert_eq!(v.pop(), Ok(Some(Value::from(0)))); + assert_eq!(v.pop(), Ok(None)); + } + + #[cfg(feature = "128bit")] + #[test] + fn conversions_i128() { + let v = Value::from(i128::MAX); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(!v.is_i64()); + assert!(!v.is_u64()); + assert!(!v.is_i32()); + assert!(!v.is_u32()); + assert!(!v.is_i16()); + assert!(!v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + let v = Value::from(i128::MIN); + assert!(v.is_i128()); + assert!(!v.is_u128()); + assert!(!v.is_i64()); + assert!(!v.is_u64()); + assert!(!v.is_i32()); + assert!(!v.is_u32()); + assert!(!v.is_i16()); + assert!(!v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_i64() { + let v = Value::from(i64::MAX); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(!v.is_i32()); + assert!(!v.is_u32()); + assert!(!v.is_i16()); + assert!(!v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + let v = Value::from(i64::MIN); + assert!(v.is_i128()); + assert!(!v.is_u128()); + assert!(v.is_i64()); + assert!(!v.is_u64()); + assert!(!v.is_i32()); + assert!(!v.is_u32()); + assert!(!v.is_i16()); + assert!(!v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_i32() { + let v = Value::from(i32::MAX); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(v.is_i32()); + assert!(v.is_u32()); + assert!(!v.is_i16()); + assert!(!v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + let v = Value::from(i32::MIN); + assert!(v.is_i128()); + assert!(!v.is_u128()); + assert!(v.is_i64()); + assert!(!v.is_u64()); + assert!(v.is_i32()); + assert!(!v.is_u32()); + assert!(!v.is_i16()); + assert!(!v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_i16() { + let v = Value::from(i16::MAX); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(v.is_i32()); + assert!(v.is_u32()); + assert!(v.is_i16()); + assert!(v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + let v = Value::from(i16::MIN); + assert!(v.is_i128()); + assert!(!v.is_u128()); + assert!(v.is_i64()); + assert!(!v.is_u64()); + assert!(v.is_i32()); + assert!(!v.is_u32()); + assert!(v.is_i16()); + assert!(!v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_i8() { + let v = Value::from(i8::MAX); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(v.is_i32()); + assert!(v.is_u32()); + assert!(v.is_i16()); + assert!(v.is_u16()); + assert!(v.is_i8()); + assert!(v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + let v = Value::from(i8::MIN); + assert!(v.is_i128()); + assert!(!v.is_u128()); + assert!(v.is_i64()); + assert!(!v.is_u64()); + assert!(v.is_i32()); + assert!(!v.is_u32()); + assert!(v.is_i16()); + assert!(!v.is_u16()); + assert!(v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_usize() { + let v = Value::from(usize::MIN as u64); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(v.is_usize()); + assert!(v.is_i32()); + assert!(v.is_u32()); + assert!(v.is_i16()); + assert!(v.is_u16()); + assert!(v.is_i8()); + assert!(v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[cfg(feature = "128bit")] + #[test] + fn conversions_u128() { + let v = Value::from(u128::MIN); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(v.is_i32()); + assert!(v.is_u32()); + assert!(v.is_i16()); + assert!(v.is_u16()); + assert!(v.is_i8()); + assert!(v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_u64() { + let v = Value::from(u64::MIN); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(v.is_i32()); + assert!(v.is_u32()); + assert!(v.is_i16()); + assert!(v.is_u16()); + assert!(v.is_i8()); + assert!(v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_u32() { + let v = Value::from(u32::MAX); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(!v.is_i32()); + assert!(v.is_u32()); + assert!(!v.is_i16()); + assert!(!v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_u16() { + let v = Value::from(u16::MAX); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(v.is_i32()); + assert!(v.is_u32()); + assert!(!v.is_i16()); + assert!(v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_u8() { + let v = Value::from(u8::MAX); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(v.is_i32()); + assert!(v.is_u32()); + assert!(v.is_i16()); + assert!(v.is_u16()); + assert!(!v.is_i8()); + assert!(v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_f64() { + let v = Value::from(f64::MAX); + assert!(!v.is_i64()); + assert!(!v.is_u64()); + assert!(v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + let v = Value::from(f64::MIN); + assert!(!v.is_i64()); + assert!(!v.is_u64()); + assert!(v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + let v = Value::from("not a f64"); + assert!(!v.is_f64_castable()); + } + + #[test] + fn conversions_f32() { + let v = Value::from(f32::MAX); + assert!(!v.is_i64()); + assert!(!v.is_u64()); + assert!(v.is_f64()); + assert!(v.is_f32()); + assert!(v.is_f64_castable()); + let v = Value::from(f32::MIN); + assert!(!v.is_i64()); + assert!(!v.is_u64()); + assert!(v.is_f64()); + assert!(v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_array() { + let v = Value::from(vec![true]); + assert!(v.is_array()); + assert_eq!(v.value_type(), ValueType::Array); + let v = Value::from("no array"); + assert!(!v.is_array()); + } + + #[test] + fn conversions_bool() { + let v = Value::from(true); + assert!(v.is_bool()); + assert_eq!(v.value_type(), ValueType::Bool); + let v = Value::from("no bool"); + assert!(!v.is_bool()); + } + + #[test] + fn conversions_float() { + let v = Value::from(42.0); + assert!(v.is_f64()); + assert_eq!(v.value_type(), ValueType::F64); + let v = Value::from("no float"); + assert!(!v.is_f64()); + } + + #[test] + fn conversions_int() { + let v = Value::from(-42); + assert!(v.is_i64()); + assert_eq!(v.value_type(), ValueType::I64); + #[cfg(feature = "128bit")] + { + let v = Value::from(-42_i128); + assert!(v.is_i64()); + assert!(v.is_i128()); + assert_eq!(v.value_type(), ValueType::I128); + } + let v = Value::from("no i64"); + assert!(!v.is_i64()); + assert!(!v.is_i128()); + } + + #[test] + fn conversions_uint() { + let v = Value::from(42_u64); + assert!(v.is_u64()); + assert_eq!(v.value_type(), ValueType::U64); + #[cfg(feature = "128bit")] + { + let v = Value::from(42_u128); + assert!(v.is_u64()); + assert!(v.is_u128()); + assert_eq!(v.value_type(), ValueType::U128); + } + let v = Value::from("no u64"); + assert!(!v.is_u64()); + #[cfg(feature = "128bit")] + assert!(!v.is_u128()); + } + + #[test] + fn conversions_null() { + let v = Value::from(()); + assert!(v.is_null()); + assert_eq!(v.value_type(), ValueType::Null); + let v = Value::from("no null"); + assert!(!v.is_null()); + } + + #[test] + fn conversions_object() { + let v = Value::from(Object::with_capacity_and_hasher(1, ObjectHasher::default())); + assert!(v.is_object()); + assert_eq!(v.value_type(), ValueType::Object); + let v = Value::from("no object"); + assert!(!v.is_object()); + } + + #[test] + fn conversions_str() { + let v = Value::from("bla"); + assert!(v.is_str()); + assert_eq!(v.value_type(), ValueType::String); + let v = Value::from(42); + assert!(!v.is_str()); + } + + #[test] + fn default() { + assert_eq!(Value::default(), Value::null()); + } + + #[test] + fn preserve_order_33_keys() { + // halfbrown uses Vec for <=32 keys, switches to HashMap at 33+ + // This is where order gets lost without IndexMap + let keys: Vec = (0..33).map(|i| format!("key_{}", i)).collect(); + let json_pairs: Vec = keys.iter().map(|k| format!(r#""{}": {}"#, k, 1)).collect(); + let json = format!("{{{}}}", json_pairs.join(", ")); + let mut input = json.into_bytes(); + + let v = to_value(input.as_mut_slice()).expect("valid JSON"); + let obj = v.as_object().expect("is object"); + let result_keys: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect(); + let expected_keys: Vec<&str> = keys.iter().map(|s| s.as_str()).collect(); + + assert_eq!(result_keys, expected_keys); + } + + #[test] + fn preserve_order_50_keys() { + // Test well past the threshold + let keys: Vec = (0..50).map(|i| format!("key_{}", i)).collect(); + let json_pairs: Vec = keys.iter().map(|k| format!(r#""{}": {}"#, k, 1)).collect(); + let json = format!("{{{}}}", json_pairs.join(", ")); + let mut input = json.into_bytes(); + + let v = to_value(input.as_mut_slice()).expect("valid JSON"); + let obj = v.as_object().expect("is object"); + let result_keys: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect(); + let expected_keys: Vec<&str> = keys.iter().map(|s| s.as_str()).collect(); + + assert_eq!(result_keys, expected_keys); + } + + #[test] + fn preserve_order_roundtrip_33_keys() { + let keys: Vec = (0..33).map(|i| format!("key_{}", i)).collect(); + let json_pairs: Vec = keys.iter().map(|k| format!(r#""{}": {}"#, k, 1)).collect(); + let json = format!("{{{}}}", json_pairs.join(", ")); + let mut input = json.into_bytes(); + + let v = to_value(input.as_mut_slice()).expect("valid JSON"); + let mut serialized = v.encode(); + let v2 = to_value(unsafe { serialized.as_bytes_mut() }).expect("valid JSON"); + + let keys1: Vec<&str> = v.as_object().unwrap().keys().map(|k| k.as_ref()).collect(); + let keys2: Vec<&str> = v2.as_object().unwrap().keys().map(|k| k.as_ref()).collect(); + + assert_eq!(keys1, keys2); + } +} diff --git a/src/value/borrowed/ordered/cmp.rs b/src/value/borrowed/ordered/cmp.rs new file mode 100644 index 00000000..f1c7cd64 --- /dev/null +++ b/src/value/borrowed/ordered/cmp.rs @@ -0,0 +1,188 @@ +use super::Value; +use crate::OrderedOwnedValue as OwnedValue; +use crate::prelude::*; + +#[allow(clippy::cast_sign_loss, clippy::default_trait_access)] +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Static(s1), Self::Static(s2)) => s1 == s2, + (Self::String(v1), Self::String(v2)) => v1.eq(v2), + (Self::Array(v1), Self::Array(v2)) => v1.eq(v2), + (Self::Object(v1), Self::Object(v2)) => v1.eq(v2), + _ => false, + } + } +} + +impl<'value, T> PartialEq<&T> for Value<'value> +where + Value<'value>: PartialEq, +{ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &&T) -> bool { + self == *other + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &OwnedValue) -> bool { + // We only need to implement this once + other.eq(self) + } +} + +impl PartialEq<()> for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, _other: &()) -> bool { + self.is_null() + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &bool) -> bool { + self.as_bool().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &str) -> bool { + self.as_str().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq<&str> for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &&str) -> bool { + self == *other + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &String) -> bool { + self.as_str().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &i8) -> bool { + self.as_i8().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &i16) -> bool { + self.as_i16().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &i32) -> bool { + self.as_i32().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &i64) -> bool { + self.as_i64().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &i128) -> bool { + self.as_i128().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &u8) -> bool { + self.as_u8().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &u16) -> bool { + self.as_u16().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &u32) -> bool { + self.as_u32().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &u64) -> bool { + self.as_u64().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &usize) -> bool { + self.as_usize().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &u128) -> bool { + self.as_u128().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &f32) -> bool { + self.as_f32().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &f64) -> bool { + self.as_f64().is_some_and(|t| t.eq(other)) + } +} + +impl<'v, T> PartialEq<&[T]> for Value<'v> +where + Value<'v>: PartialEq, +{ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &&[T]) -> bool { + self.as_array().is_some_and(|t| t.eq(other)) + } +} + +impl<'v, K, T, S> PartialEq> for Value<'v> +where + K: AsRef + std::hash::Hash + Eq, + Value<'v>: PartialEq, + S: std::hash::BuildHasher, +{ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &std::collections::HashMap) -> bool { + self.as_object().is_some_and(|object| { + object.len() == other.len() + && other + .iter() + .all(|(key, value)| object.get(key.as_ref()).is_some_and(|v| *v == *value)) + }) + } +} diff --git a/src/value/borrowed/ordered/from.rs b/src/value/borrowed/ordered/from.rs new file mode 100644 index 00000000..50a5ad12 --- /dev/null +++ b/src/value/borrowed/ordered/from.rs @@ -0,0 +1,144 @@ +use super::Value; +use crate::StaticNode; +use crate::cow::Cow; + +impl<'value> From for Value<'value> { + fn from(s: StaticNode) -> Self { + Self::Static(s) + } +} + +impl<'value> From for Value<'value> { + fn from(v: i8) -> Self { + Self::Static(StaticNode::I64(i64::from(v))) + } +} + +impl<'value> From for Value<'value> { + fn from(v: i16) -> Self { + Self::Static(StaticNode::I64(i64::from(v))) + } +} + +impl<'value> From for Value<'value> { + fn from(v: i32) -> Self { + Self::Static(StaticNode::I64(i64::from(v))) + } +} + +impl<'value> From for Value<'value> { + fn from(v: i64) -> Self { + Self::Static(StaticNode::I64(v)) + } +} + +impl<'value> From for Value<'value> { + fn from(v: u8) -> Self { + Self::Static(StaticNode::U64(u64::from(v))) + } +} + +impl<'value> From for Value<'value> { + fn from(v: u16) -> Self { + Self::Static(StaticNode::U64(u64::from(v))) + } +} + +impl<'value> From for Value<'value> { + fn from(v: u32) -> Self { + Self::Static(StaticNode::U64(u64::from(v))) + } +} + +impl<'value> From for Value<'value> { + fn from(v: u64) -> Self { + Self::Static(StaticNode::U64(v)) + } +} + +impl<'value> From for Value<'value> { + fn from(v: f32) -> Self { + Self::Static(StaticNode::from(f64::from(v))) + } +} + +impl<'value> From for Value<'value> { + fn from(v: f64) -> Self { + Self::Static(StaticNode::from(v)) + } +} + +impl<'value> From for Value<'value> { + fn from(v: bool) -> Self { + Self::Static(StaticNode::Bool(v)) + } +} + +impl<'value> From<()> for Value<'value> { + fn from(_: ()) -> Self { + Self::Static(StaticNode::Null) + } +} + +impl<'value> From for Value<'value> { + fn from(v: String) -> Self { + Self::String(Cow::from(v)) + } +} + +impl<'value> From<&'value str> for Value<'value> { + fn from(v: &'value str) -> Self { + Self::String(Cow::from(v)) + } +} + +impl<'value> From> for Value<'value> { + fn from(v: Cow<'value, str>) -> Self { + Self::String(v) + } +} + +impl<'value, T> From> for Value<'value> +where + Value<'value>: From, +{ + fn from(v: Vec) -> Self { + Self::Array(Box::new(v.into_iter().map(Value::from).collect())) + } +} + +impl<'value, K, S> From, S>> for Value<'value> +where + K: Into>, + S: std::hash::BuildHasher, +{ + fn from(v: indexmap::IndexMap, S>) -> Self { + Self::Object(Box::new(v.into_iter().map(|(k, v)| (k.into(), v)).collect())) + } +} + +impl<'value, V: Into>> FromIterator for Value<'value> { + fn from_iter>(iter: T) -> Self { + Self::Array(Box::new(iter.into_iter().map(Into::into).collect())) + } +} + +impl<'value> std::iter::FromIterator<(Cow<'value, str>, Value<'value>)> for Value<'value> { + fn from_iter, Value<'value>)>>(iter: T) -> Self { + Self::Object(Box::new(iter.into_iter().collect())) + } +} + +#[cfg(feature = "128bit")] +impl<'value> From for Value<'value> { + fn from(i: i128) -> Self { + Self::Static(StaticNode::I128(i)) + } +} + +#[cfg(feature = "128bit")] +impl<'value> From for Value<'value> { + fn from(i: u128) -> Self { + Self::Static(StaticNode::U128(i)) + } +} diff --git a/src/value/borrowed/ordered/serialize.rs b/src/value/borrowed/ordered/serialize.rs new file mode 100644 index 00000000..f6b92e9c --- /dev/null +++ b/src/value/borrowed/ordered/serialize.rs @@ -0,0 +1,273 @@ +// This is mostly taken from json-rust's codegen +// as it seems to perform well and it makes snense to see +// if we can adopt the approach +// +// https://github.com/maciejhirsz/json-rust/blob/master/src/codegen.rs + +use super::{Object, Value}; +use crate::prelude::*; +use std::io; +use std::io::Write; +use value_trait::generator::{ + DumpGenerator, PrettyGenerator, PrettyWriterGenerator, WriterGenerator, +}; + +//use util::print_dec; + +impl Writable for Value<'_> { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn encode(&self) -> String { + let mut g = DumpGenerator::new(); + let _r = g.write_json(self); + g.consume() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn encode_pp(&self) -> String { + let mut g = PrettyGenerator::new(2); + let _r = g.write_json(self); + g.consume() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn write<'writer, W>(&self, w: &mut W) -> io::Result<()> + where + W: 'writer + Write, + { + let mut g = WriterGenerator::new(w); + g.write_json(self) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn write_pp<'writer, W>(&self, w: &mut W) -> io::Result<()> + where + W: 'writer + Write, + { + let mut g = PrettyWriterGenerator::new(w, 2); + g.write_json(self) + } +} + +trait Generator: BaseGenerator { + type T: Write; + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn write_object(&mut self, object: &Object) -> io::Result<()> { + if object.is_empty() { + self.write(b"{}") + } else { + let mut iter = object.iter(); + stry!(self.write(b"{")); + + // We know this exists since it's not empty + let Some((key, value)) = iter.next() else { + // We check against size + unreachable!("object is not empty but has no next"); + }; + self.indent(); + stry!(self.new_line()); + stry!(self.write_simple_string(key)); + stry!(self.write_min(b": ", b':')); + stry!(self.write_json(value)); + + for (key, value) in iter { + stry!(self.write(b",")); + stry!(self.new_line()); + stry!(self.write_simple_string(key)); + stry!(self.write_min(b": ", b':')); + stry!(self.write_json(value)); + } + self.dedent(); + stry!(self.new_line()); + self.write(b"}") + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn write_json(&mut self, json: &Value) -> io::Result<()> { + match *json { + Value::Static(StaticNode::Null) => self.write(b"null"), + Value::Static(StaticNode::I64(number)) => self.write_int(number), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::I128(number)) => self.write_int(number), + Value::Static(StaticNode::U64(number)) => self.write_int(number), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::U128(number)) => self.write_int(number), + #[allow(clippy::useless_conversion)] // .into() required by ordered-float + Value::Static(StaticNode::F64(number)) => self.write_float(number.into()), + Value::Static(StaticNode::Bool(true)) => self.write(b"true"), + Value::Static(StaticNode::Bool(false)) => self.write(b"false"), + Value::String(ref string) => self.write_string(string), + Value::Array(ref array) => { + if array.is_empty() { + self.write(b"[]") + } else { + let mut iter = <[Value]>::iter(array); + // We know we have one item + + let Some(item) = iter.next() else { + // We check against size + unreachable!("array is not empty but has no next"); + }; + stry!(self.write(b"[")); + self.indent(); + + stry!(self.new_line()); + stry!(self.write_json(item)); + + for item in iter { + stry!(self.write(b",")); + stry!(self.new_line()); + stry!(self.write_json(item)); + } + self.dedent(); + stry!(self.new_line()); + self.write(b"]") + } + } + Value::Object(ref object) => self.write_object(object), + } + } +} + +trait FastGenerator: BaseGenerator { + type T: Write; + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn write_object(&mut self, object: &Object) -> io::Result<()> { + if object.is_empty() { + self.write(b"{}") + } else { + let mut iter = object.iter(); + stry!(self.write(b"{\"")); + + // We know this exists since it's not empty + let Some((key, value)) = iter.next() else { + // We check against size + unreachable!("object is not empty but has no next"); + }; + stry!(self.write_simple_str_content(key)); + stry!(self.write(b"\":")); + stry!(self.write_json(value)); + + for (key, value) in iter { + stry!(self.write(b",\"")); + stry!(self.write_simple_str_content(key)); + stry!(self.write(b"\":")); + stry!(self.write_json(value)); + } + self.write(b"}") + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn write_json(&mut self, json: &Value) -> io::Result<()> { + match *json { + Value::Static(StaticNode::Null) => self.write(b"null"), + Value::Static(StaticNode::I64(number)) => self.write_int(number), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::I128(number)) => self.write_int(number), + Value::Static(StaticNode::U64(number)) => self.write_int(number), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::U128(number)) => self.write_int(number), + #[allow(clippy::useless_conversion)] // .into() required by ordered-float + Value::Static(StaticNode::F64(number)) => self.write_float(number.into()), + Value::Static(StaticNode::Bool(true)) => self.write(b"true"), + Value::Static(StaticNode::Bool(false)) => self.write(b"false"), + Value::String(ref string) => self.write_string(string), + Value::Array(ref array) => { + if array.is_empty() { + self.write(b"[]") + } else { + let mut iter = <[Value]>::iter(array); + // We know we have one item + let Some(item) = iter.next() else { + // We check against size + unreachable!("array is not empty but has no next"); + }; + + stry!(self.write(b"[")); + stry!(self.write_json(item)); + + for item in iter { + stry!(self.write(b",")); + stry!(self.write_json(item)); + } + self.write(b"]") + } + } + Value::Object(ref object) => self.write_object(object), + } + } +} + +impl FastGenerator for DumpGenerator { + type T = Vec; +} + +impl Generator for PrettyGenerator { + type T = Vec; +} + +impl FastGenerator for WriterGenerator<'_, W> +where + W: Write, +{ + type T = W; +} + +impl Generator for PrettyWriterGenerator<'_, W> +where + W: Write, +{ + type T = W; +} + +#[cfg(test)] +mod test { + use super::Value; + use crate::prelude::*; + + #[test] + fn null() { + assert_eq!(Value::Static(StaticNode::Null).encode(), "null"); + } + #[test] + fn bool_true() { + assert_eq!(Value::Static(StaticNode::Bool(true)).encode(), "true"); + } + #[test] + fn bool_false() { + assert_eq!(Value::Static(StaticNode::Bool(false)).encode(), "false"); + } + + #[test] + fn obj() { + let mut o = Value::object(); + o.insert("k", ()).expect("insert"); + assert_eq!(o.encode(), r#"{"k":null}"#); + } + + fn assert_str(from: &str, to: &str) { + assert_eq!(Value::String(from.into()).encode(), to); + } + #[test] + fn string() { + assert_str("this is a test", r#""this is a test""#); + assert_str(r#"this is a test ""#, r#""this is a test \"""#); + assert_str(r#"this is a test """#, r#""this is a test \"\"""#); + assert_str( + "this is a test a long test that should span the 32 byte boundary", + r#""this is a test a long test that should span the 32 byte boundary""#, + ); + assert_str( + r#"this is a test a "long" test that should span the 32 byte boundary"#, + r#""this is a test a \"long\" test that should span the 32 byte boundary""#, + ); + + assert_str( + r#"this is a test a \"long\" test that should span the 32 byte boundary"#, + r#""this is a test a \\\"long\\\" test that should span the 32 byte boundary""#, + ); + } +} diff --git a/src/value/lazy/object.rs b/src/value/lazy/object.rs index 77da71e0..597cae9d 100644 --- a/src/value/lazy/object.rs +++ b/src/value/lazy/object.rs @@ -19,6 +19,9 @@ pub enum Iter<'borrow, 'tape, 'input> { Tape(tape::object::Iter<'tape, 'input>), /// Value variant Value(halfbrown::Iter<'borrow, crate::cow::Cow<'input, str>, borrowed::Value<'input>>), + // /// Value variant + // #[cfg(feature = "preserve_order")] + // Value(indexmap::map::Iter<'borrow, crate::cow::Cow<'input, str>, borrowed::Value<'input>>), } /// Iterator over the keys of an object @@ -27,6 +30,9 @@ pub enum Keys<'borrow, 'tape, 'input> { Tape(tape::object::Keys<'tape, 'input>), /// Value variant Value(halfbrown::Keys<'borrow, crate::cow::Cow<'input, str>, borrowed::Value<'input>>), + // /// Value variant + // #[cfg(feature = "preserve_order")] + // Value(indexmap::map::Keys<'borrow, crate::cow::Cow<'input, str>, borrowed::Value<'input>>), } /// Iterator over the values of an object pub enum Values<'borrow, 'tape, 'input> { @@ -34,6 +40,9 @@ pub enum Values<'borrow, 'tape, 'input> { Tape(tape::object::Values<'tape, 'input>), /// Value variant Value(halfbrown::Values<'borrow, crate::cow::Cow<'input, str>, borrowed::Value<'input>>), + // /// Value variant + // #[cfg(feature = "preserve_order")] + // Value(indexmap::map::Values<'borrow, crate::cow::Cow<'input, str>, borrowed::Value<'input>>), } //value_trait::Object for diff --git a/src/value/owned.rs b/src/value/owned.rs index 47d2194d..8796a714 100644 --- a/src/value/owned.rs +++ b/src/value/owned.rs @@ -22,6 +22,9 @@ mod cmp; mod from; mod serialize; +/// Ordered owned value handling. +#[cfg(feature = "preserve_order")] +pub mod ordered; use super::ObjectHasher; use crate::{Buffers, prelude::*}; @@ -947,4 +950,19 @@ mod test { let v: Value = v.into(); assert_eq!(v, 42); } + + #[test] + fn preserve_order_32_keys_baseline() { + let keys: Vec = (0..32).map(|i| format!("key_{}", i)).collect(); + let json_pairs: Vec = keys.iter().map(|k| format!(r#""{}": {}"#, k, 1)).collect(); + let json = format!("{{{}}}", json_pairs.join(", ")); + let mut input = json.into_bytes(); + + let v = to_value(input.as_mut_slice()).expect("valid JSON"); + let obj = v.as_object().expect("is object"); + let result_keys: Vec<&str> = obj.keys().map(|s| s.as_str()).collect(); + let expected_keys: Vec<&str> = keys.iter().map(|s| s.as_str()).collect(); + + assert_eq!(result_keys, expected_keys); + } } diff --git a/src/value/owned/from.rs b/src/value/owned/from.rs index 54b9368a..606277f9 100644 --- a/src/value/owned/from.rs +++ b/src/value/owned/from.rs @@ -1,5 +1,5 @@ use super::{Object, Value}; -use crate::{BorrowedValue, StaticNode}; +use crate::{BorrowedValue, ObjectHasher, StaticNode}; impl From> for Value { #[cfg_attr(not(feature = "no-inline"), inline)] @@ -199,11 +199,13 @@ impl> FromIterator for Value { impl> FromIterator<(K, V)> for Value { #[cfg_attr(not(feature = "no-inline"), inline)] fn from_iter>(iter: I) -> Self { - Self::Object(Box::new( - iter.into_iter() - .map(|(k, v)| (k.to_string(), Into::into(v))) - .collect(), - )) + let iter = iter.into_iter(); + let (lower, _) = iter.size_hint(); + let mut map = Object::with_capacity_and_hasher(lower, ObjectHasher::default()); + for (k, v) in iter { + map.insert(k.to_string(), v.into()); + } + Self::Object(Box::new(map)) } } @@ -220,3 +222,14 @@ impl From> for Value { Self::from(v.into_iter().collect::()) } } + +#[cfg(feature = "preserve_order")] +impl From> for Value +where + K: Into, + S: std::hash::BuildHasher, +{ + fn from(v: indexmap::IndexMap) -> Self { + Self::Object(Box::new(v.into_iter().map(|(k, v)| (k.into(), v)).collect())) + } +} diff --git a/src/value/owned/ordered.rs b/src/value/owned/ordered.rs new file mode 100644 index 00000000..ad887f1b --- /dev/null +++ b/src/value/owned/ordered.rs @@ -0,0 +1,1013 @@ +/// A lifetime less DOM implementation. It uses strings to make te +/// structure fully owned, avoiding lifetimes at the cost of performance. +/// Access via array indexes is possible: +/// ```rust +/// use simd_json::{OwnedValue, json}; +/// use simd_json::prelude::*; +/// let mut a = json!([1, 2, 3]); +/// assert_eq!(a[1], 2); +/// a[1] = 42.into(); +/// assert_eq!(a[1], 42); +/// ``` +/// +/// Access via object keys is possible as well: +/// ```rust +/// use simd_json::{OwnedValue, json}; +/// use simd_json::prelude::*; +/// let mut a = json!({"key": "not the value"}); +/// assert_eq!(a["key"], "not the value"); +/// a["key"] = "value".into(); +/// assert_eq!(a["key"], "value"); +/// ``` +/// Partial equality comparison impls +pub mod cmp; +/// From converter impls +pub mod from; +/// Provide Writable trait +pub mod serialize; + +use super::ObjectHasher; +use crate::{Buffers, prelude::*}; +use crate::{Deserializer, Node, Result}; +use indexmap::IndexMap; +use std::fmt; +use std::ops::{Index, IndexMut}; + +/// Representation of a JSON object +pub type Object = IndexMap; + +/// Parses a slice of bytes into a Value dom. +/// +/// This function will rewrite the slice to de-escape strings. +/// We do not keep any references to the raw data but re-allocate +/// owned memory wherever required thus returning a value without +/// a lifetime. +/// +/// # Errors +/// +/// Will return `Err` if `s` is invalid JSON. +pub fn to_value(s: &mut [u8]) -> Result { + match Deserializer::from_slice(s) { + Ok(de) => Ok(OwnedDeserializer::from_deserializer(de).parse()), + Err(e) => Err(e), + } +} + +/// Parses a slice of bytes into a Value dom. +/// +/// This function will rewrite the slice to de-escape strings. +/// We do not keep any references to the raw data but re-allocate +/// owned memory wherever required thus returning a value without +/// a lifetime. +/// +/// Passes in reusable buffers to reduce allocations. +/// +/// # Errors +/// +/// Will return `Err` if `s` is invalid JSON. +pub fn to_value_with_buffers(s: &mut [u8], buffers: &mut Buffers) -> Result { + match Deserializer::from_slice_with_buffers(s, buffers) { + Ok(de) => Ok(OwnedDeserializer::from_deserializer(de).parse()), + Err(e) => Err(e), + } +} + +/// Owned JSON-DOM Value, consider using the `ValueTrait` +/// to access it's content. +/// This is slower then the `OrderedBorrowedValue` as a tradeoff +/// for getting rid of lifetimes. +#[derive(Debug, Clone)] +#[cfg_attr(feature = "ordered-float", derive(Eq))] +pub enum Value { + /// Static values + Static(StaticNode), + /// string type + String(String), + /// array type + Array(Box>), + /// object type + Object(Box), +} + +impl Value { + fn as_static(&self) -> Option { + match self { + Value::Static(s) => Some(*s), + _ => None, + } + } +} + +impl ValueBuilder<'_> for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn null() -> Self { + Self::Static(StaticNode::Null) + } + #[cfg_attr(not(feature = "no-inline"), inline)] + fn array_with_capacity(capacity: usize) -> Self { + Self::Array(Box::new(Vec::with_capacity(capacity))) + } + #[cfg_attr(not(feature = "no-inline"), inline)] + fn object_with_capacity(capacity: usize) -> Self { + Self::Object(Box::new(Object::with_capacity_and_hasher( + capacity, + ObjectHasher::default(), + ))) + } +} + +impl ValueAsMutArray for Value { + type Array = Vec; + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_array_mut(&mut self) -> Option<&mut Vec> { + match self { + Self::Array(a) => Some(a), + _ => None, + } + } +} +impl ValueAsMutObject for Value { + type Object = Object; + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_object_mut(&mut self) -> Option<&mut Object> { + match self { + Self::Object(m) => Some(m), + _ => None, + } + } +} + +impl TypedValue for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn value_type(&self) -> ValueType { + match self { + Self::Static(s) => s.value_type(), + Self::String(_) => ValueType::String, + Self::Array(_) => ValueType::Array, + Self::Object(_) => ValueType::Object, + } + } +} +impl ValueAsScalar for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_null(&self) -> Option<()> { + self.as_static()?.as_null() + } + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_bool(&self) -> Option { + self.as_static()?.as_bool() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_i64(&self) -> Option { + self.as_static()?.as_i64() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_i128(&self) -> Option { + self.as_static()?.as_i128() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_u64(&self) -> Option { + self.as_static()?.as_u64() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_u128(&self) -> Option { + self.as_static()?.as_u128() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_f64(&self) -> Option { + self.as_static()?.as_f64() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn cast_f64(&self) -> Option { + self.as_static()?.cast_f64() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_str(&self) -> Option<&str> { + match self { + Self::String(s) => Some(s.as_str()), + _ => None, + } + } +} +impl ValueAsArray for Value { + type Array = Vec; + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_array(&self) -> Option<&Vec> { + match self { + Self::Array(a) => Some(a), + _ => None, + } + } +} +impl ValueAsObject for Value { + type Object = Object; + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn as_object(&self) -> Option<&Object> { + match self { + Self::Object(m) => Some(m), + _ => None, + } + } +} + +impl ValueIntoString for Value { + type String = String; + + fn into_string(self) -> Option<::String> { + match self { + Self::String(s) => Some(s), + _ => None, + } + } +} +impl ValueIntoArray for Value { + type Array = Vec; + + fn into_array(self) -> Option<::Array> { + match self { + Self::Array(a) => Some(*a), + _ => None, + } + } +} +impl ValueIntoObject for Value { + type Object = Object; + + fn into_object(self) -> Option<::Object> { + match self { + Self::Object(a) => Some(*a), + _ => None, + } + } +} + +#[cfg(not(tarpaulin_include))] +impl fmt::Display for Value { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Static(s) => s.fmt(f), + Self::String(s) => write!(f, "{s}"), + Self::Array(a) => write!(f, "{a:?}"), + Self::Object(o) => write!(f, "{o:?}"), + } + } +} + +impl Index<&str> for Value { + type Output = Self; + #[cfg_attr(not(feature = "no-inline"), inline)] + fn index(&self, index: &str) -> &Self::Output { + self.get(index).expect("index out of bounds") + } +} + +impl Index for Value { + type Output = Self; + #[cfg_attr(not(feature = "no-inline"), inline)] + fn index(&self, index: usize) -> &Self::Output { + self.get_idx(index).expect("index out of bounds") + } +} + +impl IndexMut<&str> for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn index_mut(&mut self, index: &str) -> &mut Self::Output { + self.get_mut(index).expect("index out of bounds") + } +} + +impl IndexMut for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.get_idx_mut(index).expect("index out of bounds") + } +} + +impl Default for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn default() -> Self { + Self::Static(StaticNode::Null) + } +} + +struct OwnedDeserializer<'de> { + de: Deserializer<'de>, +} + +impl<'de> OwnedDeserializer<'de> { + pub fn from_deserializer(de: Deserializer<'de>) -> Self { + Self { de } + } + #[cfg_attr(not(feature = "no-inline"), inline)] + pub fn parse(&mut self) -> Value { + match unsafe { self.de.next_() } { + Node::Static(s) => Value::Static(s), + Node::String(s) => Value::from(s), + Node::Array { len, count: _ } => self.parse_array(len), + Node::Object { len, count: _ } => self.parse_map(len), + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn parse_array(&mut self, len: usize) -> Value { + // Rust doesn't optimize the normal loop away here + // so we write our own avoiding the length + // checks during push + let mut res: Vec = Vec::with_capacity(len); + let res_ptr = res.as_mut_ptr(); + unsafe { + for i in 0..len { + res_ptr.add(i).write(self.parse()); + } + res.set_len(len); + } + Value::Array(Box::new(res)) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn parse_map(&mut self, len: usize) -> Value { + let mut res = Object::with_capacity_and_hasher(len, ObjectHasher::default()); + + for _ in 0..len { + if let Node::String(key) = unsafe { self.de.next_() } { + res.insert(key.into(), self.parse()); + } else { + unreachable!("parse_map: key needs to be a string"); + } + } + Value::from(res) + } +} + +#[cfg(test)] +mod test { + #![allow(clippy::cognitive_complexity, clippy::ignored_unit_patterns)] + use super::*; + + #[test] + fn object_access() { + let mut v = Value::null(); + assert_eq!(v.insert("key", ()), Err(AccessError::NotAnObject)); + assert_eq!(v.remove("key"), Err(AccessError::NotAnObject)); + let mut v = Value::object(); + assert_eq!(v.insert("key", 1), Ok(None)); + assert_eq!(v["key"], Value::from(1)); + assert_eq!(v.insert("key", 2), Ok(Some(Value::from(1)))); + v["key"] = 3.into(); + assert_eq!(v.remove("key"), Ok(Some(Value::from(3)))); + } + + #[test] + fn array_access() { + let mut v = Value::null(); + assert_eq!(v.push("key"), Err(AccessError::NotAnArray)); + assert_eq!(v.pop(), Err(AccessError::NotAnArray)); + let mut v = Value::array(); + assert_eq!(v.push(1), Ok(())); + assert_eq!(v.push(2), Ok(())); + assert_eq!(v[0], Value::from(1)); + v[0] = 0.into(); + v[1] = 1.into(); + assert_eq!(v.pop(), Ok(Some(Value::from(1)))); + assert_eq!(v.pop(), Ok(Some(Value::from(0)))); + assert_eq!(v.pop(), Ok(None)); + } + + #[cfg(feature = "128bit")] + #[test] + fn conversions_i128() { + let v = Value::from(i128::MAX); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(!v.is_i64()); + assert!(!v.is_u64()); + assert!(!v.is_i32()); + assert!(!v.is_u32()); + assert!(!v.is_i16()); + assert!(!v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + let v = Value::from(i128::MIN); + assert!(v.is_i128()); + assert!(!v.is_u128()); + assert!(!v.is_i64()); + assert!(!v.is_u64()); + assert!(!v.is_i32()); + assert!(!v.is_u32()); + assert!(!v.is_i16()); + assert!(!v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + #[test] + fn conversions_i64() { + let v = Value::from(i64::MAX); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(!v.is_i32()); + assert!(!v.is_u32()); + assert!(!v.is_i16()); + assert!(!v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + let v = Value::from(i64::MIN); + assert!(v.is_i128()); + assert!(!v.is_u128()); + assert!(v.is_i64()); + assert!(!v.is_u64()); + assert!(!v.is_i32()); + assert!(!v.is_u32()); + assert!(!v.is_i16()); + assert!(!v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_i32() { + let v = Value::from(i32::MAX); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(v.is_i32()); + assert!(v.is_u32()); + assert!(!v.is_i16()); + assert!(!v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + let v = Value::from(i32::MIN); + assert!(v.is_i128()); + assert!(!v.is_u128()); + assert!(v.is_i64()); + assert!(!v.is_u64()); + assert!(v.is_i32()); + assert!(!v.is_u32()); + assert!(!v.is_i16()); + assert!(!v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_i16() { + let v = Value::from(i16::MAX); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(v.is_i32()); + assert!(v.is_u32()); + assert!(v.is_i16()); + assert!(v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + let v = Value::from(i16::MIN); + assert!(v.is_i128()); + assert!(!v.is_u128()); + assert!(v.is_i64()); + assert!(!v.is_u64()); + assert!(v.is_i32()); + assert!(!v.is_u32()); + assert!(v.is_i16()); + assert!(!v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_i8() { + let v = Value::from(i8::MAX); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(v.is_i32()); + assert!(v.is_u32()); + assert!(v.is_i16()); + assert!(v.is_u16()); + assert!(v.is_i8()); + assert!(v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + let v = Value::from(i8::MIN); + assert!(v.is_i128()); + assert!(!v.is_u128()); + assert!(v.is_i64()); + assert!(!v.is_u64()); + assert!(v.is_i32()); + assert!(!v.is_u32()); + assert!(v.is_i16()); + assert!(!v.is_u16()); + assert!(v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_usize() { + let v = Value::from(usize::MIN as u64); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(v.is_usize()); + assert!(v.is_i32()); + assert!(v.is_u32()); + assert!(v.is_i16()); + assert!(v.is_u16()); + assert!(v.is_i8()); + assert!(v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[cfg(feature = "128bit")] + #[test] + fn conversions_u128() { + let v = Value::from(u128::MIN); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(v.is_i32()); + assert!(v.is_u32()); + assert!(v.is_i16()); + assert!(v.is_u16()); + assert!(v.is_i8()); + assert!(v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + #[test] + fn conversions_u64() { + let v = Value::from(u64::MIN); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(v.is_i32()); + assert!(v.is_u32()); + assert!(v.is_i16()); + assert!(v.is_u16()); + assert!(v.is_i8()); + assert!(v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_u32() { + let v = Value::from(u32::MAX); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(!v.is_i32()); + assert!(v.is_u32()); + assert!(!v.is_i16()); + assert!(!v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_u16() { + let v = Value::from(u16::MAX); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(v.is_i32()); + assert!(v.is_u32()); + assert!(!v.is_i16()); + assert!(v.is_u16()); + assert!(!v.is_i8()); + assert!(!v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_u8() { + let v = Value::from(u8::MAX); + assert!(v.is_i128()); + assert!(v.is_u128()); + assert!(v.is_i64()); + assert!(v.is_u64()); + assert!(v.is_i32()); + assert!(v.is_u32()); + assert!(v.is_i16()); + assert!(v.is_u16()); + assert!(!v.is_i8()); + assert!(v.is_u8()); + assert!(!v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_f64() { + let v = Value::from(f64::MAX); + assert!(!v.is_i64()); + assert!(!v.is_u64()); + assert!(v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + let v = Value::from(f64::MIN); + assert!(!v.is_i64()); + assert!(!v.is_u64()); + assert!(v.is_f64()); + assert!(!v.is_f32()); + assert!(v.is_f64_castable()); + let v = Value::from("not a f64"); + assert!(!v.is_f64_castable()); + } + + #[test] + fn conversions_f32() { + let v = Value::from(f32::MAX); + assert!(!v.is_i64()); + assert!(!v.is_u64()); + assert!(v.is_f64()); + assert!(v.is_f32()); + assert!(v.is_f64_castable()); + let v = Value::from(f32::MIN); + assert!(!v.is_i64()); + assert!(!v.is_u64()); + assert!(v.is_f64()); + assert!(v.is_f32()); + assert!(v.is_f64_castable()); + } + + #[test] + fn conversions_array() { + let v = Value::from(vec![true]); + assert!(v.is_array()); + assert_eq!(v.value_type(), ValueType::Array); + let v = Value::from("no array"); + assert!(!v.is_array()); + } + + #[test] + fn conversions_bool() { + let v = Value::from(true); + assert!(v.is_bool()); + assert_eq!(v.value_type(), ValueType::Bool); + let v = Value::from("no bool"); + assert!(!v.is_bool()); + } + + #[test] + fn conversions_float() { + let v = Value::from(42.0); + assert!(v.is_f64()); + assert_eq!(v.value_type(), ValueType::F64); + let v = Value::from("no float"); + assert!(!v.is_f64()); + } + + #[test] + fn conversions_int() { + let v = Value::from(-42); + assert!(v.is_i64()); + assert_eq!(v.value_type(), ValueType::I64); + #[cfg(feature = "128bit")] + { + let v = Value::from(-42_i128); + assert!(v.is_i64()); + assert!(v.is_i128()); + assert_eq!(v.value_type(), ValueType::I128); + } + let v = Value::from("no i64"); + assert!(!v.is_i64()); + #[cfg(feature = "128bit")] + assert!(!v.is_i128()); + } + + #[test] + fn conversions_uint() { + let v = Value::from(42_u64); + assert!(v.is_u64()); + assert_eq!(v.value_type(), ValueType::U64); + #[cfg(feature = "128bit")] + { + let v = Value::from(42_u128); + assert!(v.is_u64()); + assert!(v.is_u128()); + assert_eq!(v.value_type(), ValueType::U128); + } + let v = Value::from("no u64"); + assert!(!v.is_u64()); + #[cfg(feature = "128bit")] + assert!(!v.is_u128()); + } + + #[test] + fn conversions_null() { + let v = Value::from(()); + assert!(v.is_null()); + assert_eq!(v.value_type(), ValueType::Null); + let v = Value::from("no null"); + assert!(!v.is_null()); + } + + #[test] + fn conversions_object() { + let v = Value::from(Object::with_capacity_and_hasher(0, ObjectHasher::default())); + assert!(v.is_object()); + assert_eq!(v.value_type(), ValueType::Object); + let v = Value::from("no object"); + assert!(!v.is_object()); + } + + #[test] + fn conversions_str() { + let v = Value::from("bla"); + assert!(v.is_str()); + assert_eq!(v.value_type(), ValueType::String); + let v = Value::from(42); + assert!(!v.is_str()); + } + + #[test] + fn default() { + assert_eq!(Value::default(), Value::null()); + } + + #[cfg(not(target_arch = "wasm32"))] + use proptest::prelude::*; + #[cfg(not(target_arch = "wasm32"))] + fn arb_value() -> BoxedStrategy { + let leaf = prop_oneof![ + Just(Value::Static(StaticNode::Null)), + any::() + .prop_map(StaticNode::Bool) + .prop_map(Value::Static), + any::() + .prop_map(StaticNode::I64) + .prop_map(Value::Static), + any::() + .prop_map(StaticNode::from) + .prop_map(Value::Static), + ".*".prop_map(Value::from), + ]; + leaf.prop_recursive( + 8, // 8 levels deep + 256, // Shoot for maximum size of 256 nodes + 10, // We put up to 10 items per collection + |inner| { + prop_oneof![ + // Take the inner strategy and make the two recursive cases. + prop::collection::vec(inner.clone(), 0..10).prop_map(Value::from), + prop::collection::hash_map(".*", inner, 0..10) + .prop_map(|m| m.into_iter().collect()), + ] + }, + ) + .boxed() + } + + #[cfg(not(target_arch = "wasm32"))] + proptest! { + #![proptest_config(ProptestConfig { + .. ProptestConfig::default() + })] + + #[test] + fn prop_to_owned(owned in arb_value()) { + use crate::OrderedBorrowedValue; + let borrowed: OrderedBorrowedValue = owned.clone().into(); + prop_assert_eq!(owned, borrowed); + } + + #[test] + fn prop_serialize_deserialize(owned in arb_value()) { + let mut string = owned.encode(); + let bytes = unsafe{ string.as_bytes_mut()}; + let decoded = to_value(bytes).expect("Failed to decode"); + prop_assert_eq!(owned, decoded); + } + #[test] + #[allow(clippy::float_cmp)] + fn prop_f64_cmp(f in proptest::num::f64::NORMAL) { + let v: Value = f.into(); + prop_assert_eq!(v, f); + + } + + #[test] + #[allow(clippy::float_cmp)] + fn prop_f32_cmp(f in proptest::num::f32::NORMAL) { + let v: Value = f.into(); + prop_assert_eq!(v, f); + + } + #[test] + fn prop_i64_cmp(f in proptest::num::i64::ANY) { + let v: Value = f.into(); + prop_assert_eq!(v, f); + } + #[test] + fn prop_i32_cmp(f in proptest::num::i32::ANY) { + let v: Value = f.into(); + prop_assert_eq!(v, f); + } + #[test] + fn prop_i16_cmp(f in proptest::num::i16::ANY) { + let v: Value = f.into(); + prop_assert_eq!(v, f); + } + #[test] + fn prop_i8_cmp(f in proptest::num::i8::ANY) { + let v: Value = f.into(); + prop_assert_eq!(v, f); + } + #[test] + fn prop_u64_cmp(f in proptest::num::u64::ANY) { + let v: Value = f.into(); + prop_assert_eq!(v, f); + } + + #[test] + fn prop_usize_cmp(f in proptest::num::usize::ANY) { + let v: Value = f.into(); + prop_assert_eq!(v, f); + } + #[test] + fn prop_u32_cmp(f in proptest::num::u32::ANY) { + let v: Value = f.into(); + prop_assert_eq!(v, f); + } + #[test] + fn prop_u16_cmp(f in proptest::num::u16::ANY) { + let v: Value = f.into(); + prop_assert_eq!(v, f); + } + #[test] + fn prop_u8_cmp(f in proptest::num::u8::ANY) { + let v: Value = f.into(); + prop_assert_eq!(v.clone(), Value::from(*&f)); + prop_assert_eq!(v, f); + } + #[test] + fn prop_string_cmp(f in ".*") { + let v: Value = f.clone().into(); + prop_assert_eq!(v.clone(), Value::from(f.as_str())); + prop_assert_eq!(v, f); + } + + } + #[test] + fn test_union_cmp() { + let v: Value = ().into(); + assert_eq!(v, ()); + } + #[test] + #[allow(clippy::bool_assert_comparison)] + fn test_bool_cmp() { + let v: Value = true.into(); + assert_eq!(v, true); + let v: Value = false.into(); + assert_eq!(v, false); + } + #[test] + fn test_slice_cmp() { + use std::iter::FromIterator; + let v: Value = Value::from_iter(vec!["a", "b"]); + assert_eq!(v, &["a", "b"][..]); + } + #[test] + fn test_hashmap_cmp() { + use std::iter::FromIterator; + let v: Value = Value::from_iter(vec![("a", 1)]); + assert_eq!( + v, + [("a", 1)] + .iter() + .copied() + .collect::>() + ); + } + #[test] + fn test_option_from() { + let v: Option = None; + let v: Value = v.into(); + assert_eq!(v, ()); + let v: Option = Some(42); + let v: Value = v.into(); + assert_eq!(v, 42); + } + + #[test] + fn preserve_order_32_keys_baseline() { + let keys: Vec = (0..32).map(|i| format!("key_{}", i)).collect(); + let json_pairs: Vec = keys.iter().map(|k| format!(r#""{}": {}"#, k, 1)).collect(); + let json = format!("{{{}}}", json_pairs.join(", ")); + let mut input = json.into_bytes(); + + let v = to_value(input.as_mut_slice()).expect("valid JSON"); + let obj = v.as_object().expect("is object"); + let result_keys: Vec<&str> = obj.keys().map(|s| s.as_str()).collect(); + let expected_keys: Vec<&str> = keys.iter().map(|s| s.as_str()).collect(); + + assert_eq!(result_keys, expected_keys); + } + + #[cfg(feature = "preserve_order")] + #[test] + fn preserve_order_33_keys() { + let keys: Vec = (0..33).map(|i| format!("key_{}", i)).collect(); + let json_pairs: Vec = keys.iter().map(|k| format!(r#""{}": {}"#, k, 1)).collect(); + let json = format!("{{{}}}", json_pairs.join(", ")); + let mut input = json.into_bytes(); + + let v = to_value(input.as_mut_slice()).expect("valid JSON"); + let obj = v.as_object().expect("is object"); + let result_keys: Vec<&str> = obj.keys().map(|s| s.as_str()).collect(); + let expected_keys: Vec<&str> = keys.iter().map(|s| s.as_str()).collect(); + + assert_eq!(result_keys, expected_keys); + } + + #[cfg(feature = "preserve_order")] + #[test] + fn preserve_order_50_keys() { + let keys: Vec = (0..50).map(|i| format!("key_{}", i)).collect(); + let json_pairs: Vec = keys.iter().map(|k| format!(r#""{}": {}"#, k, 1)).collect(); + let json = format!("{{{}}}", json_pairs.join(", ")); + let mut input = json.into_bytes(); + + let v = to_value(input.as_mut_slice()).expect("valid JSON"); + let obj = v.as_object().expect("is object"); + let result_keys: Vec<&str> = obj.keys().map(|s| s.as_str()).collect(); + let expected_keys: Vec<&str> = keys.iter().map(|s| s.as_str()).collect(); + + assert_eq!(result_keys, expected_keys); + } + + #[cfg(feature = "preserve_order")] + #[test] + fn preserve_order_roundtrip_33_keys() { + let keys: Vec = (0..33).map(|i| format!("key_{}", i)).collect(); + let json_pairs: Vec = keys.iter().map(|k| format!(r#""{}": {}"#, k, 1)).collect(); + let json = format!("{{{}}}", json_pairs.join(", ")); + let mut input = json.into_bytes(); + + let v = to_value(input.as_mut_slice()).expect("valid JSON"); + let mut serialized = v.encode(); + let v2 = to_value(unsafe { serialized.as_bytes_mut() }).expect("valid JSON"); + + let keys1: Vec<&str> = v.as_object().unwrap().keys().map(|s| s.as_str()).collect(); + let keys2: Vec<&str> = v2.as_object().unwrap().keys().map(|s| s.as_str()).collect(); + + assert_eq!(keys1, keys2); + } +} diff --git a/src/value/owned/ordered/cmp.rs b/src/value/owned/ordered/cmp.rs new file mode 100644 index 00000000..eb1625c2 --- /dev/null +++ b/src/value/owned/ordered/cmp.rs @@ -0,0 +1,198 @@ +use super::Value; +use crate::{OrderedBorrowedValue as BorrowedValue, prelude::*}; + +#[allow(clippy::cast_sign_loss, clippy::default_trait_access)] +impl PartialEq> for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &BorrowedValue<'_>) -> bool { + match (self, other) { + (Self::Static(s1), BorrowedValue::Static(s2)) => s1 == s2, + (Self::String(v1), BorrowedValue::String(v2)) => v1.eq(v2), + (Self::Array(v1), BorrowedValue::Array(v2)) => v1.as_ref().eq(v2.as_ref()), + (Self::Object(v1), BorrowedValue::Object(v2)) => { + if v1.len() != v2.len() { + return false; + } + v1.iter() + .all(|(key, value)| v2.get(key.as_str()).is_some_and(|v| value == v)) + } + _ => false, + } + } +} + +#[allow(clippy::cast_sign_loss, clippy::default_trait_access)] +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Static(s1), Self::Static(s2)) => s1.eq(s2), + (Self::String(v1), Self::String(v2)) => v1.eq(v2), + (Self::Array(v1), Self::Array(v2)) => v1.eq(v2), + (Self::Object(v1), Self::Object(v2)) => v1.eq(v2), + _ => false, + } + } +} + +impl PartialEq<&T> for Value +where + Value: PartialEq, +{ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &&T) -> bool { + self == *other + } +} + +impl PartialEq<()> for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, _other: &()) -> bool { + self.is_null() + } +} + +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &bool) -> bool { + self.as_bool().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &str) -> bool { + self.as_str().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq<&str> for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &&str) -> bool { + self == *other + } +} + +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &String) -> bool { + self.as_str().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &i8) -> bool { + self.as_i8().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &i16) -> bool { + self.as_i16().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &i32) -> bool { + self.as_i32().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &i64) -> bool { + self.as_i64().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &i128) -> bool { + self.as_i128().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &u8) -> bool { + self.as_u8().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &u16) -> bool { + self.as_u16().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &u32) -> bool { + self.as_u32().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &u64) -> bool { + self.as_u64().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &usize) -> bool { + self.as_usize().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &u128) -> bool { + self.as_u128().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &f32) -> bool { + self.as_f32().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &f64) -> bool { + self.as_f64().is_some_and(|t| t.eq(other)) + } +} + +impl PartialEq<&[T]> for Value +where + Value: PartialEq, +{ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &&[T]) -> bool { + self.as_array().is_some_and(|t| t.eq(other)) + } +} +impl PartialEq> for Value +where + K: AsRef + std::hash::Hash + Eq, + Value: PartialEq, + S: std::hash::BuildHasher, +{ + #[cfg_attr(not(feature = "no-inline"), inline)] + fn eq(&self, other: &std::collections::HashMap) -> bool { + self.as_object().is_some_and(|object| { + object.len() == other.len() + && other + .iter() + .all(|(key, value)| object.get(key.as_ref()).is_some_and(|v| *v == *value)) + }) + } +} diff --git a/src/value/owned/ordered/from.rs b/src/value/owned/ordered/from.rs new file mode 100644 index 00000000..857f6a63 --- /dev/null +++ b/src/value/owned/ordered/from.rs @@ -0,0 +1,187 @@ +use super::Value; +use crate::StaticNode; +use crate::cow::Cow; + +impl From for Value { + fn from(s: StaticNode) -> Self { + Self::Static(s) + } +} + +impl From for Value { + fn from(v: i8) -> Self { + Self::Static(StaticNode::I64(i64::from(v))) + } +} + +impl From for Value { + fn from(v: i16) -> Self { + Self::Static(StaticNode::I64(i64::from(v))) + } +} + +impl From for Value { + fn from(v: i32) -> Self { + Self::Static(StaticNode::I64(i64::from(v))) + } +} + +impl From for Value { + fn from(v: i64) -> Self { + Self::Static(StaticNode::I64(v)) + } +} + +impl From for Value { + fn from(v: u8) -> Self { + Self::Static(StaticNode::U64(u64::from(v))) + } +} + +impl From for Value { + fn from(v: u16) -> Self { + Self::Static(StaticNode::U64(u64::from(v))) + } +} + +impl From for Value { + fn from(v: u32) -> Self { + Self::Static(StaticNode::U64(u64::from(v))) + } +} + +impl From for Value { + fn from(v: u64) -> Self { + Self::Static(StaticNode::U64(v)) + } +} + +impl From for Value { + fn from(v: f32) -> Self { + Self::Static(StaticNode::from(f64::from(v))) + } +} + +impl From for Value { + fn from(v: f64) -> Self { + Self::Static(StaticNode::from(v)) + } +} + +impl From for Value { + fn from(v: bool) -> Self { + Self::Static(StaticNode::Bool(v)) + } +} + +impl From<()> for Value { + fn from(_: ()) -> Self { + Self::Static(StaticNode::Null) + } +} + +impl From for Value { + fn from(v: String) -> Self { + Self::String(v) + } +} + +impl From<&str> for Value { + fn from(v: &str) -> Self { + Self::String(v.to_string()) + } +} + +impl From> for Value { + fn from(v: Cow<'_, str>) -> Self { + Self::String(v.into_owned()) + } +} + +impl From> for Value +where + Value: From, +{ + fn from(v: Vec) -> Self { + Self::Array(Box::new(v.into_iter().map(Value::from).collect())) + } +} + +impl From> for Value +where + K: Into, + S: std::hash::BuildHasher, +{ + fn from(v: indexmap::IndexMap) -> Self { + Self::Object(Box::new(v.into_iter().map(|(k, v)| (k.into(), v)).collect())) + } +} + +impl> FromIterator for Value { + fn from_iter>(iter: T) -> Self { + Self::Array(Box::new(iter.into_iter().map(Into::into).collect())) + } +} + +impl FromIterator<(K, V)> for Value +where + K: Into, + V: Into, +{ + fn from_iter>(iter: T) -> Self { + Self::Object(Box::new( + iter.into_iter() + .map(|(k, v)| (k.into(), v.into())) + .collect() + )) + } +} + +impl From for Value { + fn from(v: usize) -> Self { + Self::Static(StaticNode::U64(v as u64)) + } +} + +impl From> for Value +where + Value: From, +{ + fn from(v: Option) -> Self { + match v { + Some(val) => Value::from(val), + None => Value::Static(StaticNode::Null), + } + } +} + +impl<'a> From for crate::value::borrowed::ordered::Value<'a> { + fn from(v: Value) -> Self { + match v { + Value::Static(s) => crate::value::borrowed::ordered::Value::Static(s), + Value::String(s) => crate::value::borrowed::ordered::Value::String(Cow::from(s)), + Value::Array(arr) => crate::value::borrowed::ordered::Value::Array(Box::new( + arr.into_iter().map(Into::into).collect() + )), + Value::Object(obj) => crate::value::borrowed::ordered::Value::Object(Box::new( + obj.into_iter() + .map(|(k, v)| (Cow::from(k), v.into())) + .collect() + )), + } + } +} + +#[cfg(feature = "128bit")] +impl From for Value { + fn from(i: i128) -> Self { + Self::Static(StaticNode::I128(i)) + } +} + +#[cfg(feature = "128bit")] +impl From for Value { + fn from(i: u128) -> Self { + Self::Static(StaticNode::U128(i)) + } +} diff --git a/src/value/owned/ordered/serialize.rs b/src/value/owned/ordered/serialize.rs new file mode 100644 index 00000000..14193dbd --- /dev/null +++ b/src/value/owned/ordered/serialize.rs @@ -0,0 +1,275 @@ +// This is mostly taken from json-rust's codegen +// as it seems to perform well and it makes sense to see +// if we can adopt the approach +// +// https://github.com/maciejhirsz/json-rust/blob/master/src/codegen.rs + +use super::{Object, Value}; +use crate::prelude::*; +use std::io; +use std::io::Write; +use value_trait::generator::{ + DumpGenerator, PrettyGenerator, PrettyWriterGenerator, WriterGenerator, +}; + +//use util::print_dec; + +impl Writable for Value { + #[cfg_attr(not(feature = "no-inline"), inline)] + fn encode(&self) -> String { + let mut g = DumpGenerator::new(); + let _r = g.write_json(self); + g.consume() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn encode_pp(&self) -> String { + let mut g = PrettyGenerator::new(2); + let _r = g.write_json(self); + g.consume() + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn write<'writer, W>(&self, w: &mut W) -> io::Result<()> + where + W: 'writer + Write, + { + let mut g = WriterGenerator::new(w); + g.write_json(self) + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn write_pp<'writer, W>(&self, w: &mut W) -> io::Result<()> + where + W: 'writer + Write, + { + let mut g = PrettyWriterGenerator::new(w, 2); + g.write_json(self) + } +} + +trait Generator: BaseGenerator { + type T: Write; + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn write_object(&mut self, object: &Object) -> io::Result<()> { + if object.is_empty() { + self.write(b"{}") + } else { + let mut iter = object.iter(); + stry!(self.write(b"{")); + + // We know this exists since it's not empty + let Some((key, value)) = iter.next() else { + // We check against size + unreachable!("object is not empty but has no next"); + }; + self.indent(); + stry!(self.new_line()); + stry!(self.write_simple_string(key)); + stry!(self.write_min(b": ", b':')); + stry!(self.write_json(value)); + + for (key, value) in iter { + stry!(self.write(b",")); + stry!(self.new_line()); + stry!(self.write_simple_string(key)); + stry!(self.write_min(b": ", b':')); + stry!(self.write_json(value)); + } + self.dedent(); + stry!(self.new_line()); + self.write(b"}") + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn write_json(&mut self, json: &Value) -> io::Result<()> { + match *json { + Value::Static(StaticNode::Null) => self.write(b"null"), + Value::Static(StaticNode::I64(number)) => self.write_int(number), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::I128(number)) => self.write_int(number), + Value::Static(StaticNode::U64(number)) => self.write_int(number), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::U128(number)) => self.write_int(number), + #[allow(clippy::useless_conversion)] // .into() required by ordered-float + Value::Static(StaticNode::F64(number)) => self.write_float(number.into()), + Value::Static(StaticNode::Bool(true)) => self.write(b"true"), + Value::Static(StaticNode::Bool(false)) => self.write(b"false"), + Value::String(ref string) => self.write_string(string), + Value::Array(ref array) => { + if array.is_empty() { + self.write(b"[]") + } else { + let mut iter = <[Value]>::iter(array); + // We know we have one item + + let Some(item) = iter.next() else { + // We check against size + unreachable!("array is not empty but has no next"); + }; + + stry!(self.write(b"[")); + + self.indent(); + stry!(self.new_line()); + stry!(self.write_json(item)); + + for item in iter { + stry!(self.write(b",")); + stry!(self.new_line()); + stry!(self.write_json(item)); + } + + self.dedent(); + stry!(self.new_line()); + self.write(b"]") + } + } + Value::Object(ref object) => self.write_object(object), + } + } +} + +trait FastGenerator: BaseGenerator { + type T: Write; + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn write_object(&mut self, object: &Object) -> io::Result<()> { + if object.is_empty() { + self.write(b"{}") + } else { + let mut iter = object.iter(); + stry!(self.write(b"{\"")); + + // We know this exists since it's not empty + let Some((key, value)) = iter.next() else { + // We check against size + unreachable!("object is not empty but has no next"); + }; + stry!(self.write_simple_str_content(key)); + stry!(self.write(b"\":")); + stry!(self.write_json(value)); + + for (key, value) in iter { + stry!(self.write(b",\"")); + stry!(self.write_simple_str_content(key)); + stry!(self.write(b"\":")); + stry!(self.write_json(value)); + } + self.write(b"}") + } + } + + #[cfg_attr(not(feature = "no-inline"), inline)] + fn write_json(&mut self, json: &Value) -> io::Result<()> { + match *json { + Value::Static(StaticNode::Null) => self.write(b"null"), + Value::Static(StaticNode::I64(number)) => self.write_int(number), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::I128(number)) => self.write_int(number), + Value::Static(StaticNode::U64(number)) => self.write_int(number), + #[cfg(feature = "128bit")] + Value::Static(StaticNode::U128(number)) => self.write_int(number), + #[allow(clippy::useless_conversion)] // .into() required by ordered-float + Value::Static(StaticNode::F64(number)) => self.write_float(number.into()), + Value::Static(StaticNode::Bool(true)) => self.write(b"true"), + Value::Static(StaticNode::Bool(false)) => self.write(b"false"), + Value::String(ref string) => self.write_string(string), + Value::Array(ref array) => { + if array.is_empty() { + self.write(b"[]") + } else { + let mut iter = <[Value]>::iter(array); + // We know we have one item + let Some(item) = iter.next() else { + // We check against size + unreachable!("array is not empty but has no next"); + }; + + stry!(self.write(b"[")); + stry!(self.write_json(item)); + + for item in iter { + stry!(self.write(b",")); + stry!(self.write_json(item)); + } + self.write(b"]") + } + } + Value::Object(ref object) => self.write_object(object), + } + } +} + +impl FastGenerator for DumpGenerator { + type T = Vec; +} + +impl Generator for PrettyGenerator { + type T = Vec; +} + +impl FastGenerator for WriterGenerator<'_, W> +where + W: Write, +{ + type T = W; +} + +impl Generator for PrettyWriterGenerator<'_, W> +where + W: Write, +{ + type T = W; +} + +#[cfg(test)] +mod test { + use super::Value; + use crate::prelude::*; + + #[test] + fn null() { + assert_eq!(Value::Static(StaticNode::Null).encode(), "null"); + } + #[test] + fn bool_true() { + assert_eq!(Value::Static(StaticNode::Bool(true)).encode(), "true"); + } + #[test] + fn bool_false() { + assert_eq!(Value::Static(StaticNode::Bool(false)).encode(), "false"); + } + + #[test] + fn obj() { + let mut o = Value::object(); + o.insert("k", ()).expect("insert"); + assert_eq!(o.encode(), r#"{"k":null}"#); + } + fn assert_str(from: &str, to: &str) { + assert_eq!(Value::String(from.into()).encode(), to); + } + + #[test] + fn string() { + assert_str("this is a test", r#""this is a test""#); + assert_str(r#"this is a test ""#, r#""this is a test \"""#); + assert_str(r#"this is a test """#, r#""this is a test \"\"""#); + assert_str( + "this is a test a long test that should span the 32 byte boundary", + r#""this is a test a long test that should span the 32 byte boundary""#, + ); + assert_str( + r#"this is a test a "long" test that should span the 32 byte boundary"#, + r#""this is a test a \"long\" test that should span the 32 byte boundary""#, + ); + + assert_str( + r#"this is a test a \"long\" test that should span the 32 byte boundary"#, + r#""this is a test a \\\"long\\\" test that should span the 32 byte boundary""#, + ); + } +} From f0b0e0860683f2b9cfa2810a775cfdbe5aebe612 Mon Sep 17 00:00:00 2001 From: Louis Maddox Date: Mon, 13 Oct 2025 23:20:44 +0100 Subject: [PATCH 2/6] fix: serde module updates (WIP) --- src/serde/value.rs | 14 +++++++++++++ src/serde/value/borrowed/ordered.rs | 27 ++++++++++++++++++++++++++ src/serde/value/borrowed/ordered/de.rs | 20 +++++++++---------- src/serde/value/owned/ordered.rs | 27 ++++++++++++++++++++++++++ src/serde/value/owned/ordered/de.rs | 16 +++++++-------- 5 files changed, 86 insertions(+), 18 deletions(-) diff --git a/src/serde/value.rs b/src/serde/value.rs index adc592d5..e2e088b3 100644 --- a/src/serde/value.rs +++ b/src/serde/value.rs @@ -9,3 +9,17 @@ pub use self::owned::from_value as from_owned_value; pub use self::borrowed::to_value as to_borrowed_value; pub use self::owned::to_value as to_owned_value; + +#[cfg(feature = "preserve_order")] +pub use self::borrowed::ordered::from_refvalue as from_refborrowed_ordered_value; +#[cfg(feature = "preserve_order")] +pub use self::borrowed::ordered::from_value as from_borrowed_ordered_value; +#[cfg(feature = "preserve_order")] +pub use self::owned::ordered::from_refvalue as from_refowned_ordered_value; +#[cfg(feature = "preserve_order")] +pub use self::owned::ordered::from_value as from_owned_ordered_value; + +#[cfg(feature = "preserve_order")] +pub use self::borrowed::ordered::to_value as to_borrowed_ordered_value; +#[cfg(feature = "preserve_order")] +pub use self::owned::ordered::to_value as to_owned_ordered_value; diff --git a/src/serde/value/borrowed/ordered.rs b/src/serde/value/borrowed/ordered.rs index 06fda9ca..ed1752dc 100644 --- a/src/serde/value/borrowed/ordered.rs +++ b/src/serde/value/borrowed/ordered.rs @@ -3,6 +3,7 @@ mod se; use crate::value::borrowed::ordered::Value; use crate::Result; +use serde_ext::de::Deserialize; use serde_ext::ser::Serialize; /// Tries to convert a struct that implements serde's serialize into @@ -17,3 +18,29 @@ where { value.serialize(se::Serializer::default()) } + +/// Tries to convert a `BorrowedValue` into a struct that implements +/// serde's Deserialize interface +/// +/// # Errors +/// +/// Will return `Err` if `value` can not be deserialized +pub fn from_value<'de, T>(value: Value<'de>) -> Result +where + T: Deserialize<'de>, +{ + T::deserialize(value) +} + +/// Tries to convert a `&BorrowedValue` into a struct that implements +/// serde's Deserialize interface +/// +/// # Errors +/// +/// Will return `Err` if `value` fails to be deserialized +pub fn from_refvalue<'de, T>(value: &'de Value<'de>) -> Result +where + T: Deserialize<'de>, +{ + T::deserialize(value) +} diff --git a/src/serde/value/borrowed/ordered/de.rs b/src/serde/value/borrowed/ordered/de.rs index b83544c5..21ea05c7 100644 --- a/src/serde/value/borrowed/ordered/de.rs +++ b/src/serde/value/borrowed/ordered/de.rs @@ -832,7 +832,7 @@ mod test { let mut raw_json = r#"{"name":"bob","friends":[]}"#.to_string(); let result: Result = crate::to_borrowed_value(unsafe { raw_json.as_bytes_mut() }) - .and_then(crate::serde::value::borrowed::from_value); + .and_then(crate::serde::value::borrowed::ordered::from_value); assert_eq!( result, Ok(Person { @@ -861,7 +861,7 @@ mod test { r#"{"name":"bob","middle_name": "frank", "friends":[], "pos":[0,1]}"#.to_string(); let result: Result = crate::to_borrowed_value(unsafe { raw_json.as_bytes_mut() }) - .and_then(crate::serde::value::borrowed::from_value); + .and_then(crate::serde::value::borrowed::ordered::from_value); assert_eq!( result, Ok(Person { @@ -909,7 +909,7 @@ mod test { r#"{"name":"bob","middle_name": "frank", "friends":[], "pos": [-1, 2, -3.25, "up"], "age": 123}"#.to_string(); let value = crate::to_borrowed_value(unsafe { raw_json.as_bytes_mut() }).expect("to_owned_value"); - let result: Person = crate::serde::value::borrowed::from_refvalue(&value).expect("from_refvalue"); + let result: Person = crate::serde::value::borrowed::ordered::from_refvalue(&value).expect("from_refvalue"); let expected = Person { name: "bob".to_string(), middle_name: Some("frank".to_string()), @@ -927,7 +927,7 @@ mod test { let mut raw_json = r#"{"key":{"subkey": "value"}, "vec":[[null], [1]]}"#.to_string(); let value = crate::to_borrowed_value(unsafe { raw_json.as_bytes_mut() }).expect("to_owned_value"); - let result: TestStruct = crate::serde::value::borrowed::from_refvalue(&value).expect("from_refvalue"); + let result: TestStruct = crate::serde::value::borrowed::ordered::from_refvalue(&value).expect("from_refvalue"); let expected = TestStruct { key: hashmap!("subkey".to_string() => "value".to_string()), vec: vec![vec![None], vec![Some(1)]], @@ -940,12 +940,12 @@ mod test { fn deserialize_128bit() { let value = i64::MIN as i128 - 1; let int128 = crate::BorrowedValue::Static(crate::StaticNode::I128(value)); - let res: i128 = crate::serde::value::borrowed::from_refvalue(&int128).expect("from_refvalue"); + let res: i128 = crate::serde::value::borrowed::ordered::from_refvalue(&int128).expect("from_refvalue"); assert_eq!(value, res); let value = u64::MAX as u128; let int128 = crate::BorrowedValue::Static(crate::StaticNode::U128(value)); - let res: u128 = crate::serde::value::borrowed::from_refvalue(&int128).expect("from_refvalue"); + let res: u128 = crate::serde::value::borrowed::ordered::from_refvalue(&int128).expect("from_refvalue"); assert_eq!(value, res); } @@ -953,7 +953,7 @@ mod test { fn variant() { struct NameAndConfig<'v> { name: String, - config: Option>, + config: Option>, } impl<'v> serde::Deserialize<'v> for NameAndConfig<'v> { fn deserialize(deserializer: D) -> std::result::Result @@ -972,7 +972,7 @@ mod test { // 956 | enum Variants<'v> { // | -- lifetime `'v` defined here // ... - // 960 | config: Option>, + // 960 | config: Option>, // | ^^^^^^ requires that `'de` must outlive `'v` // | // = help: consider adding the following bound: `'de: 'v` @@ -986,7 +986,7 @@ mod test { // 956 | enum Variants<'v> { // | -- lifetime `'v` defined here // ... - // 960 | config: Option>, + // 960 | config: Option>, // | ^^^^^^ requires that `'v` must outlive `'de` // | // = help: consider adding the following bound: `'v: 'de` @@ -995,7 +995,7 @@ mod test { Name(String), NameAndConfig { name: String, - config: Option>, + config: Option>, }, } diff --git a/src/serde/value/owned/ordered.rs b/src/serde/value/owned/ordered.rs index ed906756..ca8413e3 100644 --- a/src/serde/value/owned/ordered.rs +++ b/src/serde/value/owned/ordered.rs @@ -4,6 +4,7 @@ mod se; use crate::value::owned::ordered::Value; use crate::Result; use serde_ext::ser::Serialize; +use serde_ext::de::DeserializeOwned; /// Tries to convert a struct that implements serde's serialize into /// an ordered `OwnedValue` @@ -17,3 +18,29 @@ where { value.serialize(se::Serializer::default()) } + +/// Tries to convert a `OwnedValue` into a struct that implements +/// serde's Deserialize interface +/// +/// # Errors +/// +/// Will return `Err` if `value` fails to be deserialized +pub fn from_value(value: Value) -> Result +where + T: DeserializeOwned, +{ + T::deserialize(value) +} + +/// Tries to convert a `&OwnedValue` into a struct that implements +/// serde's Deserialize interface +/// +/// # Errors +/// +/// Will return `Err` if `value` fails to be deserialized +pub fn from_refvalue(value: &Value) -> Result +where + T: DeserializeOwned, +{ + T::deserialize(value) +} diff --git a/src/serde/value/owned/ordered/de.rs b/src/serde/value/owned/ordered/de.rs index cc5f5c19..0f0aea56 100644 --- a/src/serde/value/owned/ordered/de.rs +++ b/src/serde/value/owned/ordered/de.rs @@ -807,7 +807,7 @@ mod test { } let mut raw_json = r#"{"name":"bob","friends":[]}"#.to_string(); let result: Result = crate::to_owned_value(unsafe { raw_json.as_bytes_mut() }) - .and_then(crate::serde::value::owned::from_value); + .and_then(crate::serde::value::owned::ordered::from_value); assert_eq!( result, Ok(Person { @@ -834,7 +834,7 @@ mod test { let mut raw_json = r#"{"name":"bob","middle_name": "frank", "friends":[], "pos": [1,2]}"#.to_string(); let result: Result = crate::to_owned_value(unsafe { raw_json.as_bytes_mut() }) - .and_then(crate::serde::value::owned::from_value); + .and_then(crate::serde::value::owned::ordered::from_value); assert_eq!( result, Ok(Person { @@ -883,7 +883,7 @@ mod test { let serde_result: Person = serde_json::from_str(&raw_json).expect("serde_json::from_str"); let value = crate::to_owned_value(unsafe { raw_json.as_bytes_mut() }).expect("to_owned_value"); - let result: Person = crate::serde::value::owned::from_refvalue(&value).expect("from_refvalue"); + let result: Person = crate::serde::value::owned::ordered::from_refvalue(&value).expect("from_refvalue"); let expected = Person { name: "bob".to_string(), middle_name: Some("frank".to_string()), @@ -902,7 +902,7 @@ mod test { let mut raw_json = r#"{"key":{"subkey": "value"}, "vec":[[null], [1]]}"#.to_string(); let value = crate::to_owned_value(unsafe { raw_json.as_bytes_mut() }).expect("to_owned_value"); - let result: TestStruct = crate::serde::value::owned::from_refvalue(&value).expect("from_refvalue"); + let result: TestStruct = crate::serde::value::owned::ordered::from_refvalue(&value).expect("from_refvalue"); let expected = TestStruct { key: hashmap!("subkey".to_string() => "value".to_string()), vec: vec![vec![None], vec![Some(1)]], @@ -915,19 +915,19 @@ mod test { fn deserialize_128bit() { let value = i64::MIN as i128 - 1; let int128 = crate::OwnedValue::Static(crate::StaticNode::I128(value)); - let res: i128 = crate::serde::value::owned::from_refvalue(&int128).expect("from_refvalue"); + let res: i128 = crate::serde::value::owned::ordered::from_refvalue(&int128).expect("from_refvalue"); assert_eq!(value, res); let value = u64::MAX as u128; let int128 = crate::OwnedValue::Static(crate::StaticNode::U128(value)); - let res: u128 = crate::serde::value::owned::from_refvalue(&int128).expect("from_refvalue"); + let res: u128 = crate::serde::value::owned::ordered::from_refvalue(&int128).expect("from_refvalue"); assert_eq!(value, res); } #[test] fn variant() { struct NameAndConfig { name: String, - config: Option, + config: Option, } impl<'v> serde::Deserialize<'v> for NameAndConfig { fn deserialize(deserializer: D) -> std::result::Result @@ -940,7 +940,7 @@ mod test { Name(String), NameAndConfig { name: String, - config: Option, + config: Option, }, } From fd1b09ea42da6a88a0fd0ba46012fc156da0aaab Mon Sep 17 00:00:00 2001 From: Louis Maddox Date: Mon, 13 Oct 2025 23:50:18 +0100 Subject: [PATCH 3/6] fix: use ordered funcs in deser tests; remove RandomState as global hasher --- src/serde/value/borrowed/ordered/de.rs | 8 ++++---- src/serde/value/owned/ordered/de.rs | 8 ++++---- src/value.rs | 5 +---- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/serde/value/borrowed/ordered/de.rs b/src/serde/value/borrowed/ordered/de.rs index 21ea05c7..1aacba2f 100644 --- a/src/serde/value/borrowed/ordered/de.rs +++ b/src/serde/value/borrowed/ordered/de.rs @@ -831,7 +831,7 @@ mod test { } let mut raw_json = r#"{"name":"bob","friends":[]}"#.to_string(); let result: Result = - crate::to_borrowed_value(unsafe { raw_json.as_bytes_mut() }) + crate::to_ordered_borrowed_value(unsafe { raw_json.as_bytes_mut() }) .and_then(crate::serde::value::borrowed::ordered::from_value); assert_eq!( result, @@ -860,7 +860,7 @@ mod test { let mut raw_json = r#"{"name":"bob","middle_name": "frank", "friends":[], "pos":[0,1]}"#.to_string(); let result: Result = - crate::to_borrowed_value(unsafe { raw_json.as_bytes_mut() }) + crate::to_ordered_borrowed_value(unsafe { raw_json.as_bytes_mut() }) .and_then(crate::serde::value::borrowed::ordered::from_value); assert_eq!( result, @@ -908,7 +908,7 @@ mod test { let mut raw_json = r#"{"name":"bob","middle_name": "frank", "friends":[], "pos": [-1, 2, -3.25, "up"], "age": 123}"#.to_string(); let value = - crate::to_borrowed_value(unsafe { raw_json.as_bytes_mut() }).expect("to_owned_value"); + crate::to_ordered_borrowed_value(unsafe { raw_json.as_bytes_mut() }).expect("to_owned_value"); let result: Person = crate::serde::value::borrowed::ordered::from_refvalue(&value).expect("from_refvalue"); let expected = Person { name: "bob".to_string(), @@ -926,7 +926,7 @@ mod test { let mut raw_json = r#"{"key":{"subkey": "value"}, "vec":[[null], [1]]}"#.to_string(); let value = - crate::to_borrowed_value(unsafe { raw_json.as_bytes_mut() }).expect("to_owned_value"); + crate::to_ordered_borrowed_value(unsafe { raw_json.as_bytes_mut() }).expect("to_owned_value"); let result: TestStruct = crate::serde::value::borrowed::ordered::from_refvalue(&value).expect("from_refvalue"); let expected = TestStruct { key: hashmap!("subkey".to_string() => "value".to_string()), diff --git a/src/serde/value/owned/ordered/de.rs b/src/serde/value/owned/ordered/de.rs index 0f0aea56..337365a5 100644 --- a/src/serde/value/owned/ordered/de.rs +++ b/src/serde/value/owned/ordered/de.rs @@ -806,7 +806,7 @@ mod test { pub friends: Vec, } let mut raw_json = r#"{"name":"bob","friends":[]}"#.to_string(); - let result: Result = crate::to_owned_value(unsafe { raw_json.as_bytes_mut() }) + let result: Result = crate::to_ordered_owned_value(unsafe { raw_json.as_bytes_mut() }) .and_then(crate::serde::value::owned::ordered::from_value); assert_eq!( result, @@ -833,7 +833,7 @@ mod test { } let mut raw_json = r#"{"name":"bob","middle_name": "frank", "friends":[], "pos": [1,2]}"#.to_string(); - let result: Result = crate::to_owned_value(unsafe { raw_json.as_bytes_mut() }) + let result: Result = crate::to_ordered_owned_value(unsafe { raw_json.as_bytes_mut() }) .and_then(crate::serde::value::owned::ordered::from_value); assert_eq!( result, @@ -882,7 +882,7 @@ mod test { r#"{"name":"bob","middle_name": "frank", "friends":[], "pos": [-1, 2, -3.25, "up"], "age": 123}"#.to_string(); let serde_result: Person = serde_json::from_str(&raw_json).expect("serde_json::from_str"); let value = - crate::to_owned_value(unsafe { raw_json.as_bytes_mut() }).expect("to_owned_value"); + crate::to_ordered_owned_value(unsafe { raw_json.as_bytes_mut() }).expect("to_owned_value"); let result: Person = crate::serde::value::owned::ordered::from_refvalue(&value).expect("from_refvalue"); let expected = Person { name: "bob".to_string(), @@ -901,7 +901,7 @@ mod test { let mut raw_json = r#"{"key":{"subkey": "value"}, "vec":[[null], [1]]}"#.to_string(); let value = - crate::to_owned_value(unsafe { raw_json.as_bytes_mut() }).expect("to_owned_value"); + crate::to_ordered_owned_value(unsafe { raw_json.as_bytes_mut() }).expect("to_owned_value"); let result: TestStruct = crate::serde::value::owned::ordered::from_refvalue(&value).expect("from_refvalue"); let expected = TestStruct { key: hashmap!("subkey".to_string() => "value".to_string()), diff --git a/src/value.rs b/src/value.rs index 43bcb579..367c3d4a 100644 --- a/src/value.rs +++ b/src/value.rs @@ -91,11 +91,8 @@ pub use value_trait::*; #[cfg(feature = "known-key")] pub type ObjectHasher = crate::known_key::NotSoRandomState; /// Hasher used for objects -#[cfg(all(not(feature = "known-key"), not(feature = "preserve_order")))] +#[cfg(not(feature = "known-key"))] pub type ObjectHasher = halfbrown::DefaultHashBuilder; -/// Hasher used for objects -#[cfg(all(not(feature = "known-key"), feature = "preserve_order"))] -pub type ObjectHasher = std::hash::RandomState; /// Hashmap used for objects #[cfg(not(feature = "preserve_order"))] From 3b2f3232d13492e847bb145963374d72ff0ba5e7 Mon Sep 17 00:00:00 2001 From: Louis Maddox Date: Tue, 14 Oct 2025 13:13:05 +0100 Subject: [PATCH 4/6] chore: remove 32 key orderliness test --- src/value/borrowed.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/value/borrowed.rs b/src/value/borrowed.rs index 465f296a..d3215cb9 100644 --- a/src/value/borrowed.rs +++ b/src/value/borrowed.rs @@ -1119,23 +1119,6 @@ mod test { assert_eq!(v, 42); } - #[test] - fn preserve_order_32_keys_baseline() { - // At exactly 32 keys, halfbrown still uses Vec - order preserved naturally - let keys: Vec = (0..32).map(|i| format!("key_{}", i)).collect(); - let json_pairs: Vec = keys.iter().map(|k| format!(r#""{}": {}"#, k, 1)).collect(); - let json = format!("{{{}}}", json_pairs.join(", ")); - let mut input = json.into_bytes(); - - let v = to_value(input.as_mut_slice()).expect("valid JSON"); - let obj = v.as_object().expect("is object"); - let result_keys: Vec<&str> = obj.keys().map(|k| k.as_ref()).collect(); - let expected_keys: Vec<&str> = keys.iter().map(|s| s.as_str()).collect(); - - // This should pass even without preserve_order - assert_eq!(result_keys, expected_keys); - } - // #[test] // fn size() { // assert_eq!(std::mem::size_of::(), 24); From 7a1d78d6a56f4a2f257b1ba440d2bb5fcef3f5b7 Mon Sep 17 00:00:00 2001 From: Louis Maddox Date: Tue, 14 Oct 2025 13:16:17 +0100 Subject: [PATCH 5/6] chore: remove 32 key orderliness test (owned) --- src/value/owned.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/value/owned.rs b/src/value/owned.rs index 8796a714..ea05f499 100644 --- a/src/value/owned.rs +++ b/src/value/owned.rs @@ -950,19 +950,4 @@ mod test { let v: Value = v.into(); assert_eq!(v, 42); } - - #[test] - fn preserve_order_32_keys_baseline() { - let keys: Vec = (0..32).map(|i| format!("key_{}", i)).collect(); - let json_pairs: Vec = keys.iter().map(|k| format!(r#""{}": {}"#, k, 1)).collect(); - let json = format!("{{{}}}", json_pairs.join(", ")); - let mut input = json.into_bytes(); - - let v = to_value(input.as_mut_slice()).expect("valid JSON"); - let obj = v.as_object().expect("is object"); - let result_keys: Vec<&str> = obj.keys().map(|s| s.as_str()).collect(); - let expected_keys: Vec<&str> = keys.iter().map(|s| s.as_str()).collect(); - - assert_eq!(result_keys, expected_keys); - } } From 6c0e703817e8a1ed8ba1be7d2b8816eb2659bc52 Mon Sep 17 00:00:00 2001 From: Louis Maddox Date: Thu, 16 Oct 2025 17:40:55 +0100 Subject: [PATCH 6/6] chore: comment on things to revert later --- src/tests.rs | 2 ++ src/tests/serde.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/tests.rs b/src/tests.rs index 5fa61a48..95bcbf12 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -253,9 +253,11 @@ proptest! { { // we can't do 128 bit w/ serde use crate::{deserialize, BorrowedValue, OwnedValue}; let mut e = encoded.clone(); + // TODO: can this turbofish be avoided? let res: OwnedValue = deserialize::(&mut e).expect("can't convert"); assert_eq!(val, res); let mut e = encoded; + // TODO: can this turbofish be avoided? let res: BorrowedValue = deserialize::>(&mut e).expect("can't convert"); assert_eq!(val, res); } diff --git a/src/tests/serde.rs b/src/tests/serde.rs index ee22ff83..ae9a1f1f 100644 --- a/src/tests/serde.rs +++ b/src/tests/serde.rs @@ -1008,6 +1008,8 @@ proptest! { let v_simd_owned = to_owned_value(d2).expect("to_owned_value failed"); let v_simd_borrowed = to_borrowed_value(d3).expect("to_borrowed_value failed"); assert_eq!(v_simd_borrowed, v_simd_owned); + // TODO: revert this to `deserialize(d4)...` see thread at: + // https://github.com/simd-lite/simd-json/pull/436/files#r2428840193 let v_deserialize: OwnedValue = deserialize::(d4).expect("deserialize failed"); assert_eq!(v_deserialize, v_simd_owned); }