Skip to content

Commit df33d8f

Browse files
author
dj8yf0μl
committed
chore: add de impl for serde_json::Value
1 parent 92b2e37 commit df33d8f

File tree

1 file changed

+189
-61
lines changed

1 file changed

+189
-61
lines changed

borsh/examples/serde_json_value.rs

+189-61
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use std::collections::HashMap;
22

3-
use borsh::BorshSerialize;
3+
use borsh::{BorshDeserialize, BorshSerialize};
44

55
mod serde_json_value {
6+
pub use de::deserialize_value;
67
pub use ser::serialize_value;
78
mod ser {
89
use borsh::{
@@ -11,7 +12,7 @@ mod serde_json_value {
1112
};
1213
use core::convert::TryFrom;
1314

14-
/// this is mutually recursive with serialize_array and serialize_map
15+
/// this is mutually recursive with `serialize_array` and `serialize_map`
1516
pub fn serialize_value<W: Write>(value: &serde_json::Value, writer: &mut W) -> Result<()> {
1617
match value {
1718
serde_json::Value::Null => 0_u8.serialize(writer),
@@ -38,11 +39,37 @@ mod serde_json_value {
3839
}
3940
}
4041

41-
/// this is mutually recursive with serialize_value
42-
fn serialize_array<W: Write>(
43-
array: &Vec<serde_json::Value>,
44-
writer: &mut W,
45-
) -> Result<()> {
42+
fn serialize_number<W: Write>(number: &serde_json::Number, writer: &mut W) -> Result<()> {
43+
// A JSON number can either be a non-negative integer (represented in
44+
// serde_json by a u64), a negative integer (by an i64), or a non-integer
45+
// (by an f64).
46+
// We identify these cases with the following single-byte discriminants:
47+
// 0 - u64
48+
// 1 - i64
49+
// 2 - f64
50+
if let Some(u) = number.as_u64() {
51+
0_u8.serialize(writer)?;
52+
return u.serialize(writer);
53+
}
54+
55+
if let Some(i) = number.as_i64() {
56+
1_u8.serialize(writer)?;
57+
return i.serialize(writer);
58+
}
59+
60+
if let Some(f) = number.as_f64() {
61+
2_u8.serialize(writer)?;
62+
return f.serialize(writer);
63+
}
64+
65+
// technically, it should not be unreachable, but an error instead,
66+
// as assumption about unreachable depends on private implementation detail
67+
// but it's fine to leave it be unreachable! for an example
68+
unreachable!("number is neither a u64, i64, nor f64");
69+
}
70+
71+
/// this is mutually recursive with `serialize_value`
72+
fn serialize_array<W: Write>(array: &Vec<serde_json::Value>, writer: &mut W) -> Result<()> {
4673
writer.write_all(
4774
&(u32::try_from(array.len()).map_err(|_| ErrorKind::InvalidData)?).to_le_bytes(),
4875
)?;
@@ -52,7 +79,7 @@ mod serde_json_value {
5279
Ok(())
5380
}
5481

55-
/// this is mutually recursive with serialize_value
82+
/// this is mutually recursive with `serialize_value`
5683
fn serialize_map<W: Write>(
5784
map: &serde_json::Map<String, serde_json::Value>,
5885
writer: &mut W,
@@ -69,73 +96,154 @@ mod serde_json_value {
6996

7097
Ok(())
7198
}
99+
}
100+
mod de {
101+
use borsh::{
102+
io::{Error, ErrorKind, Read, Result},
103+
BorshDeserialize,
104+
};
72105

73-
fn serialize_number<W: Write>(number: &serde_json::Number, writer: &mut W) -> Result<()> {
74-
// A JSON number can either be a non-negative integer (represented in
75-
// serde_json by a u64), a negative integer (by an i64), or a non-integer
76-
// (by an f64).
77-
// We identify these cases with the following single-byte discriminants:
78-
// 0 - u64
79-
// 1 - i64
80-
// 2 - f64
81-
if let Some(u) = number.as_u64() {
82-
0_u8.serialize(writer)?;
83-
return u.serialize(writer);
106+
fn hint_cautious<T>(hint: u32) -> usize {
107+
let el_size = core::mem::size_of::<T>() as u32;
108+
core::cmp::max(core::cmp::min(hint, 4096 / el_size), 1) as usize
109+
}
110+
111+
/// this is mutually recursive with `deserialize_array`, `deserialize_map`
112+
pub fn deserialize_value<R: Read>(reader: &mut R) -> Result<serde_json::Value> {
113+
let flag: u8 = BorshDeserialize::deserialize_reader(reader)?;
114+
match flag {
115+
0 => Ok(serde_json::Value::Null),
116+
1 => {
117+
let b: bool = BorshDeserialize::deserialize_reader(reader)?;
118+
Ok(serde_json::Value::Bool(b))
119+
}
120+
2 => {
121+
let n: serde_json::Number = deserialize_number(reader)?;
122+
Ok(serde_json::Value::Number(n))
123+
}
124+
3 => {
125+
let s: String = BorshDeserialize::deserialize_reader(reader)?;
126+
Ok(serde_json::Value::String(s))
127+
}
128+
4 => {
129+
let a: Vec<serde_json::Value> = deserialize_array(reader)?;
130+
Ok(serde_json::Value::Array(a))
131+
}
132+
5 => {
133+
let o: serde_json::Map<_, _> = deserialize_map(reader)?;
134+
Ok(serde_json::Value::Object(o))
135+
}
136+
_ => {
137+
let msg = format!(
138+
"Invalid JSON value representation: {}. The first byte must be 0-5",
139+
flag
140+
);
141+
142+
Err(Error::new(ErrorKind::InvalidData, msg))
143+
}
84144
}
145+
}
85146

86-
if let Some(i) = number.as_i64() {
87-
1_u8.serialize(writer)?;
88-
return i.serialize(writer);
147+
fn deserialize_number<R: Read>(reader: &mut R) -> Result<serde_json::Number> {
148+
let flag: u8 = BorshDeserialize::deserialize_reader(reader)?;
149+
match flag {
150+
0 => {
151+
let u: u64 = BorshDeserialize::deserialize_reader(reader)?;
152+
Ok(u.into())
153+
}
154+
1 => {
155+
let i: i64 = BorshDeserialize::deserialize_reader(reader)?;
156+
Ok(i.into())
157+
}
158+
2 => {
159+
let f: f64 = BorshDeserialize::deserialize_reader(reader)?;
160+
// This returns None if the number is a NaN or +/-Infinity,
161+
// which are not valid JSON numbers.
162+
serde_json::Number::from_f64(f).ok_or_else(|| {
163+
let msg = format!("Invalid JSON number: {}", f);
164+
165+
Error::new(ErrorKind::InvalidData, msg)
166+
})
167+
}
168+
_ => {
169+
let msg = format!(
170+
"Invalid JSON number representation: {}. The first byte must be 0-2",
171+
flag
172+
);
173+
174+
Err(Error::new(ErrorKind::InvalidData, msg))
175+
}
89176
}
177+
}
90178

91-
if let Some(f) = number.as_f64() {
92-
2_u8.serialize(writer)?;
93-
return f.serialize(writer);
179+
/// this is mutually recursive with `deserialize_value`
180+
fn deserialize_array<R: Read>(reader: &mut R) -> Result<Vec<serde_json::Value>> {
181+
let len = u32::deserialize_reader(reader)?;
182+
let mut result = Vec::with_capacity(hint_cautious::<(String, serde_json::Value)>(len));
183+
for _ in 0..len {
184+
let value = deserialize_value(reader)?;
185+
result.push(value);
94186
}
187+
Ok(result)
188+
}
95189

96-
unreachable!("number is neither a u64, i64, nor f64");
190+
/// this is mutually recursive with `deserialize_value`
191+
fn deserialize_map<R: Read>(
192+
reader: &mut R,
193+
) -> Result<serde_json::Map<String, serde_json::Value>> {
194+
// The implementation here is identical to that of BTreeMap<String, serde_json::Value>.
195+
196+
let vec: Vec<(String, serde_json::Value)> = {
197+
let len = u32::deserialize_reader(reader)?;
198+
let mut result =
199+
Vec::with_capacity(hint_cautious::<(String, serde_json::Value)>(len));
200+
for _ in 0..len {
201+
let pair = {
202+
let key = String::deserialize_reader(reader)?;
203+
let value = deserialize_value(reader)?;
204+
(key, value)
205+
};
206+
result.push(pair);
207+
}
208+
result
209+
};
210+
211+
Ok(vec.into_iter().collect())
97212
}
98213
}
99214
}
100215

101-
mod map_of_serde_json_value {
102-
pub use ser::serialize_map;
103-
104-
mod ser {
216+
mod borsh_wrapper {
217+
use borsh::{BorshDeserialize, BorshSerialize};
105218

106-
use borsh::{
107-
io::{ErrorKind, Result, Write},
108-
BorshSerialize,
109-
};
110-
use core::convert::TryFrom;
111-
use std::collections::HashMap;
219+
#[derive(Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
220+
pub struct SerdeJsonBorshWrapper(
221+
#[borsh(
222+
serialize_with = "super::serde_json_value::serialize_value",
223+
deserialize_with = "super::serde_json_value::deserialize_value"
224+
)]
225+
pub serde_json::Value,
226+
);
112227

113-
pub fn serialize_map<W: Write>(value: &HashMap<String, serde_json::Value>, writer: &mut W) -> Result<()> {
114-
let mut vec = value.iter().collect::<Vec<_>>();
115-
vec.sort_by(|(a, _), (b, _)| a.cmp(b));
116-
u32::try_from(vec.len())
117-
.map_err(|_| ErrorKind::InvalidData)?
118-
.serialize(writer)?;
119-
for kv in vec {
120-
kv.0.serialize(writer)?;
121-
crate::serde_json_value::serialize_value(kv.1, writer)?;
122-
}
123-
Ok(())
228+
impl From<serde_json::Value> for SerdeJsonBorshWrapper {
229+
fn from(value: serde_json::Value) -> Self {
230+
Self(value)
124231
}
125-
126232
}
127-
128-
}
129233

130-
#[derive(BorshSerialize)]
131-
struct SerdeJsonAsField {
132-
#[borsh(
133-
serialize_with = "map_of_serde_json_value::serialize_map",
134-
)]
135-
examples: HashMap<String, serde_json::Value>,
234+
impl From<SerdeJsonBorshWrapper> for serde_json::Value {
235+
fn from(value: SerdeJsonBorshWrapper) -> Self {
236+
value.0
237+
}
238+
}
136239
}
137240

241+
use borsh_wrapper::SerdeJsonBorshWrapper;
138242

243+
#[derive(Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
244+
struct SerdeJsonAsField {
245+
pub examples: HashMap<String, SerdeJsonBorshWrapper>,
246+
}
139247

140248
fn main() {
141249
let original = serde_json::json!({
@@ -189,12 +297,32 @@ fn main() {
189297
});
190298

191299
let mut examples = HashMap::new();
192-
examples.insert("Larry Jake Pumpkin".into(), original);
300+
examples.insert("Larry Jake Pumpkin".into(), original.clone().into());
193301

194-
let complex_struct = SerdeJsonAsField {
195-
examples,
196-
};
302+
let complex_struct = SerdeJsonAsField { examples };
197303
let serialized = borsh::to_vec(&complex_struct).unwrap();
198304

199-
println!("{:#?}", serialized);
305+
let mut deserialized: SerdeJsonAsField = borsh::from_slice(&serialized).unwrap();
306+
307+
assert_eq!(complex_struct, deserialized);
308+
309+
let deserialized_value: serde_json::Value = deserialized
310+
.examples
311+
.remove("Larry Jake Pumpkin")
312+
.expect("key present")
313+
.into();
314+
315+
assert_eq!(original, deserialized_value);
316+
317+
let number = deserialized_value
318+
.get("array_of_numbers")
319+
.expect("has key")
320+
.as_array()
321+
.expect("is array")
322+
.get(5)
323+
.expect("has index")
324+
.as_i64()
325+
.expect("is i64");
326+
327+
assert_eq!(number, 34798324);
200328
}

0 commit comments

Comments
 (0)