Serialize JValue objects with AsVec

It makes it more efficient and avoid buggy rkyv BTree serialization/validation.
This commit is contained in:
Ivan Boldyrev 2024-02-08 17:47:37 +01:00
parent 1cf0b70b06
commit 09de5f8dd2
4 changed files with 38 additions and 14 deletions

View File

@ -19,8 +19,8 @@
* licensed under conditions of MIT License and Apache License, Version 2.0.
*/
use crate::value::JValue;
use crate::{JsonString, Map, Number};
use crate::value::Object;
use crate::{JValue, JsonString, Map, Number};
use core::fmt;
use serde::de::{self, Deserialize, DeserializeSeed, MapAccess, SeqAccess, Visitor};
use std::vec::Vec;
@ -112,9 +112,9 @@ impl<'de> Deserialize<'de> for JValue {
values.insert(key, value);
}
Ok(JValue::Object(values.into()))
Ok(JValue::Object(Object(values).into()))
}
None => Ok(JValue::Object(Map::new().into())),
None => Ok(JValue::Object(Object(Map::default()).into())),
}
}
}

View File

@ -19,7 +19,7 @@
* licensed under conditions of MIT License and Apache License, Version 2.0.
*/
use super::JValue;
use super::{JValue, Object};
use crate::{JsonString, Map};
use std::borrow::Cow;
use std::collections::HashMap;
@ -181,7 +181,7 @@ impl From<Map<JsonString, JValue>> for JValue {
/// let x: JValue = m.into();
/// ```
fn from(f: Map<JsonString, JValue>) -> Self {
JValue::Object(f.into())
JValue::Object(Object(f).into())
}
}
@ -277,11 +277,11 @@ impl<K: Into<JsonString>, V: Into<JValue>> FromIterator<(K, V)> for JValue {
/// let x: JValue = v.into_iter().collect();
/// ```
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
JValue::Object(Rc::new(
JValue::Object(Rc::new(Object(
iter.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect(),
))
)))
}
}
@ -326,7 +326,7 @@ impl From<&serde_json::Value> for JValue {
Value::Array(a) => JValue::Array(a.iter().map(Into::into).collect()),
Value::Object(o) => {
let oo = Map::from_iter(o.into_iter().map(|(k, v)| (k.as_str().into(), v.into())));
JValue::Object(oo.into())
JValue::Object(Object(oo).into())
}
}
}

View File

@ -32,6 +32,7 @@ use core::fmt::{self, Debug, Display};
use core::mem;
use core::str;
use std::io;
use std::ops::Deref;
use std::rc::Rc;
pub use self::index::Index;
@ -78,10 +79,25 @@ pub enum JValue {
Object(
#[omit_bounds]
#[archive_attr(omit_bounds)]
Rc<Map<JsonString, JValue>>,
Rc<Object>,
),
}
#[derive(Clone, Debug, Eq, PartialEq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
#[archive(check_bytes)]
#[archive_attr(check_bytes(
bound = "__C: rkyv::validation::ArchiveContext + rkyv::validation::SharedContext, <__C as rkyv::Fallible>::Error: std::error::Error"
))]
#[archive(bound(
serialize = "__S: rkyv::ser::ScratchSpace + rkyv::ser::Serializer + rkyv::ser::SharedSerializeRegistry",
deserialize = "__D: rkyv::de::SharedDeserializeRegistry"
))]
/// A wrapper type for better rkyv support.
///
/// Please note that this type doens't need to implement serde types as JValue serde implementations
/// works with its contents directly.
pub struct Object(#[with(rkyv::with::AsVec)] Map<JsonString, JValue>);
impl Debug for JValue {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self {
@ -101,6 +117,14 @@ impl Debug for JValue {
}
}
impl Deref for Object {
type Target = Map<JsonString, JValue>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Display for JValue {
/// Display a JSON value as a string.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -163,18 +187,18 @@ impl JValue {
}
pub fn object(map: impl Into<Map<JsonString, JValue>>) -> Self {
Self::Object(Rc::new(map.into()))
Self::Object(Rc::new(Object(map.into())))
}
pub fn object_from_pairs(
into_iter: impl IntoIterator<Item = (impl Into<JsonString>, impl Into<JValue>)>,
) -> Self {
Self::Object(Rc::new(
Self::Object(Rc::new(Object(
into_iter
.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect(),
))
)))
}
/// Index into a JSON array or map. A string index can be used to access a

View File

@ -38,7 +38,7 @@ impl Serialize for JValue {
JValue::Object(m) => {
use serde::ser::SerializeMap;
let mut map = tri!(serializer.serialize_map(Some(m.len())));
for (k, v) in &**m {
for (k, v) in &***m {
tri!(map.serialize_entry(k, v));
}
map.end()