From c5b31f07434c9c0950415be4a34b04b72d6ecf2e Mon Sep 17 00:00:00 2001 From: liuq19 Date: Wed, 6 Dec 2023 13:50:31 +0800 Subject: [PATCH] feat: refactor document and value --- Cargo.lock | 82 +- Cargo.toml | 7 + benches/deserialize_value.rs | 50 +- benches/serialize_value.rs | 6 +- examples/document.rs | 29 +- examples/get_from.rs | 3 +- examples/get_many.rs | 1 - examples/iterator.rs | 4 +- fuzz/Cargo.lock | 124 +- fuzz/fuzz_targets/from_slice.rs | 25 +- scripts/test.sh | 33 + src/error.rs | 22 +- src/input.rs | 5 + src/lazyvalue/get.rs | 2 +- src/lazyvalue/iterator.rs | 2 +- src/lazyvalue/value.rs | 13 +- src/lib.rs | 9 +- src/parser.rs | 274 +++- src/pointer/point.rs | 6 +- src/pointer/tree.rs | 13 +- src/reader.rs | 30 +- src/serde/de.rs | 198 ++- src/serde/mod.rs | 19 +- src/serde/number.rs | 69 +- src/util/arc.rs | 154 ++ src/util/mod.rs | 16 +- src/util/offset.rs | 9 + src/util/private.rs | 4 +- src/util/reborrow.rs | 74 + src/util/string.rs | 24 +- src/util/taggedptr.rs | 80 + src/value/alloctor.rs | 69 + src/value/array.rs | 925 ++++++++++++ src/value/de.rs | 734 +++++++++ src/value/from.rs | 742 ++++++++++ src/value/index.rs | 233 ++- src/value/macros.rs | 532 +++++++ src/value/mod.rs | 37 +- src/value/node.rs | 2458 +++++++++++++++++-------------- src/value/object.rs | 981 ++++++++++++ src/value/partial_eq.rs | 333 +++++ src/value/ser.rs | 813 ++++++++++ src/value/shared.rs | 72 + src/value/tryfrom.rs | 53 + src/value/value_trait.rs | 182 ++- src/writer.rs | 4 +- 46 files changed, 8160 insertions(+), 1395 deletions(-) create mode 100755 scripts/test.sh create mode 100644 src/util/arc.rs create mode 100644 src/util/offset.rs create mode 100644 src/util/reborrow.rs create mode 100644 src/util/taggedptr.rs create mode 100644 src/value/alloctor.rs create mode 100644 src/value/array.rs create mode 100644 src/value/de.rs create mode 100644 src/value/from.rs create mode 100644 src/value/macros.rs create mode 100644 src/value/object.rs create mode 100644 src/value/partial_eq.rs create mode 100644 src/value/ser.rs create mode 100644 src/value/shared.rs create mode 100644 src/value/tryfrom.rs diff --git a/Cargo.lock b/Cargo.lock index f207d6b..75da311 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,13 +4,14 @@ version = 3 [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if", "once_cell", "version_check", + "zerocopy", ] [[package]] @@ -61,6 +62,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.4.0" @@ -513,9 +520,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.148" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libm" @@ -529,6 +536,16 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.20" @@ -592,6 +609,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + [[package]] name = "paste" version = "1.0.14" @@ -664,6 +704,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "ref-cast" version = "1.0.20" @@ -719,7 +768,7 @@ version = "0.38.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" dependencies = [ - "bitflags", + "bitflags 2.4.0", "errno", "libc", "linux-raw-sys", @@ -831,7 +880,9 @@ dependencies = [ "itoa", "jemallocator", "json-benchmark", + "libc", "packed_simd", + "parking_lot", "paste", "ryu", "serde", @@ -841,6 +892,7 @@ dependencies = [ "simd-json", "simdutf8", "smallvec", + "static_assertions", "thiserror", ] @@ -1106,3 +1158,23 @@ name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "zerocopy" +version = "0.7.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index f4eb7da..56678e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,9 @@ bumpalo = "3.13" bytes = "1.4" thiserror = "1.0" simdutf8 = "0.1" +parking_lot = "0.12" +static_assertions = "1.1" +libc = "0.2.150" [dev-dependencies] jemallocator = "0.5" @@ -55,6 +58,10 @@ panic = 'unwind' incremental = false overflow-checks = false +[build] +sanitizers = true +debug = true + [[bench]] name = "deserialize_struct" harness = false diff --git a/benches/deserialize_value.rs b/benches/deserialize_value.rs index 50ac33b..239921c 100644 --- a/benches/deserialize_value.rs +++ b/benches/deserialize_value.rs @@ -27,12 +27,24 @@ fn serde_from_str(data: &[u8]) { let _: serde_json::Value = serde_json::from_str(data).unwrap(); } -fn sonic_rs_dom_from_slice(data: &[u8]) { - let _ = sonic_rs::value::dom_from_slice(data).unwrap(); +fn sonic_rs_from_slice(data: &[u8]) { + let _: sonic_rs::Value = sonic_rs::from_slice(data).unwrap(); } -fn sonic_rs_dom_from_slice_unchecked(data: &[u8]) { - let _ = unsafe { sonic_rs::value::dom_from_slice_unchecked(data).unwrap() }; +fn sonic_rs_from_slice_unchecked(data: &[u8]) { + let _: sonic_rs::Value = unsafe { sonic_rs::from_slice_unchecked(data).unwrap() }; +} + +fn sonic_rs_skip_one(data: &[u8]) { + unsafe { + let data = from_utf8_unchecked(data); + let empty: &[&str] = &[]; + let _ = sonic_rs::get_unchecked(data, empty).unwrap(); + } +} + +fn sonic_rs_to_serdejson_value(data: &[u8]) { + let _: serde_json::Value = sonic_rs::from_slice(data).unwrap(); } macro_rules! bench_file { @@ -52,7 +64,7 @@ macro_rules! bench_file { // verify sonic-rs parse let serde_out: serde_json::Value = serde_json::from_slice(&vec).unwrap(); - let value = sonic_rs::value::dom_from_slice(&vec).unwrap(); + let value: sonic_rs::Value = sonic_rs::from_slice(&vec).unwrap(); let out = sonic_rs::to_string(&value).unwrap(); let rs_out1: serde_json::Value = serde_json::from_str(&out).unwrap(); assert_eq!(rs_out1, serde_out); @@ -63,7 +75,7 @@ macro_rules! bench_file { group.bench_with_input("sonic_rs_dom::from_slice", &vec, |b, data| { b.iter_batched( || data, - |bytes| sonic_rs_dom_from_slice(&bytes), + |bytes| sonic_rs_from_slice(&bytes), BatchSize::SmallInput, ) }); @@ -71,15 +83,23 @@ macro_rules! bench_file { group.bench_with_input("sonic_rs_dom::from_slice_unchecked", &vec, |b, data| { b.iter_batched( || data, - |bytes| sonic_rs_dom_from_slice_unchecked(&bytes), + |bytes| sonic_rs_from_slice_unchecked(&bytes), BatchSize::SmallInput, ) }); - group.bench_with_input("simd_json::slice_to_borrowed_value", &vec, |b, data| { + group.bench_with_input("sonic_rs::skip_one", &vec, |b, data| { b.iter_batched( - || data.clone(), - |mut bytes| simdjson_to_borrowed_value(&mut bytes), + || data, + |bytes| sonic_rs_skip_one(&bytes), + BatchSize::SmallInput, + ) + }); + + group.bench_with_input("sonic_rs::to_serdejson_value", &vec, |b, data| { + b.iter_batched( + || data, + |bytes| sonic_rs_to_serdejson_value(&bytes), BatchSize::SmallInput, ) }); @@ -107,6 +127,14 @@ macro_rules! bench_file { BatchSize::SmallInput, ) }); + + group.bench_with_input("simd_json::slice_to_borrowed_value", &vec, |b, data| { + b.iter_batched( + || data.clone(), + |mut bytes| simdjson_to_borrowed_value(&mut bytes), + BatchSize::SmallInput, + ) + }); group.throughput(Throughput::Bytes(vec.len() as u64)); } }; @@ -119,5 +147,5 @@ bench_file!(twitter); bench_file!(github_events); // criterion_group!(benches, canada, otfcc, citm_catalog, twitter, lottie, github_events, twitterescaped, book, poet, fgo); -criterion_group!(benches, twitter, citm_catalog, canada); +criterion_group!(benches, twitter, canada, citm_catalog); criterion_main!(benches); diff --git a/benches/serialize_value.rs b/benches/serialize_value.rs index d5ff15b..d0a530b 100644 --- a/benches/serialize_value.rs +++ b/benches/serialize_value.rs @@ -17,7 +17,7 @@ fn serde_to_string(val: &serde_json::Value) { let _ = serde_json::to_string(val).unwrap(); } -fn sonic_rs_to_string(val: &sonic_rs::value::Document) { +fn sonic_rs_to_string(val: &sonic_rs::Value) { let _ = sonic_rs::to_string(val).unwrap(); } @@ -60,7 +60,7 @@ macro_rules! bench_file { let serde_out: serde_json::Value = serde_json::from_slice(&data).unwrap(); let expect = serde_json::to_string(&serde_out).unwrap(); - let value = sonic_rs::value::dom_from_slice(&data).unwrap(); + let value: sonic_rs::Value = sonic_rs::from_slice(&data).unwrap(); let got = sonic_rs::to_string(&value).unwrap(); assert!( diff_json(&got, &expect), @@ -71,7 +71,7 @@ macro_rules! bench_file { let mut group = c.benchmark_group(stringify!($name)); group.sampling_mode(SamplingMode::Flat); - let value = sonic_rs::value::dom_from_slice(&data).unwrap(); + let value: sonic_rs::Value = sonic_rs::from_slice(&data).unwrap(); group.bench_with_input("sonic_rs::to_string", &value, |b, data| { b.iter_batched( || data, diff --git a/examples/document.rs b/examples/document.rs index bf72169..cf1b4e0 100644 --- a/examples/document.rs +++ b/examples/document.rs @@ -1,8 +1,10 @@ // Parse json into sonic_rs document. -use sonic_rs::value::{dom_from_slice, Value}; -use sonic_rs::PointerNode; -use sonic_rs::{pointer, JsonValue}; +use serde_json::json; +use sonic_rs::from_str; +use sonic_rs::JsonValueMutTrait; +use sonic_rs::{pointer, JsonValueTrait, Value}; + fn main() { let json = r#"{ "name": "Xiaoming", @@ -17,9 +19,7 @@ fn main() { ] }"#; - let mut dom = dom_from_slice(json.as_bytes()).unwrap(); - // get the value from dom - let root = dom.as_value(); + let mut root: Value = from_str(json).unwrap(); // get key from value let age = root.get("age").as_i64(); @@ -34,8 +34,17 @@ fn main() { assert_eq!(phones.as_str().unwrap(), "+123456"); // convert to mutable object - let mut obj = dom.as_object_mut().unwrap(); - let value = Value::new_bool(true); - obj.insert("inserted", value); - assert!(obj.contains_key("inserted")); + let obj = root.as_object_mut().unwrap(); + obj.insert(&"inserted", true); + assert!(obj.contains_key(&"inserted")); + + let mut object = json!({ "A": 65, "B": 66, "C": 67 }); + *object.get_mut("A").unwrap() = json!({ + "code": 123, + "success": false, + "payload": {} + }); + + let mut array = json!(["A", "B", "C"]); + *array.get_mut(2).unwrap() = json!("D"); } diff --git a/examples/get_from.rs b/examples/get_from.rs index c9bdd75..cee7d58 100644 --- a/examples/get_from.rs +++ b/examples/get_from.rs @@ -1,4 +1,5 @@ -use sonic_rs::{get, get_unchecked, pointer, JsonValue, PointerNode}; +use sonic_rs::JsonValueTrait; +use sonic_rs::{get, get_unchecked, pointer}; fn main() { let path = pointer!["a", "b", "c", 1]; diff --git a/examples/get_many.rs b/examples/get_many.rs index 102d6ac..9346e2f 100644 --- a/examples/get_many.rs +++ b/examples/get_many.rs @@ -1,5 +1,4 @@ use sonic_rs::pointer; -use sonic_rs::PointerNode; fn main() { let json = r#" diff --git a/examples/iterator.rs b/examples/iterator.rs index 343cb6d..a71124d 100644 --- a/examples/iterator.rs +++ b/examples/iterator.rs @@ -1,7 +1,7 @@ use bytes::Bytes; use faststr::FastStr; -use sonic_rs::{to_array_iter, to_object_iter_unchecked, JsonValue}; - +use sonic_rs::JsonValueTrait; +use sonic_rs::{to_array_iter, to_object_iter_unchecked}; fn main() { let json = Bytes::from(r#"[1, 2, 3, 4, 5, 6]"#); let iter = to_array_iter(&json); diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 7f337b7..9b78559 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -20,6 +20,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bumpalo" version = "3.13.0" @@ -75,9 +81,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libfuzzer-sys" @@ -96,6 +102,16 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "num-traits" version = "0.2.16" @@ -122,6 +138,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + [[package]] name = "proc-macro2" version = "1.0.69" @@ -140,12 +179,27 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags", +] + [[package]] name = "ryu" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "serde" version = "1.0.181" @@ -185,11 +239,14 @@ dependencies = [ "cfg-if", "faststr", "itoa", + "libc", "packed_simd", + "parking_lot", "ryu", "serde", "simdutf8", "smallvec", + "static_assertions", "thiserror", ] @@ -202,6 +259,12 @@ dependencies = [ "sonic-rs", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "syn" version = "2.0.38" @@ -238,3 +301,60 @@ name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/fuzz/fuzz_targets/from_slice.rs b/fuzz/fuzz_targets/from_slice.rs index f43b30c..5a5711d 100644 --- a/fuzz/fuzz_targets/from_slice.rs +++ b/fuzz/fuzz_targets/from_slice.rs @@ -2,21 +2,26 @@ use libfuzzer_sys::fuzz_target; use serde_json::Value as JValue; -use sonic_rs::dom_from_slice; -use sonic_rs::dom_from_str; +use sonic_rs::from_slice; +use sonic_rs::from_str; +use sonic_rs::value::JsonContainerTrait; use sonic_rs::JsonNumberTrait; -use sonic_rs::JsonValue; +use sonic_rs::JsonValueTrait; +use sonic_rs::Value; use sonic_rs::{to_array_iter, to_array_iter_unchecked, to_object_iter, to_object_iter_unchecked}; fuzz_target!(|data: &[u8]| { match serde_json::from_slice::(data) { Ok(jv) => { - let sv = dom_from_slice(data).unwrap(); - compare_value(&jv, sv.as_value()); + // compare from_slice result + let sv: Value = from_slice(data).unwrap(); + compare_value(&jv, &sv); + + // compare to_string result let sout = sonic_rs::to_string(&sv).unwrap(); let jv2 = serde_json::from_str::(&sout).unwrap(); - let sv2 = dom_from_str(&sout).unwrap(); - let eq = compare_value(&jv2, sv2.as_value()); + let sv2: Value = from_str(&sout).unwrap(); + let eq = compare_value(&jv2, &sv2); if jv.is_object() && eq { for ret in to_object_iter(data) { @@ -63,15 +68,15 @@ fuzz_target!(|data: &[u8]| { } } Err(_) => { - let _ = dom_from_slice(data).unwrap_err(); + let _ = from_slice::(data).unwrap_err(); } } }); fn compare_lazyvalue(jv: &JValue, sv: &sonic_rs::LazyValue) { let out = sv.as_raw_slice(); - let sv2 = sonic_rs::dom_from_slice(out).unwrap(); - compare_value(jv, sv2.as_value()); + let sv2: sonic_rs::Value = sonic_rs::from_slice(out).unwrap(); + compare_value(jv, &sv2); } fn compare_value(jv: &JValue, sv: &sonic_rs::Value) -> bool { diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100755 index 0000000..e95125e --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +set -ex + +export ASAN_OPTIONS="disable_coredump=0:unmap_shadow_on_exit=1:abort_on_error=1" + +testcase_lists() { + cargo test -- -Zunstable-options --list --format json | jq -c 'select(.type=="test") | .name' | awk -F'"' '{print $2}' | awk '{print ($2) ? $3 : $1}' + return $? +} + +sanitize() { + SAN=$1 + TARGET=$2 + TESTCASE=$3 + echo "Running tests with $SAN on $TARGET" + # # use single thread to make error info more readable and accurate + RUSTFLAGS="-Zsanitizer=$SAN" RUSTDOCFLAGS="-Zsanitizer=$SAN" cargo test --target $TARGET $3 -- --test-threads=1 +} + +sanitize_single() { + SAN=$1 + TARGET=$2 + for CASE in $(testcase_lists); do + sanitize $SAN $TARGET $CASE + done +} + +for san in address leak; do + echo "Running tests with $san" + # sanitize $san "x86_64-unknown-linux-gnu" + sanitize_single $san "x86_64-unknown-linux-gnu" +done diff --git a/src/error.rs b/src/error.rs index bc25eed..1870bc9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -89,6 +89,10 @@ impl Error { | ErrorCode::ExpectedArrayCommaOrEnd | ErrorCode::ExpectedArrayStart | ErrorCode::ExpectedObjectStart + | ErrorCode::ValueKeyMustBeString + | ErrorCode::FloatMustBeFinite + | ErrorCode::ExpectedQuote + | ErrorCode::ExpectedNumericKey | ErrorCode::RecursionLimitExceeded => Category::Syntax, } } @@ -252,6 +256,18 @@ pub(crate) enum ErrorCode { #[error("Unexpected visited type in JSON visitor")] UnexpectedVisitType, + + #[error("JSON `Value` key must be string")] + ValueKeyMustBeString, + + #[error("Float must be finite")] + FloatMustBeFinite, + + #[error("Expect a numeric key in Value")] + ExpectedNumericKey, + + #[error("Expect a quote")] + ExpectedQuote, } impl Error { @@ -463,8 +479,6 @@ fn starts_with_digit(slice: &str) -> bool { #[cfg(test)] mod test { - - use crate::Value; use crate::{from_slice, from_str, Deserialize}; #[test] @@ -544,8 +558,8 @@ mod test { } #[test] - fn test_other_erros() { - let err = Value::try_from(f64::NAN).unwrap_err(); + fn test_other_errors() { + let err = crate::Value::try_from(f64::NAN).unwrap_err(); assert_eq!( format!("{}", err), "NaN or Infinity is not a valid JSON value" diff --git a/src/input.rs b/src/input.rs index 025df0b..45278d9 100644 --- a/src/input.rs +++ b/src/input.rs @@ -11,6 +11,11 @@ pub enum JsonSlice<'de> { FastStr(FastStr), } +pub struct RawValue2<'de> { + json: &'de str, + json2: FastStr, +} + impl<'de> JsonSlice<'de> { pub fn slice_ref(&self, subset: &'de [u8]) -> Self { match self { diff --git a/src/lazyvalue/get.rs b/src/lazyvalue/get.rs index 8966aa2..483b534 100644 --- a/src/lazyvalue/get.rs +++ b/src/lazyvalue/get.rs @@ -192,7 +192,7 @@ where #[cfg(test)] mod test { use super::*; - use crate::{pointer, JsonPointer, PointerNode}; + use crate::{pointer, JsonPointer}; use std::str::{from_utf8_unchecked, FromStr}; #[test] diff --git a/src/lazyvalue/iterator.rs b/src/lazyvalue/iterator.rs index d7c2d49..02e7308 100644 --- a/src/lazyvalue/iterator.rs +++ b/src/lazyvalue/iterator.rs @@ -185,7 +185,7 @@ impl<'de> Iterator for UnsafeArrayIntoIter<'de> { #[cfg(test)] mod test { use super::*; - use crate::{value::JsonValue, JsonType}; + use crate::{value::JsonValueTrait, JsonType}; use bytes::Bytes; #[test] diff --git a/src/lazyvalue/value.rs b/src/lazyvalue/value.rs index 41d4ec8..6cd9554 100644 --- a/src/lazyvalue/value.rs +++ b/src/lazyvalue/value.rs @@ -15,8 +15,9 @@ use crate::reader::Reference; use crate::reader::SliceRead; use crate::serde::Deserializer; use crate::serde::Number; +use crate::value::index::Index; use crate::JsonType; -use crate::{from_str, JsonValue}; +use crate::{from_str, JsonValueTrait}; /// LazyValue is a raw value from json text. Mainly used for get few values from json fastly. /// LazyValue is only generated when using `get` for `Iterator`. @@ -28,8 +29,8 @@ pub struct LazyValue<'de> { own: UnsafeCell>, } -impl<'de> JsonValue for LazyValue<'de> { - type ValueType<'dom> = LazyValue<'dom> where Self: 'dom; +impl<'de> JsonValueTrait for LazyValue<'de> { + type ValueType<'v> = LazyValue<'v> where Self: 'v; fn as_bool(&self) -> Option { match self.raw.as_ref() { @@ -69,7 +70,7 @@ impl<'de> JsonValue for LazyValue<'de> { } } - fn get(&self, index: I) -> Option> { + fn get(&self, index: I) -> Option> { index.lazyvalue_index_into(self) } @@ -187,9 +188,9 @@ impl<'de> LazyValue<'de> { #[cfg(test)] mod test { - use crate::value::JsonValue; + use crate::to_array_iter; + use crate::value::JsonValueTrait; use crate::{get_unchecked, pointer}; - use crate::{to_array_iter, PointerNode}; use super::*; diff --git a/src/lib.rs b/src/lib.rs index eb7cb71..a34aaea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,13 @@ +#![feature(slice_range)] +#![feature(no_sanitize)] #![cfg_attr(not(doctest), doc = include_str!("../README.md"))] #![allow(dead_code)] + mod error; mod input; mod parser; mod pointer; -mod reader; +pub mod reader; mod util; pub mod format; @@ -38,8 +41,8 @@ pub use crate::serde::{ #[doc(inline)] pub use crate::value::{ - dom_from_slice, dom_from_slice_unchecked, dom_from_str, Array, ArrayMut, Document, JsonType, - JsonValue, Object, ObjectMut, Value, ValueMut, + from_value, to_value, Array, JsonContainerTrait, JsonType, JsonValueMutTrait, JsonValueTrait, + Object, Value, ValueRef, }; // re-export the serde trait diff --git a/src/parser.rs b/src/parser.rs index a2d7a88..7a5ae35 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -5,10 +5,12 @@ use crate::pointer::{ tree::MultiIndex, tree::MultiKey, tree::PointerTreeInner, tree::PointerTreeNode, PointerTrait, }; use crate::pointer::{JsonPointer, PointerTree}; +use crate::util::arc::Arc; use crate::util::arch::{get_nonspace_bits, prefix_xor}; use crate::util::num::{parse_number, ParserNumber}; use crate::util::string::*; use crate::util::unicode::{codepoint_to_utf8, hex_to_u32_nocheck}; +use crate::value::shared::Shared; use crate::visitor::JsonVisitor; use crate::JsonType; use arrayref::array_ref; @@ -132,9 +134,10 @@ fn skip_container_loop( /// A structure that used to get from json pub struct Parser { pub(crate) read: R, - error_index: usize, // mark the error position - nospace_bits: u64, // SIMD marked nospace bitmap - nospace_start: isize, // the start position of nospace_bits + error_index: usize, // mark the error position + nospace_bits: u64, // SIMD marked nospace bitmap + nospace_start: isize, // the start position of nospace_bits + pub(crate) shared: Option>, // the shared allocator for `Value` } enum ParseStatus { @@ -152,6 +155,7 @@ where error_index: usize::MAX, nospace_bits: 0, nospace_start: -128, + shared: None, } } @@ -159,7 +163,7 @@ where fn error_index(&self) -> usize { // when parsing strings , we need record the error postion. // it must be smaller than reader.index(). - std::cmp::min(self.error_index, self.read.index() - 1) + std::cmp::min(self.error_index, self.read.index().saturating_sub(1)) } /// Error caused by a byte from next_char(). @@ -204,7 +208,7 @@ where where V: JsonVisitor<'de>, { - let ok = match self.parse_str(strbuf)? { + let ok = match self.parse_str_impl(strbuf)? { Reference::Borrowed(s) => visitor.visit_borrowed_str(s), Reference::Copied(s) => visitor.visit_str(s), }; @@ -216,7 +220,7 @@ where } #[inline(always)] - fn parse_string_inplace_visit(&mut self, visitor: &mut V) -> Result<()> + fn parse_string_inplace(&mut self, visitor: &mut V) -> Result<()> where V: JsonVisitor<'de>, { @@ -290,7 +294,7 @@ where where V: JsonVisitor<'de>, { - let ok = match self.parse_str(strbuf)? { + let ok = match self.parse_str_impl(strbuf)? { Reference::Borrowed(s) => visitor.visit_borrowed_key(s), Reference::Copied(s) => visitor.visit_key(s), }; @@ -434,7 +438,7 @@ where _ => return perr!(self, ExpectedObjectCommaOrEnd), } - let key = match self.parse_str(strbuf)? { + let key = match self.parse_str_impl(strbuf)? { Reference::Borrowed(s) => FastStr::new(s), Reference::Copied(s) => FastStr::new(s), }; @@ -474,12 +478,12 @@ where match r.at(r.index() - 1) { b'-' => self.parse_number_visit(true, visitor), b'0'..=b'9' => self.parse_number_visit(false, visitor), - b'"' => self.parse_string_inplace_visit(visitor), + b'"' => self.parse_string_inplace(visitor), first => self.parse_literal_visit(first, visitor), } } - pub(crate) fn parse_value_goto(&mut self, visitor: &mut V) -> Result<()> + pub(crate) fn parse_value_with_padding(&mut self, visitor: &mut V) -> Result<()> where V: JsonVisitor<'de>, { @@ -553,7 +557,7 @@ where } b'0'..=b'9' => self.parse_number_visit(false, visitor)?, b'-' => self.parse_number_visit(true, visitor)?, - b'"' => self.parse_string_inplace_visit(visitor)?, + b'"' => self.parse_string_inplace(visitor)?, first => self.parse_literal_visit(first, visitor)?, } // count after array primitive value end @@ -582,7 +586,7 @@ where if c != b'"' { return perr!(self, ExpectObjectKeyOrEnd); } - self.parse_string_inplace_visit(visitor)?; + self.parse_string_inplace(visitor)?; self.parse_object_clo()?; match self.skip_space2() { b'{' => { @@ -611,7 +615,228 @@ where } b'0'..=b'9' => self.parse_number_visit(false, visitor)?, b'-' => self.parse_number_visit(true, visitor)?, - b'"' => self.parse_string_inplace_visit(visitor)?, + b'"' => self.parse_string_inplace(visitor)?, + first => self.parse_literal_visit(first, visitor)?, + } + // count after object primitive value end + let len = depth.len(); + depth[len - 1] += 1; + match self.skip_space2() { + b',' => { + c = self.skip_space2(); + + continue 'obj_key; + } + b'}' => { + let back = depth[depth.len() - 1]; + check_visit!( + self, + visitor.visit_object_end((back & (ARR_MASK - 1)) as usize) + ); + state = Fsm::ScopeEnd; + break 'obj_key; + } + _ => return perr!(self, ExpectedArrayCommaOrEnd), + } + } + } + Fsm::ScopeEnd => { + 'scope_end: loop { + depth.pop(); + if depth.is_empty() { + // Note: we will not check trailing charaters + // because get_from maybe returns all remaining bytes. + return Ok(()); + } + // count after container value end + let len = depth.len(); + depth[len - 1] += 1; + c = self.skip_space2(); + if (depth[len - 1] & ARR_MASK) != 0 { + // parent is array + match c { + b',' => { + c = self.skip_space2(); + state = Fsm::ArrVal; + + break 'scope_end; + } + b']' => { + let back = depth[depth.len() - 1]; + check_visit!( + self, + visitor.visit_array_end((back & (ARR_MASK - 1)) as usize) + ); + + continue 'scope_end; + } + _ => return perr!(self, ExpectedArrayCommaOrEnd), + } + } else { + // parent is object + match c { + b',' => { + c = self.skip_space2(); + state = Fsm::ObjKey; + + break 'scope_end; + } + b'}' => { + let back = depth[depth.len() - 1]; + check_visit!( + self, + visitor.visit_object_end((back & (ARR_MASK - 1)) as usize) + ); + + continue 'scope_end; + } + _ => return perr!(self, ExpectedObjectCommaOrEnd), + } + } + } + } + } + } + } + + pub(crate) fn parse_value_without_padding(&mut self, visitor: &mut V) -> Result<()> + where + V: JsonVisitor<'de>, + { + const COMMON_DEPTH: usize = 20; + const ARR_MASK: u32 = 1u32 << 31; + const OBJ_MASK: u32 = 0u32; + let mut depth = SmallVec::<[u32; COMMON_DEPTH]>::new(); + let mut c: u8; + + enum Fsm { + ScopeEnd, + ArrVal, + ObjKey, + } + + let mut strbuf = Vec::with_capacity(DEFAULT_KEY_BUF_CAPACITY); + let mut state; + match self.skip_space2() { + b'[' => { + check_visit!(self, visitor.visit_array_start(0)); + depth.push(ARR_MASK); + c = self.skip_space2(); + if c == b']' { + check_visit!(self, visitor.visit_array_end(0)); + state = Fsm::ScopeEnd; + } else { + state = Fsm::ArrVal; + } + } + b'{' => { + check_visit!(self, visitor.visit_object_start(0)); + depth.push(OBJ_MASK); + c = self.skip_space2(); + if c == b'}' { + check_visit!(self, visitor.visit_object_end(0)); + state = Fsm::ScopeEnd; + } else { + state = Fsm::ObjKey; + } + } + b'-' => return self.parse_number_visit(true, visitor), + b'0'..=b'9' => return self.parse_number_visit(false, visitor), + b'"' => return self.parse_string(visitor, &mut strbuf), + 0 => return perr!(self, EofWhileParsing), + first => return self.parse_literal_visit(first, visitor), + } + + loop { + match state { + Fsm::ArrVal => { + 'arr_val: loop { + match c { + b'{' => { + check_visit!(self, visitor.visit_object_start(0)); + depth.push(OBJ_MASK); + c = self.skip_space2(); + if c == b'}' { + check_visit!(self, visitor.visit_object_end(0)); + state = Fsm::ScopeEnd; + } else { + state = Fsm::ObjKey; + } + break 'arr_val; + } + b'[' => { + check_visit!(self, visitor.visit_array_start(0)); + depth.push(ARR_MASK); + c = self.skip_space2(); + if c == b']' { + check_visit!(self, visitor.visit_array_end(0)); + state = Fsm::ScopeEnd; + break 'arr_val; + } + + continue 'arr_val; + } + b'0'..=b'9' => self.parse_number_visit(false, visitor)?, + b'-' => self.parse_number_visit(true, visitor)?, + b'"' => self.parse_string(visitor, &mut strbuf)?, + first => self.parse_literal_visit(first, visitor)?, + } + // count after array primitive value end + let len = depth.len(); + depth[len - 1] += 1; + match self.skip_space2() { + b',' => { + c = self.skip_space2(); + continue 'arr_val; + } + b']' => { + let back = depth[depth.len() - 1]; + check_visit!( + self, + visitor.visit_array_end((back & (ARR_MASK - 1)) as usize) + ); + state = Fsm::ScopeEnd; + break 'arr_val; + } + _ => return perr!(self, ExpectedArrayCommaOrEnd), + } + } + } + Fsm::ObjKey => { + 'obj_key: loop { + if c != b'"' { + return perr!(self, ExpectObjectKeyOrEnd); + } + self.parse_string(visitor, &mut strbuf)?; + self.parse_object_clo()?; + match self.skip_space2() { + b'{' => { + check_visit!(self, visitor.visit_object_start(0)); + depth.push(OBJ_MASK); + c = self.skip_space2(); + if c == b'}' { + check_visit!(self, visitor.visit_object_end(0)); + state = Fsm::ScopeEnd; + break 'obj_key; + } + + continue 'obj_key; + } + b'[' => { + check_visit!(self, visitor.visit_array_start(0)); + depth.push(ARR_MASK); + c = self.skip_space2(); + if c == b']' { + check_visit!(self, visitor.visit_array_end(0)); + state = Fsm::ScopeEnd; + } else { + state = Fsm::ArrVal; + } + break 'obj_key; + } + b'0'..=b'9' => self.parse_number_visit(false, visitor)?, + b'-' => self.parse_number_visit(true, visitor)?, + b'"' => self.parse_string(visitor, &mut strbuf)?, first => self.parse_literal_visit(first, visitor)?, } // count after object primitive value end @@ -696,7 +921,7 @@ where } #[inline(always)] - pub(crate) fn parse_str<'own>( + pub(crate) fn parse_str_impl<'own>( &mut self, buf: &'own mut Vec, ) -> Result> { @@ -1166,7 +1391,7 @@ where let mut remain = [0u8; 64]; unsafe { - let n = reader.remain() as usize; + let n = reader.remain(); remain[..n].copy_from_slice(reader.peek_n(n).unwrap_unchecked()); } if let Some(count) = skip_container_loop( @@ -1812,7 +2037,7 @@ where let mut visited = 0; loop { - let key = self.parse_str(strbuf)?; + let key = self.parse_str_impl(strbuf)?; self.parse_object_clo()?; if let Some(val) = mkeys.get(key.deref()) { self.get_many_rec(val, out, strbuf, remain, false)?; @@ -1873,7 +2098,7 @@ where let mut visited = 0; loop { - let key = self.parse_str(strbuf)?; + let key = self.parse_str_impl(strbuf)?; self.parse_object_clo()?; if let Some(val) = mkeys.get(key.deref()) { // parse the child point tree @@ -1911,13 +2136,8 @@ where pub(crate) fn remain_u8_slice(&self) -> &'de [u8] { let reader = &self.read; - let len = if reader.remain() >= 0 { - reader.remain() as usize - } else { - 0 - }; let start = reader.index(); - reader.slice_unchecked(start, start + len) + reader.slice_unchecked(start, start + reader.remain()) } fn get_many_index_unchecked( @@ -2042,4 +2262,12 @@ where self.get_many_rec(cur, &mut out, &mut strbuf, &mut remain, is_safe)?; Ok(out) } + + #[inline] + pub(crate) fn get_shared_inc_count(&mut self) -> Arc { + if self.shared.is_none() { + self.shared = Some(Arc::new(Shared::new())); + } + unsafe { self.shared.as_ref().unwrap_unchecked().clone() } + } } diff --git a/src/pointer/point.rs b/src/pointer/point.rs index e3a6ae4..2fa05e8 100644 --- a/src/pointer/point.rs +++ b/src/pointer/point.rs @@ -49,11 +49,11 @@ pub type JsonPointer<'a> = Vec; #[macro_export] macro_rules! pointer { () => ( - std::vec::Vec::::new() + std::vec::Vec::<$crate::PointerNode>::new() ); ($($x:expr),+ $(,)?) => ( <[_]>::into_vec( - std::boxed::Box::new([$(PointerNode::from($x)),+]) + std::boxed::Box::new([$($crate::PointerNode::from($x)),+]) ) ); } @@ -90,8 +90,6 @@ impl<'a> PointerTrait for &'a usize { #[cfg(test)] mod test { - use super::*; - #[test] fn test_json_pointer() { let pointers = pointer![]; diff --git a/src/pointer/tree.rs b/src/pointer/tree.rs index e080bfd..5f4df18 100644 --- a/src/pointer/tree.rs +++ b/src/pointer/tree.rs @@ -1,6 +1,5 @@ use super::PointerTrait; use faststr::FastStr; -use std::collections::hash_map::Entry; use std::collections::HashMap; /// PointerTree is designed for `get_many`. @@ -50,7 +49,6 @@ pub(crate) struct PointerTreeNode { pub(crate) order: Vec, pub(crate) children: PointerTreeInner, } - use PointerTreeInner::{Empty, Index, Key}; impl PointerTreeNode { @@ -78,10 +76,7 @@ impl PointerTreeNode { fn insert_key(&mut self, key: &str) -> &mut Self { if let Key(mkey) = &mut self.children { - match mkey.entry(FastStr::new(key)) { - Entry::Occupied(o) => o.into_mut(), - Entry::Vacant(v) => v.insert(Self::default()), - } + mkey.entry(FastStr::new(key)).or_insert(Self::default()) } else { unreachable!() } @@ -89,10 +84,7 @@ impl PointerTreeNode { fn insert_index(&mut self, idx: usize) -> &mut Self { if let Index(midx) = &mut self.children { - match midx.entry(idx) { - Entry::Occupied(o) => o.into_mut(), - Entry::Vacant(v) => v.insert(Self::default()), - } + midx.entry(idx).or_insert(Self::default()) } else { unreachable!() } @@ -108,7 +100,6 @@ pub(crate) type MultiIndex = HashMap; mod test { use super::*; use crate::pointer; - use crate::PointerNode; #[test] fn test_tree() { diff --git a/src/reader.rs b/src/reader.rs index 7691e19..60ee8b0 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -51,7 +51,7 @@ where // Reader is a unified wrapper for inputs. pub trait Reader<'de>: Sealed { - fn remain(&self) -> isize; + fn remain(&self) -> usize; fn eat(&mut self, n: usize); fn backward(&mut self, n: usize); fn peek_n(&mut self, n: usize) -> Option<&'de [u8]>; @@ -68,7 +68,10 @@ pub trait Reader<'de>: Sealed { a }) } - unsafe fn cur_ptr(&mut self) -> *mut u8; + fn cur_ptr(&mut self) -> *mut u8; + + /// # Safety + /// cur must be a valid pointer in the slice unsafe fn set_ptr(&mut self, cur: *mut u8); fn slice_unchecked(&self, start: usize, end: usize) -> &'de [u8]; @@ -89,8 +92,8 @@ impl<'a> SliceRead<'a> { impl<'a> Reader<'a> for SliceRead<'a> { #[inline(always)] - fn remain(&self) -> isize { - self.slice.len() as isize - self.index as isize + fn remain(&self) -> usize { + self.slice.len() - self.index } #[inline(always)] @@ -134,13 +137,13 @@ impl<'a> Reader<'a> for SliceRead<'a> { } #[inline(always)] - unsafe fn cur_ptr(&mut self) -> *mut u8 { - todo!() + fn cur_ptr(&mut self) -> *mut u8 { + panic!("should only used in PaddedSliceRead"); } #[inline(always)] unsafe fn set_ptr(&mut self, _cur: *mut u8) { - todo!() + panic!("should only used in PaddedSliceRead"); } #[inline(always)] @@ -169,14 +172,14 @@ impl<'a> Reader<'a> for SliceRead<'a> { } } -pub(crate) struct UncheckedSliceRead<'a> { +pub(crate) struct PaddedSliceRead<'a> { base: NonNull, cur: NonNull, len: usize, _life: PhantomData<&'a mut [u8]>, } -impl<'a> UncheckedSliceRead<'a> { +impl<'a> PaddedSliceRead<'a> { const PADDING_SIZE: usize = 64; pub fn new(slice: &'a mut [u8]) -> Self { let base = unsafe { NonNull::new_unchecked(slice.as_mut_ptr()) }; @@ -189,15 +192,16 @@ impl<'a> UncheckedSliceRead<'a> { } } -impl<'a> Reader<'a> for UncheckedSliceRead<'a> { +impl<'a> Reader<'a> for PaddedSliceRead<'a> { #[inline(always)] fn as_u8_slice(&self) -> &'a [u8] { unsafe { std::slice::from_raw_parts(self.base.as_ptr(), self.len) } } #[inline(always)] - fn remain(&self) -> isize { - self.len as isize - self.index() as isize + fn remain(&self) -> usize { + let remain = self.len as isize - self.index() as isize; + std::cmp::max(remain, 0) as usize } #[inline(always)] @@ -241,7 +245,7 @@ impl<'a> Reader<'a> for UncheckedSliceRead<'a> { } #[inline(always)] - unsafe fn cur_ptr(&mut self) -> *mut u8 { + fn cur_ptr(&mut self) -> *mut u8 { self.cur.as_ptr() } diff --git a/src/serde/de.rs b/src/serde/de.rs index 372969f..e656404 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -1,26 +1,21 @@ //! Deserialize JSON data to a Rust data structure. // The code is cloned from [serde_json](https://github.com/serde-rs/json) and modified necessary parts. - -use std::ptr::slice_from_raw_parts; - +use crate::error::{ + Error, + ErrorCode::{self, EofWhileParsing, RecursionLimitExceeded}, + Result, +}; use crate::parser::{as_str, Parser}; use crate::reader::{Reader, Reference, SliceRead}; +use crate::serde::number::BorrowedJsonNumberDeserializer; +use crate::serde::raw::BorrowedRawDeserializer; use crate::util::num::ParserNumber; -use crate::{ - error::{ - Error, - ErrorCode::{self, EofWhileParsing, RecursionLimitExceeded}, - Result, - }, - Document, -}; - +use crate::value::node::Value; use serde::de::{self, Expected, Unexpected}; use serde::forward_to_deserialize_any; - -use crate::serde::number::BorrowedJsonNumberDeserializer; -use crate::serde::raw::BorrowedRawDeserializer; +use std::mem::ManuallyDrop; +use std::ptr::slice_from_raw_parts; const MAX_ALLOWED_DEPTH: u8 = u8::MAX; @@ -87,7 +82,7 @@ impl ParserNumber { } } -macro_rules! deserialize_number { +macro_rules! impl_deserialize_number { ($method:ident) => { fn $method(self, visitor: V) -> Result where @@ -108,7 +103,7 @@ impl<'de, R: Reader<'de>> Deserializer { } } - fn deserialize_number(&mut self, visitor: V) -> Result + pub(crate) fn deserialize_number(&mut self, visitor: V) -> Result where V: de::Visitor<'de>, { @@ -160,7 +155,7 @@ impl<'de, R: Reader<'de>> Deserializer { }, b'"' => { self.scratch.clear(); - match self.parser.parse_str(&mut self.scratch) { + match self.parser.parse_str_impl(&mut self.scratch) { Ok(s) => de::Error::invalid_type(Unexpected::Str(&s), exp), Err(err) => return err, } @@ -230,20 +225,35 @@ impl<'de, R: Reader<'de>> Deserializer { }) } - fn deserialize_document(&mut self, visitor: V) -> Result + fn deserialize_value(&mut self, visitor: V) -> Result where V: de::Visitor<'de>, { + let shared = self.parser.get_shared_inc_count(); + let mut val = Value::new_null(shared.data_ptr()); + let val = if self.parser.read.index() == 0 { + // get n to check trailing characters in later + let n = val.parse_with_padding(self.parser.read.as_u8_slice())?; + self.parser.read.eat(n); + val + } else { + // deserialize some json parts into `Value`, not use padding buffer, avoid the memory copy + val.parse_without_padding(&mut self.parser)?; + val + }; + + // deserialize `Value` must be root node + debug_assert!(val.is_static() || val.is_root()); + if !val.shared_parts().is_null() { + std::mem::forget(shared); + } + + let val = ManuallyDrop::new(val); // #Safety // the json is validate before parsing json, and we pass the document using visit_bytes here. unsafe { - let raw = as_str(self.parser.skip_one_unchecked()?); - let dom = crate::dom_from_slice_unchecked(raw.as_bytes())?; - let binary = &*slice_from_raw_parts( - &dom as *const _ as *const u8, - std::mem::size_of::(), - ); - std::mem::forget(dom); + let binary = + &*slice_from_raw_parts(&val as *const _ as *const u8, std::mem::size_of::()); visitor.visit_bytes(binary) } } @@ -317,7 +327,7 @@ impl<'de, 'a, R: Reader<'de>> de::Deserializer<'de> for &'a mut Deserializer b'0'..=b'9' => tri!(self.parser.parse_number(false)).visit(visitor), b'"' => { self.scratch.clear(); - match tri!(self.parser.parse_str(&mut self.scratch)) { + match tri!(self.parser.parse_str_impl(&mut self.scratch)) { Reference::Borrowed(s) => visitor.visit_borrowed_str(s), Reference::Copied(s) => visitor.visit_str(s), } @@ -370,16 +380,16 @@ impl<'de, 'a, R: Reader<'de>> de::Deserializer<'de> for &'a mut Deserializer } } - deserialize_number!(deserialize_i8); - deserialize_number!(deserialize_i16); - deserialize_number!(deserialize_i32); - deserialize_number!(deserialize_i64); - deserialize_number!(deserialize_u8); - deserialize_number!(deserialize_u16); - deserialize_number!(deserialize_u32); - deserialize_number!(deserialize_u64); - deserialize_number!(deserialize_f32); - deserialize_number!(deserialize_f64); + impl_deserialize_number!(deserialize_i8); + impl_deserialize_number!(deserialize_i16); + impl_deserialize_number!(deserialize_i32); + impl_deserialize_number!(deserialize_i64); + impl_deserialize_number!(deserialize_u8); + impl_deserialize_number!(deserialize_u16); + impl_deserialize_number!(deserialize_u32); + impl_deserialize_number!(deserialize_u64); + impl_deserialize_number!(deserialize_f32); + impl_deserialize_number!(deserialize_f64); fn deserialize_i128(self, visitor: V) -> Result where @@ -460,7 +470,7 @@ impl<'de, 'a, R: Reader<'de>> de::Deserializer<'de> for &'a mut Deserializer let value = match peek { b'"' => { self.scratch.clear(); - match tri!(self.parser.parse_str(&mut self.scratch)) { + match tri!(self.parser.parse_str_impl(&mut self.scratch)) { Reference::Borrowed(s) => visitor.visit_borrowed_str(s), Reference::Copied(s) => visitor.visit_str(s), } @@ -571,8 +581,8 @@ impl<'de, 'a, R: Reader<'de>> de::Deserializer<'de> for &'a mut Deserializer return self.deserialize_raw_value(visitor); } else if name == crate::serde::number::TOKEN { return self.deserialize_json_number(visitor); - } else if name == crate::value::TOKEN { - return self.deserialize_document(visitor); + } else if name == crate::value::de::TOKEN { + return self.deserialize_value(visitor); } } @@ -964,28 +974,55 @@ impl<'de, 'a, R: Reader<'de> + 'a> de::VariantAccess<'de> for UnitVariantAccess< } /// Only deserialize from this after peeking a '"' byte! Otherwise it may +/// deserialize invalid JSON successfully./// Only deserialize from this after peeking a '"' byte! Otherwise it may /// deserialize invalid JSON successfully. struct MapKey<'a, R: 'a> { de: &'a mut Deserializer, } -macro_rules! deserialize_integer_key { - ($method:ident => $visit:ident) => { +macro_rules! deserialize_numeric_key { + ($method:ident) => { fn $method(self, visitor: V) -> Result where V: de::Visitor<'de>, { - self.de.scratch.clear(); - let string = tri!(self.de.parser.parse_str(&mut self.de.scratch)); - match (string.parse(), string) { - (Ok(integer), _) => visitor.$visit(integer), - (Err(_), Reference::Borrowed(s)) => visitor.visit_borrowed_str(s), - (Err(_), Reference::Copied(s)) => visitor.visit_str(s), + let value = tri!(self.de.deserialize_number(visitor)); + if self.de.parser.read.next() != Some(b'"') { + return Err(self.de.parser.error(ErrorCode::ExpectedQuote)); } + + Ok(value) + } + }; + + ($method:ident, $delegate:ident) => { + fn $method(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + match self.de.parser.read.peek() { + Some(b'0'..=b'9' | b'-') => {} + _ => return Err(self.de.parser.error(ErrorCode::ExpectedNumericKey)), + } + + let value = tri!(self.de.$delegate(visitor)); + + if self.de.parser.read.next() != Some(b'"') { + return Err(self.de.parser.error(ErrorCode::ExpectedQuote)); + } + + Ok(value) } }; } +impl<'de, 'a, R> MapKey<'a, R> +where + R: Reader<'de>, +{ + deserialize_numeric_key!(deserialize_number, deserialize_number); +} + impl<'de, 'a, R> de::Deserializer<'de> for MapKey<'a, R> where R: Reader<'de>, @@ -998,22 +1035,51 @@ where V: de::Visitor<'de>, { self.de.scratch.clear(); - match tri!(self.de.parser.parse_str(&mut self.de.scratch)) { + match tri!(self.de.parser.parse_str_impl(&mut self.de.scratch)) { Reference::Borrowed(s) => visitor.visit_borrowed_str(s), Reference::Copied(s) => visitor.visit_str(s), } } - deserialize_integer_key!(deserialize_i8 => visit_i8); - deserialize_integer_key!(deserialize_i16 => visit_i16); - deserialize_integer_key!(deserialize_i32 => visit_i32); - deserialize_integer_key!(deserialize_i64 => visit_i64); - deserialize_integer_key!(deserialize_i128 => visit_i128); - deserialize_integer_key!(deserialize_u8 => visit_u8); - deserialize_integer_key!(deserialize_u16 => visit_u16); - deserialize_integer_key!(deserialize_u32 => visit_u32); - deserialize_integer_key!(deserialize_u64 => visit_u64); - deserialize_integer_key!(deserialize_u128 => visit_u128); + deserialize_numeric_key!(deserialize_i8); + deserialize_numeric_key!(deserialize_i16); + deserialize_numeric_key!(deserialize_i32); + deserialize_numeric_key!(deserialize_i64); + deserialize_numeric_key!(deserialize_i128, deserialize_i128); + deserialize_numeric_key!(deserialize_u8); + deserialize_numeric_key!(deserialize_u16); + deserialize_numeric_key!(deserialize_u32); + deserialize_numeric_key!(deserialize_u64); + deserialize_numeric_key!(deserialize_u128, deserialize_u128); + deserialize_numeric_key!(deserialize_f32); + deserialize_numeric_key!(deserialize_f64); + + fn deserialize_bool(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + let mut value = match self.de.parser.read.next() { + Some(b't') => { + tri!(self.de.parser.parse_literal("rue")); + visitor.visit_bool(true) + } + Some(b'f') => { + tri!(self.de.parser.parse_literal("alse")); + visitor.visit_bool(false) + } + None => Err(self.de.parser.error(ErrorCode::EofWhileParsing)), + Some(peek) => Err(self.de.peek_invalid_type(peek, &visitor)), + }; + + if self.de.parser.read.next() != Some(b'"') { + value = Err(self.de.parser.error(ErrorCode::ExpectedQuote)); + } + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.de.parser.fix_position(err)), + } + } #[inline] fn deserialize_option(self, visitor: V) -> Result @@ -1029,13 +1095,10 @@ where where V: de::Visitor<'de>, { - { - if name == crate::serde::raw::TOKEN { - return self.de.deserialize_raw_value(visitor); - } else if name == crate::serde::number::TOKEN { - return self.de.deserialize_json_number(visitor); - } + if name == crate::serde::raw::TOKEN { + return self.de.deserialize_raw_value(visitor); } + let _ = name; visitor.visit_newtype_struct(self) } @@ -1071,11 +1134,10 @@ where } forward_to_deserialize_any! { - bool f32 f64 char str string unit unit_struct seq tuple tuple_struct map - struct identifier ignored_any + char str string unit unit_struct seq tuple tuple_struct map struct + identifier ignored_any } } - ////////////////////////////////////////////////////////////////////////////// fn from_trait<'de, R, T>(read: R) -> Result diff --git a/src/serde/mod.rs b/src/serde/mod.rs index 88f0b0b..3a1c114 100644 --- a/src/serde/mod.rs +++ b/src/serde/mod.rs @@ -1,6 +1,6 @@ mod de; -mod number; -mod raw; +pub(crate) mod number; +pub(crate) mod raw; mod ser; pub use self::de::{from_slice, from_slice_unchecked, from_str, Deserializer}; @@ -72,6 +72,7 @@ mod test { struct TestData<'a> { fieldless: FieldlessEnum, enummap: HashMap, + nummap: HashMap, enum_: Enum, // basic types @@ -81,7 +82,6 @@ mod test { int128: i128, uint128: u128, char_: char, - // string or bytes str_: &'a str, // bytes_: &'a [u8], @@ -89,7 +89,6 @@ mod test { faststr: FastStr, #[serde(borrow)] cow: Cow<'a, str>, - // containers vector: Vec, array: [u32; 1], @@ -108,7 +107,7 @@ mod test { #[serde(borrow)] wrapper: Wrapper<'a>, - phan_struct: Phan<()>, + phan_struct: Phan<&'a ()>, } #[test] @@ -120,13 +119,11 @@ mod test { int128: -22_000_000_000_000_000_000_000_000, uint128: 11_000_000_000_000_000_000_000_000, char_: 'A', - str_: "hello world", // bytes_: &[0x52, 0x75, 0x73, 0x74], string: String::from("hello world"), faststr: FastStr::from("hello world"), cow: Cow::Borrowed("borrowed"), - vector: vec![42, 24, 7], array: [99], empty_array: [], @@ -150,6 +147,12 @@ mod test { m.insert(Enum::One, FieldlessEnum::Unit); m }, + nummap: { + let mut m = HashMap::new(); + m.insert(0, FieldlessEnum::Struct {}); + m.insert(1, FieldlessEnum::Unit); + m + }, fieldenum: FieldEnum::Tuple((FastStr::from("test"), 42)), fieldless: FieldlessEnum::Struct {}, enum_: Enum::One, @@ -177,7 +180,7 @@ mod test { #[test] fn test_struct_with_skipped() { - let json = r#"{"unknown":0,"unknown":null,"unknown":1234e123,"unknown":1.234,"unknown":[],"unknown":{},"unknown":{"a":[]},"unknown":[1,2,3],"fieldless":{"Struct":{}},"enummap":{"Zero":{"Struct":{}},"One":"Unit"},"enum_":"One","boolean":true,"integer":-42,"float":3.33,"int128":-22000000000000000000000000,"uint128":11000000000000000000000000,"char_":"A","str_":"hello world","string":"hello world","faststr":"hello world","cow":"borrowed","vector":[42,24,7],"array":[99],"empty_array":[],"map":{"key2":2.2,"key1":1.1},"map_opkey":{"key1":1.1},"option":"I'm here","fieldenum":{"Tuple":["test",42]},"tuple":[42,"test"],"tuple_struct":[42,3.33],"unit_struct":null,"wrapper":"hello","phan_struct":{"phan":"test data","_data":null},"unknown":0,"unknown":null,"unknown":1234e123,"unknown":1.234,"unknown":[],"unknown":{},"unknown":{"a":[]},"unknown":[1,2,3]}"#; + let json = r#"{"unknown":0,"unknown":null,"unknown":1234e123,"unknown":1.234,"unknown":[],"unknown":{},"unknown":{"a":[]},"unknown":[1,2,3],"fieldless":{"Struct":{}},"enummap":{"Zero":{"Struct":{}},"One":"Unit"},"nummap":{"0":{"Struct":{}},"1":"Unit"},"enum_":"One","boolean":true,"integer":-42,"float":3.33,"int128":-22000000000000000000000000,"uint128":11000000000000000000000000,"char_":"A","str_":"hello world","string":"hello world","faststr":"hello world","cow":"borrowed","vector":[42,24,7],"array":[99],"empty_array":[],"map":{"key2":2.2,"key1":1.1},"map_opkey":{"key1":1.1},"option":"I'm here","fieldenum":{"Tuple":["test",42]},"tuple":[42,"test"],"tuple_struct":[42,3.33],"unit_struct":null,"wrapper":"hello","phan_struct":{"phan":"test data","_data":null},"unknown":0,"unknown":null,"unknown":1234e123,"unknown":1.234,"unknown":[],"unknown":{},"unknown":{"a":[]},"unknown":[1,2,3]}"#; let expect: TestData = serde_json::from_str(json).unwrap(); let val: TestData = from_str(json).unwrap(); diff --git a/src/serde/number.rs b/src/serde/number.rs index 46c325c..83c454c 100644 --- a/src/serde/number.rs +++ b/src/serde/number.rs @@ -1,5 +1,6 @@ // The code is cloned from [serde_json](https://github.com/serde-rs/json) and modified necessary parts. +use crate::error::make_error; use crate::util::num::ParserNumber; use crate::util::private::Sealed; use serde::de::value::BorrowedStrDeserializer; @@ -8,7 +9,7 @@ use serde::ser::SerializeStruct; /// Represents a JSON number, whether integer or floating point. #[derive(Clone, PartialEq, Eq, Hash)] pub struct Number { - n: N, + pub(crate) n: N, } #[derive(Debug, Copy, Clone)] @@ -260,7 +261,7 @@ macro_rules! deserialize_any { } macro_rules! deserialize_number { - ($deserialize:ident => $visit:ident) => { + ($deserialize:ident) => { fn $deserialize(self, visitor: V) -> Result where V: Visitor<'de>, @@ -275,18 +276,18 @@ impl<'de> Deserializer<'de> for Number { deserialize_any!(owned); - deserialize_number!(deserialize_i8 => visit_i8); - deserialize_number!(deserialize_i16 => visit_i16); - deserialize_number!(deserialize_i32 => visit_i32); - deserialize_number!(deserialize_i64 => visit_i64); - deserialize_number!(deserialize_i128 => visit_i128); - deserialize_number!(deserialize_u8 => visit_u8); - deserialize_number!(deserialize_u16 => visit_u16); - deserialize_number!(deserialize_u32 => visit_u32); - deserialize_number!(deserialize_u64 => visit_u64); - deserialize_number!(deserialize_u128 => visit_u128); - deserialize_number!(deserialize_f32 => visit_f32); - deserialize_number!(deserialize_f64 => visit_f64); + deserialize_number!(deserialize_i8); + deserialize_number!(deserialize_i16); + deserialize_number!(deserialize_i32); + deserialize_number!(deserialize_i64); + deserialize_number!(deserialize_i128); + deserialize_number!(deserialize_u8); + deserialize_number!(deserialize_u16); + deserialize_number!(deserialize_u32); + deserialize_number!(deserialize_u64); + deserialize_number!(deserialize_u128); + deserialize_number!(deserialize_f32); + deserialize_number!(deserialize_f64); forward_to_deserialize_any! { bool char str string bytes byte_buf option unit unit_struct @@ -300,18 +301,18 @@ impl<'de, 'a> Deserializer<'de> for &'a Number { deserialize_any!(ref); - deserialize_number!(deserialize_i8 => visit_i8); - deserialize_number!(deserialize_i16 => visit_i16); - deserialize_number!(deserialize_i32 => visit_i32); - deserialize_number!(deserialize_i64 => visit_i64); - deserialize_number!(deserialize_i128 => visit_i128); - deserialize_number!(deserialize_u8 => visit_u8); - deserialize_number!(deserialize_u16 => visit_u16); - deserialize_number!(deserialize_u32 => visit_u32); - deserialize_number!(deserialize_u64 => visit_u64); - deserialize_number!(deserialize_u128 => visit_u128); - deserialize_number!(deserialize_f32 => visit_f32); - deserialize_number!(deserialize_f64 => visit_f64); + deserialize_number!(deserialize_i8); + deserialize_number!(deserialize_i16); + deserialize_number!(deserialize_i32); + deserialize_number!(deserialize_i64); + deserialize_number!(deserialize_i128); + deserialize_number!(deserialize_u8); + deserialize_number!(deserialize_u16); + deserialize_number!(deserialize_u32); + deserialize_number!(deserialize_u64); + deserialize_number!(deserialize_u128); + deserialize_number!(deserialize_f32); + deserialize_number!(deserialize_f64); forward_to_deserialize_any! { bool char str string bytes byte_buf option unit unit_struct @@ -374,6 +375,22 @@ macro_rules! impl_from_signed { impl_from_unsigned!(u8, u16, u32, u64, usize); impl_from_signed!(i8, i16, i32, i64, isize); +impl TryFrom for Number { + type Error = crate::Error; + #[inline] + fn try_from(f: f32) -> Result { + Number::try_from(f as f64) + } +} + +impl TryFrom for Number { + type Error = crate::Error; + fn try_from(value: f64) -> Result { + Number::from_f64(value) + .ok_or_else(|| make_error("NaN or Infinity is not a valid JSON value".to_string())) + } +} + /// Represents a JSON number with arbitrary precision, like as Golang json.Number #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct RawNumber { diff --git a/src/util/arc.rs b/src/util/arc.rs new file mode 100644 index 0000000..a8a1db0 --- /dev/null +++ b/src/util/arc.rs @@ -0,0 +1,154 @@ +use std::fmt; +use std::fmt::Display; +use std::fmt::Formatter; +use std::marker::PhantomData; +use std::ops::Deref; +use std::ptr::NonNull; +use std::sync::atomic; +use std::sync::atomic::Ordering::Acquire; +use std::sync::atomic::Ordering::Relaxed; +use std::sync::atomic::Ordering::Release; + +use crate::field_offset; + +pub struct Arc { + ptr: NonNull>, + phantom: PhantomData>, +} + +impl Arc { + pub fn new(data: T) -> Arc { + let x = Box::into_raw(Box::new(ArcInner { + refcnt: atomic::AtomicUsize::new(1), + data, + })); + Self { + ptr: unsafe { NonNull::new_unchecked(x) }, + phantom: PhantomData, + } + } + + #[inline] + pub(crate) unsafe fn from_raw(ptr: *const T) -> Arc { + let offset = field_offset!(ArcInner, data); + let ptr = (ptr as *mut u8).sub(offset) as *mut ArcInner; + Self { + ptr: NonNull::new_unchecked(ptr), + phantom: PhantomData, + } + } + + #[inline] + pub(crate) unsafe fn clone_from_raw(ptr: *const T) -> Arc { + let now = Self::from_raw(ptr); + let ret = now.clone(); + std::mem::forget(now); + ret + } + + #[inline] + pub(crate) fn inner(&self) -> &ArcInner { + unsafe { self.ptr.as_ref() } + } + + #[inline] + pub(crate) fn refcnt(&self) -> usize { + self.inner().refcnt.load(Relaxed) + } + + #[inline] + pub(crate) fn inner_ptr(&self) -> *const ArcInner { + self.ptr.as_ptr() + } + + #[inline] + pub(crate) fn data_ptr(&self) -> *const T { + &self.inner().data as *const T + } +} + +impl Deref for Arc { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + &self.inner().data + } +} + +impl Display for Arc { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(&**self, f) + } +} + +impl Drop for Arc { + #[inline] + fn drop(&mut self) { + // Because `fetch_sub` is already atomic, we do not need to synchronize + // with other threads unless we are going to delete the object. + if self.inner().refcnt.fetch_sub(1, Release) != 1 { + return; + } + + // TODO: fix me when using ThreadSanitizer + // ThreadSanitizer does not support memory fences. To avoid false positive + // reports in Arc / Weak implementation use atomic loads for synchronization + // instead. + atomic::fence(Acquire); + + let inner = unsafe { Box::from_raw(self.ptr.as_ptr()) }; + drop(inner); + } +} + +impl Clone for Arc { + #[inline] + fn clone(&self) -> Arc { + // Using a relaxed ordering is alright here, as knowledge of the + // original reference prevents other threads from erroneously deleting + // the object. + // + self.inner().refcnt.fetch_add(1, Relaxed); + + Self { + ptr: self.ptr, + phantom: PhantomData, + } + } +} + +#[derive(Debug)] +#[repr(C)] +pub(crate) struct ArcInner { + data: T, + refcnt: atomic::AtomicUsize, +} + +impl ArcInner { + #[inline] + pub(crate) fn new(data: T) -> Self { + Self { + refcnt: atomic::AtomicUsize::new(1), + data, + } + } + + #[inline] + pub(crate) fn data(&self) -> &T { + &self.data + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_arc() { + let x = Arc::new(42); + let y = x.clone(); + assert_eq!(*x, 42); + assert_eq!(*y, 42); + } +} diff --git a/src/util/mod.rs b/src/util/mod.rs index ff0a9da..95f03ea 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,6 +1,10 @@ -pub mod arch; -pub mod num; -pub mod private; -pub mod string; -pub mod unicode; -pub mod utf8; +pub(crate) mod arc; +pub(crate) mod arch; +pub(crate) mod num; +pub(crate) mod offset; +pub(crate) mod private; +pub(crate) mod reborrow; +pub(crate) mod string; +pub(crate) mod taggedptr; +pub(crate) mod unicode; +pub(crate) mod utf8; diff --git a/src/util/offset.rs b/src/util/offset.rs new file mode 100644 index 0000000..38d4d0c --- /dev/null +++ b/src/util/offset.rs @@ -0,0 +1,9 @@ +#[macro_export] +macro_rules! field_offset { + ($type:ty, $field:tt) => {{ + let dummy = std::mem::MaybeUninit::<$type>::uninit(); + let dummy_ptr = dummy.as_ptr(); + let member_ptr = unsafe { std::ptr::addr_of!((*dummy_ptr).$field) }; + member_ptr as usize - dummy_ptr as usize + }}; +} diff --git a/src/util/private.rs b/src/util/private.rs index b07cc12..ea970b7 100644 --- a/src/util/private.rs +++ b/src/util/private.rs @@ -1,4 +1,4 @@ -use crate::reader::{SliceRead, UncheckedSliceRead}; +use crate::reader::{PaddedSliceRead, SliceRead}; use bytes::Bytes; use faststr::FastStr; @@ -11,6 +11,6 @@ impl Sealed for FastStr {} impl Sealed for Bytes {} impl Sealed for u8 {} impl<'de> Sealed for SliceRead<'de> {} -impl<'de> Sealed for UncheckedSliceRead<'de> {} +impl<'de> Sealed for PaddedSliceRead<'de> {} impl<'a, T> Sealed for &'a T where T: ?Sized + Sealed {} impl Sealed for [T] where T: Sized + Sealed {} diff --git a/src/util/reborrow.rs b/src/util/reborrow.rs new file mode 100644 index 0000000..9332122 --- /dev/null +++ b/src/util/reborrow.rs @@ -0,0 +1,74 @@ +// Copied from Rust-lang BTreeMap implementation + +use core::marker::PhantomData; +use core::ptr::NonNull; + +/// Models a reborrow of some unique reference, when you know that the reborrow +/// and all its descendants (i.e., all pointers and references derived from it) +/// will not be used any more at some point, after which you want to use the +/// original unique reference again. +/// +/// The borrow checker usually handles this stacking of borrows for you, but +/// some control flows that accomplish this stacking are too complicated for +/// the compiler to follow. A `DormantMutRef` allows you to check borrowing +/// yourself, while still expressing its stacked nature, and encapsulating +/// the raw pointer code needed to do this without undefined behavior. +pub struct DormantMutRef<'a, T> { + ptr: NonNull, + _marker: PhantomData<&'a mut T>, +} + +unsafe impl<'a, T> Sync for DormantMutRef<'a, T> where &'a mut T: Sync {} +unsafe impl<'a, T> Send for DormantMutRef<'a, T> where &'a mut T: Send {} + +impl<'a, T> DormantMutRef<'a, T> { + /// Capture a unique borrow, and immediately reborrow it. For the compiler, + /// the lifetime of the new reference is the same as the lifetime of the + /// original reference, but you promise to use it for a shorter period. + pub fn new(t: &'a mut T) -> (&'a mut T, Self) { + let ptr = NonNull::from(t); + // SAFETY: we hold the borrow throughout 'a via `_marker`, and we expose + // only this reference, so it is unique. + let new_ref = unsafe { &mut *ptr.as_ptr() }; + ( + new_ref, + Self { + ptr, + _marker: PhantomData, + }, + ) + } + + /// Revert to the unique borrow initially captured. + /// + /// # Safety + /// + /// The reborrow must have ended, i.e., the reference returned by `new` and + /// all pointers and references derived from it, must not be used anymore. + pub unsafe fn awaken(self) -> &'a mut T { + // SAFETY: our own safety conditions imply this reference is again unique. + unsafe { &mut *self.ptr.as_ptr() } + } + + /// Borrows a new mutable reference from the unique borrow initially captured. + /// + /// # Safety + /// + /// The reborrow must have ended, i.e., the reference returned by `new` and + /// all pointers and references derived from it, must not be used anymore. + pub unsafe fn reborrow(&mut self) -> &'a mut T { + // SAFETY: our own safety conditions imply this reference is again unique. + unsafe { &mut *self.ptr.as_ptr() } + } + + /// Borrows a new shared reference from the unique borrow initially captured. + /// + /// # Safety + /// + /// The reborrow must have ended, i.e., the reference returned by `new` and + /// all pointers and references derived from it, must not be used anymore. + pub unsafe fn reborrow_shared(&self) -> &'a T { + // SAFETY: our own safety conditions imply this reference is again unique. + unsafe { &*self.ptr.as_ptr() } + } +} diff --git a/src/util/string.rs b/src/util/string.rs index c627a4b..b25c84a 100644 --- a/src/util/string.rs +++ b/src/util/string.rs @@ -572,8 +572,10 @@ unsafe fn escape_unchecked(src: &mut *const u8, nb: &mut usize, dst: &mut *mut u } } +#[inline(always)] fn cross_page(ptr: *const u8, step: usize) -> bool { - ((ptr as usize & 4095) + step) > 4096 + let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }; + ((ptr as usize & (page_size - 1)) + step) > page_size } #[inline(always)] @@ -594,7 +596,10 @@ pub fn format_string(value: &str, dst: &mut [MaybeUninit], need_quote: bool) while nb >= LANS { let v = { let raw = std::slice::from_raw_parts(sptr, LANS); - u8x32::from_slice_unaligned_unchecked(raw) + #[no_sanitize(address)] + { + u8x32::from_slice_unaligned_unchecked(raw) + } }; v.write_to_slice_unaligned_unchecked(std::slice::from_raw_parts_mut(dptr, LANS)); let mask = escaped_mask(v); @@ -611,14 +616,23 @@ pub fn format_string(value: &str, dst: &mut [MaybeUninit], need_quote: bool) } } - let mut temp: [u8; 64] = [0u8; 64]; + let mut temp: [u8; LANS] = [0u8; LANS]; while nb > 0 { let v = if cross_page(sptr, LANS) { std::ptr::copy_nonoverlapping(sptr, temp[..].as_mut_ptr(), nb); u8x32::from_slice_unaligned_unchecked(&temp[..]) } else { - let raw = std::slice::from_raw_parts(sptr, LANS); - u8x32::from_slice_unaligned_unchecked(raw) + #[cfg(not(debug_assertions))] + { + // disable memory sanitizer here + let raw = std::slice::from_raw_parts(sptr, LANS); + u8x32::from_slice_unaligned_unchecked(raw) + } + #[cfg(debug_assertions)] + { + std::ptr::copy_nonoverlapping(sptr, temp[..].as_mut_ptr(), nb); + u8x32::from_slice_unaligned_unchecked(&temp[..]) + } }; v.write_to_slice_unaligned_unchecked(std::slice::from_raw_parts_mut(dptr, LANS)); diff --git a/src/util/taggedptr.rs b/src/util/taggedptr.rs new file mode 100644 index 0000000..68620aa --- /dev/null +++ b/src/util/taggedptr.rs @@ -0,0 +1,80 @@ +use std::mem::transmute; + +/// TaggpedPtr is a pointer of T with a tag. +/// +#[derive(Debug)] +pub(crate) struct TaggedPtr { + // ptr is allow null ptr + ptr: *const u8, + _marker: std::marker::PhantomData<*const T>, +} + +impl TaggedPtr { + const TAG_MASK: usize = std::mem::align_of::() - 1; + const PTR_MASK: usize = !Self::TAG_MASK; + + #[inline] + pub const fn new(ptr: *const T, tag: usize) -> Self { + let mut slf = Self { + ptr: ptr.cast(), + _marker: std::marker::PhantomData, + }; + #[allow(clippy::transmutes_expressible_as_ptr_casts)] + let mut raw: usize = unsafe { transmute(slf.ptr) }; + raw |= tag; + slf.ptr = raw as *const u8; + slf + } + + #[inline] + pub fn set_tag(&mut self, tag: usize) { + let mut raw = self.ptr as usize; + raw &= Self::PTR_MASK; + raw |= tag; + self.ptr = raw as *const u8; + } + + #[inline] + pub fn tag(&self) -> usize { + (self.ptr as usize) & Self::TAG_MASK + } + + #[inline] + pub fn ptr(&self) -> *const T { + ((self.ptr as usize) & Self::PTR_MASK) as *const T + } + + #[inline] + pub fn set_ptr(&mut self, ptr: *const T) { + let tag = self.tag(); + self.ptr = ((ptr as usize) | tag) as *const u8; + } + + #[inline] + pub fn addr(&self) -> usize { + self.ptr as usize + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[repr(align(16))] + struct Fox; + + #[test] + fn test_taggedptr() { + let f = Fox; + let f2 = Fox; + let mut tagged: TaggedPtr = TaggedPtr::new(&f as *const _, 0xf); + assert_eq!(tagged.tag(), 0xf); + tagged.set_tag(2); + assert_eq!(tagged.tag(), 2); + assert_eq!(tagged.ptr(), &f as *const _); + + tagged.set_ptr(&f2 as *const _); + assert_eq!(tagged.tag(), 2); + assert_eq!(tagged.ptr(), &f2 as *const _); + } +} diff --git a/src/value/alloctor.rs b/src/value/alloctor.rs new file mode 100644 index 0000000..c138318 --- /dev/null +++ b/src/value/alloctor.rs @@ -0,0 +1,69 @@ +use bumpalo::Bump; +use parking_lot::Mutex; +use std::{alloc::Layout, ptr::NonNull}; + +#[derive(Debug)] +pub(crate) struct SyncBump(pub(crate) Mutex); + +#[derive(Debug)] +pub(crate) struct AllocError; + +impl std::error::Error for AllocError {} + +impl std::fmt::Display for AllocError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("alloc error") + } +} + +pub(crate) trait AllocatorTrait { + fn try_alloc_layout(&self, layout: Layout) -> Result, AllocError>; + + fn deallocate(&self, ptr: NonNull, layout: Layout); + + fn allocate(&self, layout: Layout) -> NonNull { + self.try_alloc_layout(layout).expect("OOM, too big layout") + } + + #[allow(clippy::mut_from_ref)] + fn alloc_str(&self, s: &str) -> &mut str { + let layout = Layout::from_size_align(s.len(), 1).unwrap(); + let ptr = self.allocate(layout); + unsafe { + std::ptr::copy_nonoverlapping(s.as_ptr(), ptr.as_ptr(), s.len()); + } + unsafe { + std::str::from_utf8_unchecked_mut(std::slice::from_raw_parts_mut(ptr.as_ptr(), s.len())) + } + } + + #[allow(clippy::mut_from_ref)] + fn alloc_slice(&self, len: usize) -> &mut [T] { + let layout = Layout::array::(len).expect("OOM, too big layout"); + let ptr = self.allocate(layout); + unsafe { std::slice::from_raw_parts_mut(ptr.as_ptr() as *mut T, len) } + } +} + +impl Default for SyncBump { + fn default() -> Self { + Self::new() + } +} + +impl SyncBump { + pub fn new() -> Self { + Self(Mutex::new(Bump::new())) + } +} + +impl AllocatorTrait for SyncBump { + fn try_alloc_layout(&self, layout: Layout) -> Result, AllocError> { + self.0 + .lock() + .try_alloc_layout(layout) + .map_err(|_| AllocError) + } + + fn deallocate(&self, _ptr: NonNull, _layout: Layout) {} +} diff --git a/src/value/array.rs b/src/value/array.rs new file mode 100644 index 0000000..fb998fe --- /dev/null +++ b/src/value/array.rs @@ -0,0 +1,925 @@ +use super::shared::Shared; +use crate::serde::tri; +use crate::util::arc::Arc; +use crate::value::from::SharedCtxGuard; +use crate::value::node::Value; +use crate::value::value_trait::JsonValueTrait; +use std::fmt::Debug; +use std::iter::FusedIterator; +use std::ops::Deref; +use std::ops::DerefMut; +use std::ops::Range; +use std::ops::RangeBounds; +use std::ptr::NonNull; +use std::slice::from_raw_parts; +use std::slice::from_raw_parts_mut; + +/// Array represents a JSON array. Its most APIs are as `Array`. +/// +#[derive(Debug, Eq, PartialEq, Clone)] +#[repr(transparent)] +pub struct Array(pub(crate) Value); + +pub(crate) const DEFAULT_ARRAY_CAP: usize = 8; + +impl Array { + /// Returns the inner [`Value`]. + #[inline] + pub fn into_value(self) -> Value { + self.0 + } + + /// Constructs a new, empty `Array`. + /// + /// The array will not allocate until elements are pushed onto it. + /// + #[inline] + pub const fn new() -> Self { + let value = Value { + meta: super::node::Meta::new(super::node::ROOT_ARRAY, std::ptr::null()), + data: super::node::Data { + achildren: std::ptr::null_mut(), + }, + }; + Array(value) + } + + /// Constructs a new, empty `Array` with at least the specified capacity. + /// + /// The array will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is 0, the array will not allocate. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` bytes. + /// + #[inline] + pub fn with_capacity(capacity: usize) -> Self { + let mut array = Self::new(); + array.reserve(capacity); + array + } + + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the given `Array`. The collection may reserve more space to + /// speculatively avoid frequent reallocations. After calling `reserve`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Does nothing if capacity is already sufficient. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` bytes. + /// + /// # Examples + /// ``` + /// use sonic_rs::array; + /// let mut arr = array![1, 2, 3]; + /// arr.reserve(10); + /// assert!(arr.capacity() >= 13); + /// ``` + /// + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.0.reserve::(additional); + } + + /// Resizes the `Array` in-place so that `len` is equal to `new_len`. + /// + /// If `new_len` is greater than `len`, the `Array` is extended by the + /// difference, with each additional slot filled with the `Value` converted from `value`. + /// If `new_len` is less than `len`, the `Array` is simply truncated. + /// + /// If you need more flexibility, use [`Array::resize_with`]. + /// If you only need to resize to a smaller size, use [`Array::truncate`]. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{array, json}; + /// + /// let mut arr = array!["hello"]; + /// arr.resize(3, "world"); + /// assert_eq!(arr, ["hello", "world", "world"]); + /// + /// arr.resize(2, 0); + /// assert_eq!(arr, ["hello", "world"]); + /// + /// arr.resize(4, json!("repeat")); + /// assert_eq!(arr, array!["hello", "world", "repeat", "repeat"]); + /// ``` + #[inline] + pub fn resize>(&mut self, new_len: usize, value: T) { + if new_len > self.len() { + self.reserve(new_len - self.len()); + for _ in self.len()..new_len { + self.push(value.clone().into()); + } + } else { + self.truncate(new_len); + } + } + + /// Resizes the `Array` in-place so that `len` is equal to `new_len`. + /// + /// If `new_len` is greater than `len`, the `Array` is extended by the + /// difference, with each additional slot filled with the result of + /// calling the closure `f`. The return values from `f` will end up + /// in the `Array` in the order they have been generated. + /// + /// If `new_len` is less than `len`, the `Array` is simply truncated. + /// + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::array; + /// let mut arr = array![1, 2, 3]; + /// arr.resize_with(5, Default::default); + /// assert_eq!(arr, array![1, 2, 3, null, null]); + /// + /// let mut arr = array![]; + /// let mut p = 1; + /// arr.resize_with(4, || { p *= 2; p.into() }); + /// assert_eq!(arr, [2, 4, 8, 16]); + /// ``` + #[inline] + pub fn resize_with(&mut self, new_len: usize, mut f: F) + where + F: FnMut() -> Value, + { + if new_len > self.len() { + self.reserve(new_len - self.len()); + for _ in self.len()..new_len { + self.push(f()); + } + } else { + self.truncate(new_len); + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` for which `f(&e)` returns `false`. + /// This method operates in place, visiting each element exactly once in the + /// original order, and preserves the order of the retained elements. + /// + /// Because the elements are visited exactly once in the original order, + /// external state may be used to decide which elements to keep. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::array; + /// let mut arr = array![1, 2, 3, 4, 5]; + /// let keep = [false, true, true, false, true]; + /// let mut iter = keep.iter(); + /// arr.retain(|_| *iter.next().unwrap()); + /// assert_eq!(arr, array![2, 3, 5]); + /// ``` + #[inline] + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&Value) -> bool, + { + self.retain_mut(|elem| f(elem)); + } + + /// Splits the collection into two at the given index. + /// + /// Returns a newly allocated array containing the elements in the range + /// `[at, len)`. After the call, the original array will be left containing + /// the elements `[0, at)` with its previous capacity unchanged. + /// + /// # Panics + /// + /// Panics if `at > len`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::array; + /// let mut arr = array![1, 2, 3]; + /// let arr2 = arr.split_off(1); + /// assert_eq!(arr, [1]); + /// assert_eq!(arr2, [2, 3]); + /// assert_eq!(arr.split_off(1), array![]); + /// ``` + #[inline] + pub fn split_off(&mut self, at: usize) -> Self { + let len = self.len(); + assert!(at <= len, "at {} out of bounds(len: {})", at, len); + + let mut arr = Self::new_in(self.0.shared_clone()); + if at == len { + return arr; + } + arr.reserve(len - at); + + unsafe { + let src = self.as_mut_ptr().add(at); + let dst = arr.as_mut_ptr(); + std::ptr::copy_nonoverlapping(src, dst, len - at); + self.set_len(at); + arr.set_len(len - at); + } + arr + } + + /// Removes an element from the array and returns it. + /// + /// The removed element is replaced by the last element of the array. + /// + /// This does not preserve ordering, but is *O*(1). + /// If you need to preserve the element order, use [`remove`] instead. + /// + /// [`remove`]: Array::remove + /// + /// # Panics + /// + /// Panics if `index` is out of bounds. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::array; + /// let mut v = array!["foo", "bar", "baz", "qux"]; + /// + /// assert_eq!(v.swap_remove(1), "bar"); + /// assert_eq!(v, ["foo", "qux", "baz"]); + /// + /// assert_eq!(v.swap_remove(0), "foo"); + /// assert_eq!(v, ["baz", "qux"]); + /// ``` + #[inline] + pub fn swap_remove(&mut self, index: usize) -> Value { + let len = self.len(); + assert!(index < len, "index {} out of bounds(len: {})", index, len); + if index != self.len() - 1 { + unsafe { + let src = self.as_mut_ptr().add(index); + let dst = self.as_mut_ptr().add(len - 1); + std::ptr::swap(src, dst); + } + } + self.pop().unwrap() + } + + /// Retains only the elements specified by the predicate, passing a mutable reference to it. + /// + /// In other words, remove all elements `e` such that `f(&mut e)` returns `false`. + /// This method operates in place, visiting each element exactly once in the + /// original order, and preserves the order of the retained elements. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::array; + /// use sonic_rs::JsonValueTrait; + /// + /// let mut arr = array![1, 2, 3, 4]; + /// arr.retain_mut(|x| { + /// let v = (x.as_i64().unwrap()); + /// if v <= 3 { + /// *x = (v + 1).into(); + /// true + /// } else { + /// false + /// }}); + /// assert_eq!(arr, [2, 3, 4]); + /// ``` + #[inline] + pub fn retain_mut(&mut self, mut f: F) + where + F: FnMut(&mut Value) -> bool, + { + if self.is_empty() { + return; + } + + let mut i = 0; + let mut j = 0; + let start = self.as_mut_ptr(); + while i < self.len() { + unsafe { + let cur = start.add(i); + if !f(&mut *cur) { + (*cur).take(); + i += 1; + continue; + } + + if i > j { + std::ptr::copy_nonoverlapping(cur, start.add(j), 1); + } + i += 1; + j += 1; + } + } + + unsafe { self.set_len(j) }; + } + + /// Shortens the array, keeping the first `len` elements and dropping + /// the rest. + /// + /// If `len` is greater or equal to the array's current length, this has + /// no effect. + /// + /// The [`drain`] method can emulate `truncate`, but causes the excess + /// elements to be returned instead of dropped. + /// + /// Note that this method has no effect on the allocated capacity + /// of the array. + /// + /// # Examples + /// + /// Truncating a five element array to two elements: + /// + /// ``` + /// use sonic_rs::array; + /// let mut arr = array![1, 2, 3, true, "hi"]; + /// arr.truncate(2); + /// assert_eq!(arr, [1, 2]); + /// ``` + /// + /// No truncation occurs when `len` is greater than the array's current + /// length: + /// + /// ``` + /// use sonic_rs::array; + /// let mut arr = array![1, 2, 3]; + /// arr.truncate(8); + /// assert_eq!(arr, [1, 2, 3]); + /// ``` + /// + /// Truncating when `len == 0` is equivalent to calling the [`clear`] + /// method. + /// + /// ``` + /// use sonic_rs::array; + /// let mut arr = array![1, 2, 3]; + /// arr.truncate(0); + /// assert!(arr.is_empty()); + /// ``` + /// + /// [`clear`]: Array::clear + /// [`drain`]: Array::drain + #[inline] + pub fn truncate(&mut self, len: usize) { + let old_len = self.len(); + if len < old_len { + unsafe { + let mut v = self.as_mut_ptr().add(len); + let end = self.as_mut_ptr().add(old_len); + + while v != end { + (*v).take(); + v = v.add(1); + } + } + unsafe { self.set_len(len) }; + } + } + + /// Appends an element `val` to the back of a collection. + /// The `val` will be converted into `Value`. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` bytes. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::array; + /// let mut arr = array![1, 2]; + /// arr.push(3); + /// arr.push("hi"); + /// assert_eq!(arr, array![1, 2, 3, "hi"]); + /// ``` + #[inline] + pub fn push>(&mut self, val: T) { + self.reserve(1); + let val = { + let _ = SharedCtxGuard::assign(self.0.shared()); + val.into() + }; + self.0.append_value(val); + } + + /// Removes the last element from a array and returns it, or [`None`] if it is empty. + #[inline] + pub fn pop(&mut self) -> Option { + debug_assert!(self.0.is_array()); + self.0.pop() + } + + /// Returns the number of elements in the array. + #[inline] + pub fn len(&self) -> usize { + self.0.len() + } + + /// Returns `true` if the array contains no elements. + #[inline] + pub fn is_empty(&self) -> bool { + self.0.len() == 0 + } + + /// Extracts a mutable slice of the entire array. Equivalent to &mut s[..]. + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [Value] { + self + } + + /// Extracts a slice containing the entire array. Equivalent to &s[..]. + #[inline] + pub fn as_slice(&self) -> &[Value] { + self + } + + /// Returns the total number of elements the array can hold without reallocating. + #[inline] + pub fn capacity(&self) -> usize { + self.0.capacity() + } + + /// Clears the array, removing all values. + /// + /// Note that this method has no effect on the allocated capacity of the array. + #[inline] + pub fn clear(&mut self) { + self.0.clear(); + } + + /// Removes and returns the element at position `index` within the array, + /// + /// # Panics + /// + /// Panics if `index` is out of bounds. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::array; + /// + /// let mut arr = array![0, 1, 2]; + /// arr.remove(1); + /// assert_eq!(arr, [0, 2]); + /// ``` + #[inline] + pub fn remove(&mut self, index: usize) { + self.0.remove_index(index); + } + + /// Moves all the elements of other into self, leaving other empty. + /// + /// # Examples + /// ``` + /// use sonic_rs::{array, Value}; + /// + /// let mut arr1 = array![1]; + /// arr1.push(Value::from("arr1")); + /// + /// let mut arr2 = array![2]; + /// arr2.push(Value::from("arr2")); + /// arr2.append(&mut arr1); + /// + /// assert_eq!(arr2, array![2, "arr2", "arr1", 1]); + /// assert!(arr1.is_empty()); + /// ``` + #[inline] + pub fn append(&mut self, other: &mut Self) { + self.reserve(other.len()); + while let Some(v) = other.pop() { + debug_assert!(v.is_root() || v.is_static()); + self.push(v); + } + } + + /// Removes the specified range from the array in bulk, returning all + /// removed elements as an iterator. If the iterator is dropped before + /// being fully consumed, it drops the remaining removed elements. + /// + /// The returned iterator keeps a mutable borrow on the array to optimize + /// its implementation. + /// + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the array. + /// + /// # Leaking + /// + /// If the returned iterator goes out of scope without being dropped (due to + /// [`mem::forget`], for example), the array may have lost and leaked + /// elements arbitrarily, including elements outside the range. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{array, Value}; + /// let mut v = array![1, 2, 3]; + /// let u: Vec = v.drain(1..).collect(); + /// assert_eq!(v, &[1]); + /// assert_eq!(u, &[2, 3]); + /// + /// // A full range clears the array, like `clear()` does + /// v.drain(..); + /// assert!(v.is_empty()); + /// ``` + #[inline] + pub fn drain(&mut self, range: R) -> Drain<'_> + where + R: RangeBounds, + { + let len = self.len(); + let Range { start, end } = std::slice::range(range, ..len); + + unsafe { + // set self.arr length's to start, to be safe in case Drain is leaked + self.set_len(start); + let range_slice = std::slice::from_raw_parts(self.as_ptr().add(start), end - start); + Drain { + tail_start: end, + tail_len: len - end, + iter: range_slice.iter(), + arr: NonNull::from(self), + } + } + } + + /// Copies elements from `src` range to the end of the array. + /// + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the array. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::Array; + /// let mut arr: Array = sonic_rs::from_str("[0, 1, 2, 3, 4]").unwrap(); + /// + /// arr.extend_from_within(2..); + /// assert_eq!(arr, [0, 1, 2, 3, 4, 2, 3, 4]); + /// + /// arr.extend_from_within(..2); + /// assert_eq!(arr, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1]); + /// + /// arr.extend_from_within(4..8); + /// assert_eq!(arr, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1, 4, 2, 3, 4]); + /// ``` + pub fn extend_from_within(&mut self, src: R) + where + R: RangeBounds, + { + let range = std::slice::range(src, ..self.len()); + if range.is_empty() { + return; + } + + self.reserve(range.len()); + unsafe { + let start = self.as_mut_ptr().add(range.start); + let end = self.as_mut_ptr().add(range.end); + let src = std::slice::from_raw_parts(start, end.offset_from(start) as usize); + for v in src.iter() { + self.0.append_value(v.clone_in(self.0.shared())); + } + } + } + + /// Inserts an element at position `index` within the array, shifting all + /// elements after it to the right. + /// The `element` will be converted into `Value`. + /// + /// # Panics + /// + /// Panics if `index > len`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{array, json}; + /// + /// let mut arr = array![1, 2, 3]; + /// arr.insert(1, "inserted1"); + /// assert_eq!(arr, array![1, "inserted1", 2, 3]); + /// + /// arr.insert(4, "inserted2"); + /// assert_eq!(arr, array![1, "inserted1", 2, 3, "inserted2"]); + /// + /// arr.insert(5, json!({"a": 123})); // insert at the end + /// assert_eq!(arr, array![1, "inserted1", 2, 3, "inserted2", {"a": 123}]); + /// ``` + #[inline] + pub fn insert>(&mut self, index: usize, element: T) { + let element = { + let _ = SharedCtxGuard::assign(self.0.shared()); + element.into() + }; + self.0.insert_value(index, element); + } + + #[inline] + pub(crate) fn new_in(shared: Arc) -> Self { + let mut array = Array::default(); + array.0.mark_shared(shared.data_ptr()); + std::mem::forget(shared); + array + } + + #[inline] + pub(crate) unsafe fn set_len(&mut self, new_len: usize) { + self.0.set_len(new_len); + } +} + +impl Default for Array { + fn default() -> Self { + Self::new() + } +} + +impl Deref for Array { + type Target = [Value]; + + fn deref(&self) -> &Self::Target { + unsafe { + let start = self.0.data.achildren.add(Value::MEAT_NODE_COUNT); + let ptr = start as *const Value; + let len = self.0.len(); + from_raw_parts(ptr, len) + } + } +} + +impl DerefMut for Array { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + let ptr = self.0.data.achildren.add(Value::MEAT_NODE_COUNT); + let len = self.0.len(); + from_raw_parts_mut(ptr, len) + } + } +} + +/// A draining iterator for `Array`. +/// +/// This `struct` is created by [`Array::drain`]. +/// See its documentation for more. +/// +pub struct Drain<'a> { + pub(super) tail_start: usize, + pub(super) tail_len: usize, + // the iter of remain slice + pub(super) iter: std::slice::Iter<'a, Value>, + // origin array + pub(super) arr: NonNull, +} + +impl<'a> Drain<'a> { + #[inline] + pub fn as_slice(&self) -> &'a [Value] { + self.iter.as_slice() + } +} + +impl Iterator for Drain<'_> { + type Item = Value; + + #[inline] + fn next(&mut self) -> Option { + self.iter + .next() + .map(|v| v.clone_in(unsafe { self.arr.as_ref().0.shared() })) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +use std::ops::Index; +use std::ops::IndexMut; +use std::slice::SliceIndex; + +impl> Index for Array { + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { + Index::index(&**self, index) + } +} + +impl> IndexMut for Array { + fn index_mut(&mut self, index: I) -> &mut Self::Output { + IndexMut::index_mut(&mut **self, index) + } +} + +////////////////////////////////////////////////////////////////////////////// + +#[derive(Debug, Default, Clone)] +pub struct IntoIter { + array: Array, + index: usize, + len: usize, +} + +impl IntoIter { + pub fn as_mut_slice(&mut self) -> &mut [Value] { + unsafe { + let ptr = self.array.0.children_mut_ptr(); + let len = self.array.0.len(); + from_raw_parts_mut(ptr, len) + } + } + + pub fn as_slice(&self) -> &[Value] { + unsafe { + let ptr = self.array.0.children_ptr(); + let len = self.array.0.len(); + from_raw_parts(ptr, len) + } + } +} + +impl AsRef<[Value]> for IntoIter { + fn as_ref(&self) -> &[Value] { + self.as_slice() + } +} + +impl AsMut<[Value]> for IntoIter { + fn as_mut(&mut self) -> &mut [Value] { + self.as_mut_slice() + } +} + +impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + if self.index < self.len { + self.len -= 1; + let value = self.array.0.get_index_mut(self.len).unwrap(); + Some(value.take()) + } else { + None + } + } +} + +impl ExactSizeIterator for IntoIter { + #[inline] + fn len(&self) -> usize { + self.len - self.index + } +} + +impl FusedIterator for IntoIter {} + +impl Iterator for IntoIter { + type Item = Value; + + #[inline] + fn next(&mut self) -> Option { + if self.index < self.len { + let value = self.array.0.get_index_mut(self.index).unwrap(); + self.index += 1; + Some(value.take()) + } else { + None + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = self.len - self.index; + (len, Some(len)) + } +} + +impl IntoIterator for Array { + type Item = Value; + type IntoIter = IntoIter; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + let len = self.len(); + IntoIter { + array: self, + index: 0, + len, + } + } +} + +impl<'a> IntoIterator for &'a Array { + type Item = &'a Value; + type IntoIter = std::slice::Iter<'a, Value>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a> IntoIterator for &'a mut Array { + type Item = &'a mut Value; + type IntoIter = std::slice::IterMut<'a, Value>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +////////////////////////////////////////////////////////////////////////////// + +impl serde::ser::Serialize for Array { + #[inline] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::ser::Serializer, + { + use serde::ser::SerializeSeq; + let mut seq = tri!(serializer.serialize_seq(Some(self.len()))); + for v in self { + tri!(seq.serialize_element(v)); + } + seq.end() + } +} + +impl<'de> serde::de::Deserialize<'de> for Array { + #[inline] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::de::Deserializer<'de>, + { + // deserialize to value at first + let value: Value = + deserializer.deserialize_newtype_struct(super::de::TOKEN, super::de::ValueVisitor)?; + if value.is_array() { + Ok(Array(value)) + } else { + Err(serde::de::Error::invalid_type( + serde::de::Unexpected::Other("not a array"), + &"array", + )) + } + } +} + +#[cfg(test)] +mod test { + use super::Array; + use crate::value::node::Value; + use crate::value::value_trait::JsonValueMutTrait; + + #[test] + fn test_value_array() { + let mut val = crate::from_str::(r#"[1,2,3]"#); + let array = val.as_array_mut().unwrap(); + assert_eq!(array.len(), 3); + + for i in 0..3 { + // push static node + let old_len = array.len(); + let new_node = Value::new_u64(i, std::ptr::null()); + array.push(new_node); + assert_eq!(array.len(), old_len + 1); + + // push node with new allocator + let old_len = array.len(); + let mut new_node = Array::default(); + new_node.push(Value::new_u64(i, std::ptr::null())); + dbg!(&new_node.0); + array.push(new_node.0); + assert_eq!(array.len(), old_len + 1); + + // push node with self allocator + let old_len = array.len(); + let mut new_node = Array::new_in(array.0.shared_clone()); + new_node.push(Value::new_u64(i, std::ptr::null())); + dbg!(&new_node.0); + array.push(new_node.0); + assert_eq!(array.len(), old_len + 1); + } + + dbg!(&array); + for (i, v) in array.iter_mut().enumerate() { + *v = Value::new_u64(i as u64, std::ptr::null()); + } + + while !array.is_empty() { + dbg!(array.pop()); + } + } +} diff --git a/src/value/de.rs b/src/value/de.rs new file mode 100644 index 0000000..bd49eb9 --- /dev/null +++ b/src/value/de.rs @@ -0,0 +1,734 @@ +use super::node::ValueRef; +use crate::error::{Error, ErrorCode}; +use crate::reader::Reader; +use crate::serde::number::N; +use crate::serde::tri; +use crate::value::node::Value; +use crate::value::Object; +use serde::de::Visitor; +use serde::de::{ + self, Deserialize, DeserializeSeed, EnumAccess, Expected, IntoDeserializer, MapAccess, + SeqAccess, Unexpected, VariantAccess, +}; +use serde::forward_to_deserialize_any; +use std::mem::MaybeUninit; +use std::result::Result as StdResult; +use std::slice; + +/// Interpret a `sonic_rs::Value` as an instance of type `T`. +/// +/// # Example +/// +/// ``` +/// use serde::Deserialize; +/// use sonic_rs::json; +/// +/// #[derive(Deserialize, Debug)] +/// struct User { +/// string: String, +/// number: i32, +/// array: Vec, +/// } +/// +/// // The type of `j` is `sonic_rs::Value` +/// let j = json!({ +/// "string": "hello", +/// "number": 123, +/// "array": ["a", "b", "c"], +/// }); +/// let u: User = sonic_rs::from_value(&j).unwrap(); +/// assert_eq!(u.string, "hello"); +/// assert_eq!(u.number, 123); +/// assert_eq!(u.array, vec!["a", "b", "c"]); +/// ``` +/// +/// # Errors +/// +/// This conversion can fail if the structure of the Value does not match the +/// structure expected by `T`, for example if `T` is a struct type but the Value +/// contains something other than a JSON map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the JSON map or some number is too big to fit in the expected primitive +/// type. +/// +/// +pub fn from_value<'de, T>(value: &'de Value) -> Result +where + T: Deserialize<'de>, +{ + T::deserialize(value) +} + +impl<'de> Deserialize<'de> for Value { + /// Deserialize this value from a `Deserializer`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::Value; + /// + /// let v: Value = sonic_rs::from_str(r#"{"a": 1, "b": 2}"#).unwrap(); + /// assert_eq!(v["a"], 1); + /// assert_eq!(v["b"], 2); + /// ``` + /// + fn deserialize(deserializer: D) -> StdResult + where + D: ::serde::Deserializer<'de>, + { + deserializer.deserialize_newtype_struct(TOKEN, ValueVisitor) + } +} + +pub(crate) const TOKEN: &str = "$sonic_rs::private::Value"; + +pub(crate) struct ValueVisitor; + +impl<'de> Visitor<'de> for ValueVisitor { + type Value = Value; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("a valid json") + } + + fn visit_bytes(self, value_binary: &[u8]) -> StdResult + where + E: de::Error, + { + // we pass the value from value_binary + unsafe { + assert!( + value_binary.len() == std::mem::size_of::(), + "invalid value size {}", + value_binary.len() + ); + let mut dom: MaybeUninit = MaybeUninit::zeroed(); + std::ptr::copy_nonoverlapping( + value_binary.as_ptr() as *const Value, + dom.as_mut_ptr(), + 1, + ); + Ok(dom.assume_init()) + } + } +} + +struct SeqRefDeserializer<'de> { + iter: slice::Iter<'de, Value>, +} + +impl<'de> SeqRefDeserializer<'de> { + fn new(slice: &'de [Value]) -> Self { + SeqRefDeserializer { iter: slice.iter() } + } +} + +impl<'de> SeqAccess<'de> for SeqRefDeserializer<'de> { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result, Error> + where + T: DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => seed.deserialize(value).map(Some), + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +struct MapRefDeserializer<'de> { + iter: <&'de Object as IntoIterator>::IntoIter, + value: Option<&'de Value>, +} + +impl<'de> MapRefDeserializer<'de> { + fn new(map: &'de Object) -> Self { + MapRefDeserializer { + iter: map.into_iter(), + value: None, + } + } +} + +impl<'de> MapAccess<'de> for MapRefDeserializer<'de> { + type Error = Error; + + fn next_key_seed(&mut self, seed: T) -> Result, Error> + where + T: DeserializeSeed<'de>, + { + match self.iter.next() { + Some((key, value)) => { + self.value = Some(value); + let key_de = MapKeyDeserializer { key }; + seed.deserialize(key_de).map(Some) + } + None => Ok(None), + } + } + + fn next_value_seed(&mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.value.take() { + Some(value) => seed.deserialize(value), + None => Err(serde::de::Error::custom("value is missing")), + } + } + + fn size_hint(&self) -> Option { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +struct MapKeyDeserializer<'de> { + key: &'de str, +} + +macro_rules! deserialize_numeric_key { + ($method:ident) => { + deserialize_numeric_key!($method, deserialize_number); + }; + + ($method:ident, $using:ident) => { + fn $method(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let mut de = + crate::Deserializer::new(crate::reader::SliceRead::new(self.key.as_bytes())); + match de.parser.read.peek() { + Some(b'0'..=b'9' | b'-') => {} + _ => return Err(Error::syntax(ErrorCode::ExpectedNumericKey, b"", 0)), + } + let number = tri!(de.$using(visitor)); + Ok(number) + } + }; +} + +impl<'de> serde::Deserializer<'de> for MapKeyDeserializer<'de> { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_borrowed_str(self.key) + } + + deserialize_numeric_key!(deserialize_i8); + deserialize_numeric_key!(deserialize_i16); + deserialize_numeric_key!(deserialize_i32); + deserialize_numeric_key!(deserialize_i64); + deserialize_numeric_key!(deserialize_u8); + deserialize_numeric_key!(deserialize_u16); + deserialize_numeric_key!(deserialize_u32); + deserialize_numeric_key!(deserialize_u64); + // TODO: impl parsing f32 + deserialize_numeric_key!(deserialize_f32); + deserialize_numeric_key!(deserialize_f64); + deserialize_numeric_key!(deserialize_i128, deserialize_i128); + deserialize_numeric_key!(deserialize_u128, deserialize_u128); + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + if self.key == "true" { + visitor.visit_bool(true) + } else if self.key == "false" { + visitor.visit_bool(false) + } else { + Err(serde::de::Error::invalid_type( + Unexpected::Str(self.key), + &visitor, + )) + } + } + + #[inline] + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + // Map keys cannot be null. + visitor.visit_some(self) + } + + #[inline] + fn deserialize_newtype_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.key + .into_deserializer() + .deserialize_enum(name, variants, visitor) + } + + forward_to_deserialize_any! { + char str string bytes byte_buf unit unit_struct seq tuple tuple_struct + map struct identifier ignored_any + } +} + +fn visit_array_ref<'de, V>(array: &'de [Value], visitor: V) -> Result +where + V: Visitor<'de>, +{ + let len = array.len(); + let mut deserializer = SeqRefDeserializer::new(array); + let seq = tri!(visitor.visit_seq(&mut deserializer)); + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(seq) + } else { + Err(serde::de::Error::invalid_length( + len, + &"fewer elements in array", + )) + } +} + +fn visit_object_ref<'de, V>(object: &'de Object, visitor: V) -> Result +where + V: Visitor<'de>, +{ + let len = object.len(); + let mut deserializer = MapRefDeserializer::new(object); + let map = tri!(visitor.visit_map(&mut deserializer)); + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(map) + } else { + Err(serde::de::Error::invalid_length( + len, + &"fewer elements in map", + )) + } +} + +macro_rules! deserialize_number { + ($method:ident) => { + fn $method(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.as_ref() { + ValueRef::Number(n) => n.deserialize_any(visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + }; +} + +impl Value { + #[cold] + fn invalid_type(&self, exp: &dyn Expected) -> E + where + E: serde::de::Error, + { + serde::de::Error::invalid_type(self.unexpected(), exp) + } + + #[cold] + fn unexpected(&self) -> Unexpected<'_> { + self.as_ref().unexpected() + } +} + +impl<'a> ValueRef<'a> { + #[cold] + fn unexpected(&self) -> Unexpected<'a> { + match self { + ValueRef::Null => Unexpected::Unit, + ValueRef::Bool(b) => Unexpected::Bool(*b), + ValueRef::Number(n) => match n.n { + N::PosInt(u) => Unexpected::Unsigned(u), + N::NegInt(i) => Unexpected::Signed(i), + N::Float(f) => Unexpected::Float(f), + }, + ValueRef::String(s) => Unexpected::Str(s), + ValueRef::Array(_) => Unexpected::Seq, + ValueRef::Object(_) => Unexpected::Map, + } + } +} + +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(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )), + } + } + + fn tuple_variant(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.value.map(|v| v.as_ref()) { + Some(ValueRef::Array(v)) => { + if v.is_empty() { + visitor.visit_unit() + } else { + visit_array_ref(v, visitor) + } + } + Some(other) => Err(serde::de::Error::invalid_type( + other.unexpected(), + &"tuple variant", + )), + None => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )), + } + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self.value.map(|v| v.as_ref()) { + Some(ValueRef::Object(v)) => visit_object_ref(v, visitor), + Some(other) => Err(serde::de::Error::invalid_type( + other.unexpected(), + &"struct variant", + )), + None => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )), + } + } +} + +impl<'de> IntoDeserializer<'de, Error> for &'de Value { + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +impl<'de> serde::Deserializer<'de> for &'de Value { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.as_ref() { + ValueRef::Null => visitor.visit_unit(), + ValueRef::Bool(v) => visitor.visit_bool(v), + ValueRef::Number(n) => n.deserialize_any(visitor), + ValueRef::String(v) => visitor.visit_borrowed_str(v), + ValueRef::Array(v) => visit_array_ref(v, visitor), + ValueRef::Object(v) => visit_object_ref(v, visitor), + } + } + + deserialize_number!(deserialize_i8); + deserialize_number!(deserialize_i16); + deserialize_number!(deserialize_i32); + deserialize_number!(deserialize_i64); + deserialize_number!(deserialize_i128); + deserialize_number!(deserialize_u8); + deserialize_number!(deserialize_u16); + deserialize_number!(deserialize_u32); + deserialize_number!(deserialize_u64); + deserialize_number!(deserialize_u128); + deserialize_number!(deserialize_f32); + deserialize_number!(deserialize_f64); + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.as_ref() { + ValueRef::Null => visitor.visit_none(), + _ => visitor.visit_some(self), + } + } + + fn deserialize_enum( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let (variant, value) = match self.as_ref() { + ValueRef::Object(value) => { + let mut iter = value.into_iter(); + let (variant, value) = match iter.next() { + Some(v) => v, + None => { + return Err(serde::de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )); + } + }; + // enums are encoded in json as maps with a single key:value pair + if iter.next().is_some() { + return Err(serde::de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )); + } + (variant, Some(value)) + } + ValueRef::String(variant) => (variant, None), + other => { + return Err(serde::de::Error::invalid_type( + other.unexpected(), + &"string or map", + )); + } + }; + + visitor.visit_enum(EnumRefDeserializer { variant, value }) + } + + #[inline] + fn deserialize_newtype_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + // deserialize value into RawValue + if name == crate::serde::raw::TOKEN { + return visitor.visit_map(crate::serde::raw::OwnedRawDeserializer { + raw_value: Some(self.to_string()), + }); + } + + let _ = name; + visitor.visit_newtype_struct(self) + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.as_ref() { + ValueRef::Bool(v) => visitor.visit_bool(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.as_ref() { + ValueRef::String(v) => visitor.visit_borrowed_str(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.as_ref() { + ValueRef::String(v) => visitor.visit_borrowed_str(v), + ValueRef::Array(v) => visit_array_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_bytes(visitor) + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.as_ref() { + ValueRef::Null => visitor.visit_unit(), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_unit(visitor) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.as_ref() { + ValueRef::Array(v) => visit_array_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_tuple(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.as_ref() { + ValueRef::Object(v) => visit_object_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self.as_ref() { + ValueRef::Array(v) => visit_array_ref(v, visitor), + ValueRef::Object(v) => visit_object_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_unit() + } +} + +#[cfg(test)] +mod test { + + #[test] + fn test_value_as_deserializer() { + // unimplemented!() + } +} diff --git a/src/value/from.rs b/src/value/from.rs new file mode 100644 index 0000000..612c3c6 --- /dev/null +++ b/src/value/from.rs @@ -0,0 +1,742 @@ +use super::array::{Array, DEFAULT_ARRAY_CAP}; +use super::object::Object; +use crate::serde::number::N; +use crate::util::arc::Arc; +use crate::value::node::Value; +use crate::value::object::DEFAULT_OBJ_CAP; +use crate::value::shared::Shared; +use crate::Number; +use faststr::FastStr; +use std::borrow::Cow; +use std::cell::UnsafeCell; +use std::convert::Into; +use std::fmt::Debug; +use std::mem::ManuallyDrop; +use std::str::FromStr; + +impl From for Value { + /// Convert `Number` to a `Value`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{Number, Value, json}; + /// + /// let x = Value::from(Number::from(7)); + /// assert_eq!(x, json!(7)); + /// ``` + #[inline] + fn from(val: Number) -> Self { + let shared = get_shared(); + match val.n { + N::PosInt(u) => Value::new_u64(u, shared), + N::NegInt(i) => Value::new_i64(i, shared), + N::Float(f) => unsafe { Value::new_f64_unchecked(f, shared) }, + } + } +} + +macro_rules! impl_from_integer { + ($($ty:ident),*) => { + $( + impl From<$ty> for Value { + fn from(val: $ty) -> Self { + Into::::into(val).into() + } + } + )* + }; + () => {}; +} + +impl_from_integer!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize); + +impl From for Value { + /// Convert `bool` to a boolean `Value`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::Value; + /// use sonic_rs::JsonValueTrait; + /// + /// let x: Value = true.into(); + /// assert!(x.is_true()); + /// ``` + #[inline] + fn from(val: bool) -> Self { + Value::new_bool(val, get_shared()) + } +} + +macro_rules! impl_from_str { + () => {}; + ($($ty:ident),*) => { + $( + impl From<&$ty> for Value { + /// Convert a string type into a string `Value`. The string will be copied into the `Value`. + /// + /// # Performance + /// + /// If it is `&'static str`, recommend to use [`Value::from_static_str`] and it is zero-copy. + /// + #[inline] + fn from(val: &$ty) -> Self { + let (shared, is_root) = get_shared_or_new(); + let mut value = Value::copy_str(val, shared); + if is_root { + value.mark_root(); + } + value + } + } + )* + }; +} + +impl_from_str!(String, str, FastStr); + +impl<'a> From> for Value { + /// Convert copy-on-write string to a string `Value`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::Value; + /// use std::borrow::Cow; + /// + /// let s1: Cow = Cow::Borrowed("hello"); + /// let x1 = Value::from(s1); + /// + /// let s2: Cow = Cow::Owned("hello".to_string()); + /// let x2 = Value::from(s2); + /// + /// assert_eq!(x1, x2); + /// ``` + #[inline] + fn from(value: Cow<'a, str>) -> Self { + Into::::into(value.as_ref()) + } +} + +impl From for Value { + /// Convert `char` to a string `Value`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{Value, json}; + /// + /// let c: char = '😁'; + /// let x: Value = c.into(); + /// assert_eq!(x, json!("😁")); + /// ``` + #[inline] + fn from(val: char) -> Self { + Into::::into(&val.to_string()) + } +} + +impl> From> for Value { + /// Convert a `Vec` to a `Value`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{Value, json}; + /// + /// assert_eq!(Value::from(vec!["hi", "hello"]), json!(["hi", "hello"])); + /// + /// assert_eq!(Value::from(Vec::::new()), json!([])); + /// + /// assert_eq!(Value::from(vec![json!(null), json!("hi")]), json!([null, "hi"])); + /// + /// ``` + #[inline] + fn from(val: Vec) -> Self { + let shared = get_shared(); + let is_root = shared.is_null(); + if val.is_empty() { + return Value::new_array(shared, 0); + } + + let mut array = if is_root { + let new_shared = Shared::new_ptr(); + set_shared(new_shared); + Value::new_array(new_shared, val.len()) + } else { + Value::new_array(shared, val.len()) + }; + + for v in val { + // new create value will use the shared allocator. + array.append_value(Into::::into(v)); + } + if is_root { + set_shared(std::ptr::null()); + array.mark_root(); + } + array + } +} + +impl, const N: usize> From<&[T; N]> for Value { + /// Convert a array reference `&[T; N]` to a `Value`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{Value, json}; + /// + /// let x = Value::from(&["hi", "hello"]); + /// + /// assert_eq!(x, json!(["hi", "hello"])); + /// + #[inline] + fn from(val: &[T; N]) -> Self { + Into::::into(val.as_ref()) + } +} + +impl> From<&[T]> for Value { + /// Convert a slice `&[T]` to a `Value`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{Value, json}; + /// + /// let x = Value::from(&["hi", "hello"][..]); + /// + /// assert_eq!(x, json!(["hi", "hello"])); + /// + /// let x: &[i32] = &[]; + /// assert_eq!(Value::from(x), json!([])); + /// ``` + fn from(val: &[T]) -> Self { + let shared = get_shared(); + let is_root = shared.is_null(); + if val.is_empty() { + return Value::new_array(shared, 0); + } + + let mut array = if is_root { + let new_shared = Shared::new_ptr(); + set_shared(new_shared); + Value::new_array(new_shared, val.len()) + } else { + Value::new_array(shared, val.len()) + }; + for v in val { + // new create value will use the shared allocator. + array.append_value(Into::::into(v.clone())); + } + + if is_root { + array.mark_root(); + set_shared(std::ptr::null()); + } + array + } +} + +impl From<()> for Value { + /// Convert `()` to `Value::Null`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::Value; + /// use sonic_rs::JsonValueTrait; + /// + /// assert!(Value::from(()).is_null()); + /// + /// ``` + #[inline] + fn from(_: ()) -> Self { + let shared = get_shared(); + Value::new_null(shared) + } +} + +impl From> for Value +where + T: Into, +{ + /// Convert `Option` to `Value::Null`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::Value; + /// use sonic_rs::JsonValueTrait; + /// + /// let u = Some(123); + /// let x = Value::from(u); + /// assert_eq!(x.as_i64(), u); + /// + /// let u = None; + /// let x: Value = u.into(); + /// assert_eq!(x.as_i64(), u); + /// ``` + #[inline] + fn from(opt: Option) -> Self { + match opt { + None => Into::into(()), + Some(value) => Into::into(value), + } + } +} + +impl FromStr for Value { + type Err = crate::Error; + /// Convert `&str` to `Value`. The `&str` will be copied into the `Value`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::Value; + /// use sonic_rs::JsonValueTrait; + /// use std::str::FromStr; + /// + /// let x = Value::from_str("string").unwrap(); + /// assert_eq!(x.as_str().unwrap(), "string"); + /// ``` + /// # Performance + /// + /// If it is `&'static str`, recommend to use [`Value::from_static_str`]. + /// + fn from_str(s: &str) -> Result { + Ok(Value::new_str_owned(s)) + } +} + +impl<'a, K: AsRef, V: Clone + Into> FromIterator<(K, &'a V)> for Value { + /// Create a `Value` by collecting an iterator of key-value pairs. + /// The key will be copied into the `Value`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{Value, json, object}; + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("sonic_rs", 40); + /// map.insert("json", 2); + /// + /// let x: Value = map.iter().collect(); + /// assert_eq!(x, json!({"sonic_rs": 40, "json": 2})); + /// + /// let x: Value = Value::from_iter(&object!{"sonic_rs": 40, "json": 2}); + /// assert_eq!(x, json!({"sonic_rs": 40, "json": 2})); + /// ``` + /// + fn from_iter>(iter: T) -> Self { + let (shared, is_root) = get_shared_or_new(); + if is_root { + set_shared(shared); + } + + let mut obj = Value::new_object(shared, DEFAULT_OBJ_CAP); + for (k, v) in iter.into_iter() { + let k = Value::copy_str(k.as_ref(), shared); + // will create value use `shared` allocator + let v = v.clone().into(); + obj.append_pair((k, v)); + } + + if is_root { + obj.mark_root(); + set_shared(std::ptr::null()); + } + obj + } +} + +impl> FromIterator for Value { + /// Create a `Value` by collecting an iterator of array elements. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{Value, json}; + /// use std::iter::FromIterator; + /// + /// let v = std::iter::repeat(6).take(3); + /// let x: Value = v.collect(); + /// assert_eq!(x, json!([6, 6, 6])); + /// + /// let x = Value::from_iter(vec!["sonic_rs", "json", "serde"]); + /// assert_eq!(x, json!(["sonic_rs", "json", "serde"])); + /// ``` + /// + #[inline] + fn from_iter>(iter: I) -> Self { + let (shared, is_root) = get_shared_or_new(); + if is_root { + set_shared(shared); + } + + let mut arr = Value::new_array(shared, DEFAULT_ARRAY_CAP); + for v in iter.into_iter() { + // will create value use `shared` allocator + arr.append_value(v.into()); + } + + if is_root { + arr.mark_root(); + set_shared(std::ptr::null()); + } + arr + } +} + +////////////////////////////////////////////////////////////////////////////// + +impl> From> for Array { + /// Convert a `Vec` to a `Array`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::value::Array; + /// use sonic_rs::array; + /// + /// let v = vec!["hi", "hello"]; + /// let x: Array = v.into(); + /// assert_eq!(x, array!["hi", "hello"]); + /// ``` + #[inline] + fn from(val: Vec) -> Self { + debug_assert!(get_shared().is_null(), "array should not be shared"); + let value = Into::::into(val); + Array(value) + } +} + +impl, const N: usize> From<&[T; N]> for Array { + /// Convert a array `&[T; N]` to a `Array`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{Array, array}; + /// + /// let v = &["hi", "hello"]; + /// let x: Array = v.into(); + /// assert_eq!(x, array!["hi", "hello"]); + /// ``` + /// + fn from(val: &[T; N]) -> Self { + debug_assert!(get_shared().is_null(), "array should not be shared"); + let value = Into::::into(val.as_ref()); + Array(value) + } +} + +impl> FromIterator for Array { + /// Create a `Array` by collecting an iterator of array elements. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{Array, json, array}; + /// use std::iter::FromIterator; + /// + /// let v = std::iter::repeat(6).take(3); + /// let x: Array = v.collect(); + /// assert_eq!(x, json!([6, 6, 6])); + /// + /// let x = Array::from_iter(vec!["sonic_rs", "json", "serde"]); + /// assert_eq!(x, array!["sonic_rs", "json", "serde"]); + /// ``` + /// + fn from_iter>(iter: I) -> Self { + debug_assert!(get_shared().is_null(), "array should not be shared"); + let value = Value::from_iter(iter); + Array(value) + } +} + +impl> From<&[T]> for Array { + /// Convert a slice `&[T]` to a `Array`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::value::Array; + /// use sonic_rs::array; + /// + /// let v = &["hi", "hello"]; + /// let x: Array = v.into(); + /// assert_eq!(x, array!["hi", "hello"]); + /// ``` + /// + fn from(val: &[T]) -> Self { + debug_assert!(get_shared().is_null(), "array should not be shared"); + let value = Into::::into(val); + Array(value) + } +} + +////////////////////////////////////////////////////////////////////////////// + +impl<'a, K: AsRef, V: Clone + Into + 'a> FromIterator<(K, &'a V)> for Object { + /// Create a `Object` by collecting an iterator of key-value pairs. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{Value, object, Object}; + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("sonic_rs", 40); + /// map.insert("json", 2); + /// + /// let x: Object = map.iter().collect(); + /// assert_eq!(x, object!{"sonic_rs": 40, "json": 2}); + /// + /// let x = Object::from_iter(&object!{"sonic_rs": 40, "json": 2}); + /// assert_eq!(x, object!{"sonic_rs": 40, "json": 2}); + /// ``` + /// + #[inline] + fn from_iter>(iter: T) -> Self { + debug_assert!(get_shared().is_null(), "object should not be shared"); + let value = Value::from_iter(iter); + Object(value) + } +} + +impl<'a, T: Clone + Into + 'a> Extend<&'a T> for Array { + /// Extend a `Array` with the contents of an iterator. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{Array, array, json}; + /// let mut arr = array![]; + /// + /// // array extend from a slice &[i32] + /// arr.extend(&[1, 2, 3]); + /// assert_eq!(arr, array![1, 2, 3]); + /// + /// arr.extend(&Array::default()); + /// assert_eq!(arr, array![1, 2, 3]); + /// + /// // array extend from other array + /// arr.extend(&array![4, 5, 6]); + /// assert_eq!(arr, array![1, 2, 3, 4, 5, 6]); + /// + /// ``` + /// + #[inline] + fn extend>(&mut self, iter: I) { + debug_assert!( + get_shared().is_null(), + "array extend should not use outer shared allocator" + ); + let shared = self.0.check_shared(); + set_shared(shared); + for v in iter { + // new create value will use `shared` allocator + self.push(v.clone().into()); + } + set_shared(std::ptr::null()); + } +} + +impl<'a, K: AsRef + ?Sized, V: Clone + Debug + Into + 'a> Extend<(&'a K, &'a V)> + for Object +{ + /// Extend a `Object` with the contents of an iterator. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{Object, object, json, Value}; + /// use std::collections::HashMap; + /// + /// let mut obj = object![]; + /// let mut map: HashMap<&str, Value> ={ + /// let mut map = HashMap::new(); + /// map.insert("sonic", json!(40)); + /// map.insert("rs", json!(null)); + /// map + /// }; + /// + /// obj.extend(&map); + /// assert_eq!(obj, object!{"sonic": 40, "rs": null}); + /// + /// obj.extend(&object!{"object": [1, 2, 3]}); + /// assert_eq!(obj, object!{"sonic": 40, "rs": null, "object": [1, 2, 3]}); + /// + /// ``` + /// + fn extend>(&mut self, iter: I) { + debug_assert!( + get_shared().is_null(), + "object extend should not use outer shared allocator" + ); + let shared = self.0.check_shared() as *const _; + set_shared(shared); + for (k, v) in iter { + let k = Value::copy_str(k.as_ref(), self.0.shared()); + // new create value will use `shared` allocator + let mut v = v.clone().into(); + v.unmark_root(); + self.0.append_pair((k, v)); + } + set_shared(std::ptr::null()); + } +} + +impl From for Value { + #[inline] + fn from(val: Array) -> Self { + val.0 + } +} + +impl From for Value { + #[inline] + fn from(val: Object) -> Self { + val.0 + } +} + +////////////////////////////////////////////////////////////////////////////// + +// We use a thread local to make the allocator can be used in whole `From` trait. +thread_local! { + static SHARED: UnsafeCell<*const Shared> = const { UnsafeCell::new(std::ptr::null()) }; +} + +pub(crate) fn get_shared() -> *const Shared { + SHARED.with(|shared| unsafe { *shared.get() }) +} + +pub(crate) fn get_shared_or_new() -> (&'static Shared, bool) { + let shared = SHARED.with(|shared| unsafe { *shared.get() }); + if shared.is_null() { + let arc = ManuallyDrop::new(Arc::new(Shared::new())); + (unsafe { &*arc.data_ptr() }, true) + } else { + (unsafe { &*shared }, false) + } +} + +pub(crate) fn set_shared(new_shared: *const Shared) { + SHARED.with(|shared| unsafe { *((*shared).get()) = new_shared }); +} + +pub(crate) struct SharedCtxGuard { + old: *const Shared, +} + +impl SharedCtxGuard { + /// assign `new_shared` into SharedCtx + pub(crate) fn assign(new_shared: *const Shared) -> Self { + let old = get_shared(); + set_shared(new_shared); + Self { old } + } +} + +impl Drop for SharedCtxGuard { + fn drop(&mut self) { + set_shared(self.old); + } +} + +pub(crate) struct CheckCtxGuard { + is_root: bool, +} + +impl CheckCtxGuard { + /// assign `new_shared` into SharedCtx + pub(crate) fn new() -> Self { + let old = get_shared(); + if old.is_null() { + set_shared(Shared::new_ptr()); + Self { is_root: true } + } else { + Self { is_root: false } + } + } +} + +impl Drop for CheckCtxGuard { + fn drop(&mut self) { + if self.is_root { + set_shared(std::ptr::null()); + } + } +} +#[cfg(test)] +mod test { + + use crate::array; + use crate::json; + use crate::object; + use crate::value::node::Value; + use std::collections::HashMap; + + #[test] + fn test_from() { + let a1 = json!([1, 2, 3]); + let a2: Value = vec![1, 2, 3].into(); + assert_eq!(a1, a2); + let v = Value::from(vec![json!("hi")]); + dbg!(&v); + assert_eq!(v, json!(["hi"])); + } + + #[test] + fn test_extend_array() { + let mut a1 = array![1, 2, 3]; + let mut b1 = a1.clone(); + + let a2 = vec![4, 5, 6]; + let a3 = array![4, 5, 6]; + a1.extend(&a2); + b1.extend(&a3); + assert_eq!(a1, b1); + } + + #[test] + fn test_extend_object() { + let mut obj = object![]; + let mut map: HashMap<&str, Value> = HashMap::new(); + + map.insert("sonic_rs", json!(40)); + map.insert("json", "hi".into()); + obj.extend(map.iter()); + } + + #[test] + fn test_from_iter() { + use crate::{json, Value}; + use std::collections::HashMap; + use std::iter::FromIterator; + + let mut map = HashMap::new(); + map.insert("sonic_rs", 40); + map.insert("json", 2); + + let x: Value = map.iter().collect(); + assert_eq!(x, json!({"sonic_rs": 40, "json": 2})); + + let v = std::iter::repeat(6).take(3); + let x1: Vec<_> = v.collect(); + dbg!(x1); + let v = std::iter::repeat(6).take(3); + let x: Value = v.collect(); + assert_eq!(x, json!([6, 6, 6])); + + let x = Value::from_iter(vec!["sonic_rs", "json", "serde"]); + assert_eq!(x, json!(["sonic_rs", "json", "serde"])); + } +} diff --git a/src/value/index.rs b/src/value/index.rs index dde3fe5..09c0bdf 100644 --- a/src/value/index.rs +++ b/src/value/index.rs @@ -1,83 +1,240 @@ -use crate::{lazyvalue::LazyValue, value::Value}; -use core::ops; +use super::{node::Value, value_trait::JsonValueMutTrait}; +use crate::lazyvalue::LazyValue; +use crate::util::private::Sealed; +use crate::util::reborrow::DormantMutRef; +use crate::value::from::SharedCtxGuard; +use crate::value::object::DEFAULT_OBJ_CAP; +use crate::value::shared::Shared; +use crate::value::value_trait::JsonValueTrait; +use std::convert::Into; -pub trait Index: private::Sealed { +impl std::ops::Index for Value +where + I: Index, +{ + type Output = Value; + + /// Index into an array `Value` using the syntax `value[0]` and index into an + /// object `Value` using the syntax `value["k"]`. + /// + /// Returns a null `Value` if the `Value` type does not match the index, or the + /// index does not exist in the array or object. + /// + /// For retrieving deeply nested values, you should have a look at the `Value::pointer` method. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{json, pointer, JsonValueTrait}; + /// + /// let data = json!({ + /// "x": { + /// "y": ["z", "zz"] + /// } + /// }); + /// + /// assert_eq!(data["x"]["y"], json!(["z", "zz"])); + /// assert_eq!(data["x"]["y"][0], json!("z")); + /// + /// assert_eq!(data["a"], json!(null)); // returns null for undefined values + /// assert_eq!(data["a"]["b"], json!(null)); // does not panic + /// + /// // use pointer for retrieving nested values + /// assert_eq!(data.pointer(&pointer!["x", "y", 0]).unwrap(), &json!("z")); + /// ``` + + #[inline] + fn index(&self, index: I) -> &Value { + static NULL: Value = Value::new(); + index.value_index_into(self).unwrap_or(&NULL) + } +} + +impl std::ops::IndexMut for Value { + /// Write the index of a mutable `Value`, and use the syntax `value[0] = ...` + /// in an array and `value["k"] = ...` in an object. + /// + /// If the index is a number, the value must be an array of length bigger + /// than the index. Indexing into a value that is not an array or an array + /// that is too small will panic. + /// + /// If the index is a string, the value must be an object or null which is + /// treated like an empty object. If the key is not already present in the + /// object, it will be inserted with a value of null. Indexing into a value + /// that is neither an object nor null will panic. + /// + /// # Examples + /// + /// ``` + /// # use sonic_rs::json; + /// # + /// let mut data = json!({ "x": 0, "z": null }); + /// + /// // replace an existing key + /// data["x"] = json!(1); + /// + /// // insert a new key + /// data["y"] = json!([1, 2, 3]); + /// + /// // replace an array value + /// data["y"][0] = json!(true); + /// + /// // inserted a deeply nested key + /// data["a"]["b"]["c"]["d"] = json!(true); + /// + /// //insert an key in a null value + /// data["z"]["zz"] = json!("insert in null"); + /// + /// assert_eq!(data, json!({ + /// "x": 1, + /// "y": [true, 2, 3], + /// "a": { "b": {"c": {"d": true}}}, + /// "z": {"zz": "insert in null"} + /// })); + /// + /// ``` + #[inline] + fn index_mut(&mut self, index: I) -> &mut Value { + index.index_or_insert(self) + } +} + +/// An indexing trait for immutable `sonic_rs::Value`. +/// +pub trait Index: Sealed { /// Return None if the index is not already in the array or object. #[doc(hidden)] - fn value_index_into<'dom, 'v>(self, v: &'v Value<'dom>) -> Option<&'v Value<'dom>>; + fn value_index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>; /// Return None if the index is not already in the array or object lazy_value. #[doc(hidden)] - fn lazyvalue_index_into<'de>(self, v: &'de LazyValue<'de>) -> Option>; + fn lazyvalue_index_into<'de>(&self, v: &'de LazyValue<'de>) -> Option>; } -pub trait IndexMut: private::Sealed { +/// An indexing trait for a mutable `sonic_rs::Value`. +/// +pub trait IndexMut: Sealed { /// Return None if the key is not already in the array or object. #[doc(hidden)] - fn index_into_mut<'dom, 'v>(self, v: &'v mut Value<'dom>) -> Option<&'v mut Value<'dom>>; + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>; + + /// Panic if array index out of bounds. If key is not already in the object, + /// insert it with a value of null. Panic if Value is a type that cannot be + /// indexed into, except if Value is null then it can be treated as an empty + /// object. + #[doc(hidden)] + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value; } impl Index for usize { - fn value_index_into<'dom, 'v>(self, v: &'v Value<'dom>) -> Option<&'v Value<'dom>> { - v.get_index(self) + fn value_index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + if !v.is_array() { + return None; + } + v.get_index(*self) } - fn lazyvalue_index_into<'de>(self, v: &'de LazyValue<'de>) -> Option> { - v.get_index(self) + fn lazyvalue_index_into<'de>(&self, v: &'de LazyValue<'de>) -> Option> { + v.get_index(*self) } } impl IndexMut for usize { - fn index_into_mut<'dom, 'v>(self, v: &'v mut Value<'dom>) -> Option<&'v mut Value<'dom>> { - v.get_index_mut(self) + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + if !v.is_array() { + return None; + } + v.get_index_mut(*self) + } + + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + let typ = v.get_type(); + let len = v.len(); + v.as_array_mut() + .unwrap_or_else(|| panic!("cannot access index in non-array value type {:?}", typ)) + .0 + .get_index_mut(*self) + .unwrap_or_else(|| panic!("index {} out of bounds (len: {})", *self, len)) } } -macro_rules! impl_index { +macro_rules! impl_str_index { ($($t: ty),*) => { $( impl Index for &$t { - fn value_index_into<'dom, 'v>(self, v: &'v Value<'dom>) -> Option<&'v Value<'dom>> { - v.get_key(self) + fn value_index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + if !v.is_object() { + return None; + } + v.get_key(*self) } - fn lazyvalue_index_into<'de>(self, v: &'de LazyValue<'de>) -> Option> { - v.get_key(self) + fn lazyvalue_index_into<'de>(&self, v: &'de LazyValue<'de>) -> Option> { + v.get_key(*self) } + } impl IndexMut for &$t { - fn index_into_mut<'dom, 'v>(self, v: &'v mut Value<'dom>) -> Option<&'v mut Value<'dom>> { - v.get_key_mut(self) + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + if !v.is_object() { + return None; + } + v.get_key_mut(*self).map(|v| v.0) + } + + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + let mut shared = v.shared_parts(); + if v.is_null() { + if shared.is_null() { + shared = Shared::new_ptr(); + *v = Value::new_object(shared, 8); + } else { + unsafe { std::ptr::write(v, Value::new_object(shared, DEFAULT_OBJ_CAP)) }; + } + } + + let typ = v.get_type(); + let (obj, mut dormant_obj) = DormantMutRef::new(v); + obj.as_object_mut() + .expect(&format!("cannot access key in non-object value {:?}", typ)) + .0 + .get_key_mut(*self).map_or_else(|| { + let o = unsafe { dormant_obj.reborrow() }; + let _ = SharedCtxGuard::assign(shared); + let inserted = o.append_pair((Into::::into((*self)), Value::new_null(shared))); + &mut inserted.1 + }, |v| v.0) } } )* }; } -impl_index!(str, String, faststr::FastStr); +impl_str_index!(str, String, faststr::FastStr); + +impl Index for &T +where + T: ?Sized + Index, +{ + fn value_index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + (**self).value_index_into(v) + } -// Prevent users from implementing the Index trait. -mod private { - pub trait Sealed {} - impl Sealed for usize {} - impl Sealed for str {} - impl Sealed for std::string::String {} - impl Sealed for faststr::FastStr {} - impl<'a, T> Sealed for &'a T where T: ?Sized + Sealed {} + fn lazyvalue_index_into<'de>(&self, v: &'de LazyValue<'de>) -> Option> { + (**self).lazyvalue_index_into(v) + } } -impl<'dom, I> ops::Index for Value<'dom> +impl IndexMut for &T where - I: Index, + T: ?Sized + IndexMut, { - type Output = Value<'dom>; + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + (**self).index_into_mut(v) + } - fn index(&self, index: I) -> &Value<'dom> { - // if not found, return NULL value - thread_local! { - pub static NULL: Value<'static> = const { Value::new_uinit() }; - } - index.value_index_into(self).unwrap() + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + (**self).index_or_insert(v) } } diff --git a/src/value/macros.rs b/src/value/macros.rs new file mode 100644 index 0000000..b832219 --- /dev/null +++ b/src/value/macros.rs @@ -0,0 +1,532 @@ +// The file is copied from `serde_json` and modified. + +/// Construct a `sonic_rs::Value` from a JSON literal. +/// +/// ``` +/// # use sonic_rs::json; +/// # +/// let value = json!({ +/// "code": 200, +/// "success": true, +/// "payload": { +/// "features": [ +/// "serde", +/// "json" +/// ], +/// "homepage": null +/// } +/// }); +/// ``` +/// +/// Variables or expressions can be interpolated into the JSON literal. Any type +/// interpolated into an array element or object value must implement Serde's +/// `Serialize` trait, while any type interpolated into a object key must +/// implement `AsRef`. If the `Serialize` implementation of the +/// interpolated type decides to fail, or if the interpolated type contains a +/// map with non-string keys, the `json!` macro will panic. +/// +/// ``` +/// # use sonic_rs::json; +/// # +/// let code = 200; +/// let features = vec!["sonic_rs", "json"]; +/// +/// let value = json!({ +/// "code": code, +/// "success": code == 200, +/// "payload": { +/// "features": features, +/// features[0]: features[1] +/// } +/// }); +/// assert_eq!(value["code"], 200); +/// assert_eq!(value["payload"]["features"][0], "sonic_rs"); +/// ``` +/// +/// Trailing commas are allowed inside both arrays and objects. +/// +/// ``` +/// # use sonic_rs::json; +/// # +/// +/// let value = json!([ +/// "notice", +/// "the", +/// "trailing", +/// "comma -->", +/// ]); +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! json { + ////////////////////////////////////////////////////////////////////////// + // The implementation of a static node. It will not create a shared allocator. + // + // Must be invoked as: json_internal!($($json)+) + ////////////////////////////////////////////////////////////////////////// + (true) => { + $crate::value::node::Value::new_bool(true, std::ptr::null()) + }; + + (false) => { + $crate::value::node::Value::new_bool(false, std::ptr::null()) + }; + + (null) => { + $crate::value::node::Value::new_null(std::ptr::null()) + }; + + ([]) => { + $crate::value::array::Array::new().into_value() + }; + + ({}) => { + $crate::value::object::Object::new().into_value() + }; + + // Hide distracting implementation details from the generated rustdoc. + ($($json:tt)+) => { + { + use $crate::value::value_trait::JsonValueTrait; + let shared = unsafe { &*$crate::value::shared::Shared::new_ptr() }; + let mut value = json_internal!(shared, $($json)+); + if value.is_number() { + unsafe { + drop(Box::from_raw(shared as *const _ as *mut $crate::value::shared::Shared)); + } + value.mark_shared(std::ptr::null()); + } else { + value.mark_root(); + } + value + } + }; +} + +/// Construct a `sonic_rs::value::Array` from a JSON array literal. +/// +/// ``` +/// use sonic_rs::array; +/// use sonic_rs::json; +/// use sonic_rs::JsonValueTrait; // tait for `is_null()` +/// +/// let local = "foo"; +/// let array = array![null, local, true, false, 123, "hello", 1 == 2, array![1, 2, 3], {"key": "value"}]; +/// assert!(array[0].is_null()); +/// assert_eq!(array[1].as_str(), Some("foo")); +/// assert_eq!(array[array.len() - 2][0].as_u64(), Some(1)); +/// assert_eq!(array[array.len() - 1], json!({"key": "value"})); +/// +/// ``` +/// +#[macro_export(local_inner_macros)] +macro_rules! array { + () => { + $crate::value::Array::new() + }; + + ($($tt:tt)+) => { + { + let shared = unsafe { &*$crate::value::shared::Shared::new_ptr() }; + let mut value = json_internal!(shared, [$($tt)+]); + value.mark_root(); + value.into_array().expect("the literal is not a json array") + } + }; +} + +/// Construct a `sonic_rs::value::Object` from a JSON object literal. +/// +/// ``` +/// # use sonic_rs::object; +/// # +/// let code = 200; +/// let features = vec!["sonic_rs", "json"]; +/// +/// let object = object!{ +/// "code": code, +/// "success": code == 200, +/// "payload": { +/// "features": features, +/// features[0]: features[1] +/// } +/// }; +/// assert_eq!(object["code"], 200); +/// assert_eq!(object["payload"]["features"][0], "sonic_rs"); +/// ``` +/// +#[macro_export(local_inner_macros)] +macro_rules! object { + () => { + $crate::value::Object::new() + }; + + ($($tt:tt)+) => { + { + let shared = unsafe { &*$crate::value::shared::Shared::new_ptr() }; + let mut value = json_internal!(shared, {$($tt)+}); + value.mark_root(); + value.into_object().expect("the literal is not a json object") + } + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! json_internal { + ////////////////////////////////////////////////////////////////////////// + // TT muncher for parsing the inside of an array [...]. Produces a vec![...] + // of the elements. + // + // Must be invoked as: json_internal!(@array [] $($tt)*) + ////////////////////////////////////////////////////////////////////////// + + // Done with trailing comma. + (@array $shared:expr, [$($elems:expr,)*]) => { + json_internal_array![$shared, $($elems)*] + }; + + // Done without trailing comma. + (@array $shared:expr, [$($elems:expr),*]) => { + json_internal_array![$shared, $($elems)*] + }; + + // Next element is `null`. + (@array $shared:expr, [$($elems:expr,)*] null $($rest:tt)*) => { + json_internal!(@array $shared, [$($elems,)* json_internal!($shared, null)] $($rest)*) + }; + + // Next element is `true`. + (@array $shared:expr, [$($elems:expr,)*] true $($rest:tt)*) => { + json_internal!(@array $shared, [$($elems,)* json_internal!($shared, true)] $($rest)*) + }; + + // Next element is `false`. + (@array $shared:expr, [$($elems:expr,)*] false $($rest:tt)*) => { + json_internal!(@array $shared, [$($elems,)* json_internal!($shared, false)] $($rest)*) + }; + + // Next element is an array. + (@array $shared:expr, [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => { + json_internal!(@array $shared, [$($elems,)* json_internal!($shared, [$($array)*])] $($rest)*) + }; + + // Next element is a map. + (@array $shared:expr, [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => { + json_internal!(@array $shared, [$($elems,)* json_internal!($shared, {$($map)*})] $($rest)*) + }; + + // Next element is an expression followed by comma. + (@array $shared:expr, [$($elems:expr,)*] $next:expr, $($rest:tt)*) => { + json_internal!(@array $shared, [$($elems,)* json_internal!($shared, $next),] $($rest)*) + }; + + // Last element is an expression with no trailing comma. + (@array $shared:expr, [$($elems:expr,)*] $last:expr) => { + json_internal!(@array $shared, [$($elems,)* json_internal!($shared, $last)]) + }; + + // Comma after the most recent element. + (@array $shared:expr, [$($elems:expr),*] , $($rest:tt)*) => { + json_internal!(@array $shared, [$($elems,)*] $($rest)*) + }; + + // Unexpected token after most recent element. + (@array $shared:expr, [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => { + json_unexpected!($unexpected) + }; + + ////////////////////////////////////////////////////////////////////////// + // TT muncher for parsing the inside of an object {...}. Each entry is + // inserted into the given map variable. + // + // Must be invoked as: json_internal!(@object $map () ($($tt)*) ($($tt)*)) + // + // We require two copies of the input tokens so that we can match on one + // copy and trigger errors on the other copy. + ////////////////////////////////////////////////////////////////////////// + + // Done. + (@object $shared:expr, $object:ident () () ()) => {}; + + // Insert the current entry followed by trailing comma. + (@object $shared:expr, $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => { + let key: &str = ($($key)+).as_ref(); + let pair: $crate::value::object::Pair = ($crate::value::node::Value::copy_str(key, $shared), $value); + let _ = $object.append_pair(pair); + json_internal!(@object $shared, $object () ($($rest)*) ($($rest)*)); + }; + + // Current entry followed by unexpected token. + (@object $shared:expr, $object:ident [$($key:tt)+] ($value:expr) $unexpected:tt $($rest:tt)*) => { + json_unexpected!($unexpected); + }; + + // Insert the last entry without trailing comma. + (@object $shared:expr, $object:ident [$($key:tt)+] ($value:expr)) => { + let key: &str = ($($key)+).as_ref(); + let pair: $crate::value::object::Pair = ($crate::value::node::Value::copy_str(key, $shared), $value); + let _ = $object.append_pair(pair); + }; + + // Next value is `null`. + (@object $shared:expr, $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => { + json_internal!(@object $shared, $object [$($key)+] (json_internal!($shared, null)) $($rest)*); + }; + + // Next value is `true`. + (@object $shared:expr, $object:ident ($($key:tt)+) (: true $($rest:tt)*) $copy:tt) => { + json_internal!(@object $shared, $object [$($key)+] (json_internal!($shared, true)) $($rest)*); + }; + + // Next value is `false`. + (@object $shared:expr, $object:ident ($($key:tt)+) (: false $($rest:tt)*) $copy:tt) => { + json_internal!(@object $shared, $object [$($key)+] (json_internal!($shared, false)) $($rest)*); + }; + + // Next value is an array. + (@object $shared:expr, $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => { + json_internal!(@object $shared, $object [$($key)+] (json_internal!($shared, [$($array)*])) $($rest)*); + }; + + // Next value is a map. + (@object $shared:expr, $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => { + json_internal!(@object $shared, $object [$($key)+] (json_internal!($shared, {$($map)*})) $($rest)*); + }; + + // Next value is an expression followed by comma. + (@object $shared:expr, $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => { + json_internal!(@object $shared, $object [$($key)+] (json_internal!($shared, $value)) , $($rest)*); + }; + + // Last value is an expression with no trailing comma. + (@object $shared:expr, $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => { + json_internal!(@object $shared, $object [$($key)+] (json_internal!($shared, $value))); + }; + + // Missing value for last entry. Trigger a reasonable error message. + (@object $shared:expr, $object:ident ($($key:tt)+) (:) $copy:tt) => { + // "unexpected end of macro invocation" + json_internal!(); + }; + + // Missing colon and value for last entry. Trigger a reasonable error + // message. + (@object $shared:expr, $object:ident ($($key:tt)+) () $copy:tt) => { + // "unexpected end of macro invocation" + json_internal!(); + }; + + // Misplaced colon. Trigger a reasonable error message. + (@object $shared:expr, $object:ident () (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => { + // Takes no arguments so "no rules expected the token `:`". + json_unexpected!($colon); + }; + + // Found a comma inside a key. Trigger a reasonable error message. + (@object $shared:expr, $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => { + // Takes no arguments so "no rules expected the token `,`". + json_unexpected!($comma); + }; + + // Key is fully parenthesized. This avoids clippy double_parens false + // positives because the parenthesization may be necessary here. + (@object $shared:expr, $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => { + json_internal!(@object $shared, $object ($key) (: $($rest)*) (: $($rest)*)); + }; + + // Refuse to absorb colon token into key expression. + (@object $shared:expr, $object:ident ($($key:tt)*) (: $($unexpected:tt)+) $copy:tt) => { + json_expect_expr_comma!($($unexpected)+); + }; + + // Munch a token into the current key. + (@object $shared:expr, $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => { + json_internal!(@object $shared, $object ($($key)* $tt) ($($rest)*) ($($rest)*)); + }; + + ////////////////////////////////////////////////////////////////////////// + // The main implementation. + // + // Must be invoked as: json_internal!($($json)+) + ////////////////////////////////////////////////////////////////////////// + + ($shared:expr, true) => { + $crate::value::node::Value::new_bool(true, $shared) + }; + + ($shared:expr, false) => { + $crate::value::node::Value::new_bool(false, $shared) + }; + + ($shared:expr, null) => { + $crate::value::node::Value::new_null($shared) + }; + + ($shared:expr, []) => { + $crate::value::node::Value::new_array($shared, 0) + }; + + ($shared:expr, [ $($tt:tt)+ ]) => { + json_internal!(@array $shared, [] $($tt)+) + }; + + ($shared:expr, {}) => { + $crate::value::node::Value::new_object($shared, 0) + }; + + ($shared:expr, { $($tt:tt)+ }) => { + { + let mut obj_value = $crate::value::node::Value::new_object($shared, 0); + json_internal!(@object $shared, obj_value () ($($tt)+) ($($tt)+)); + obj_value + } + }; + + // Any Serialize type: numbers, strings, struct literals, variables etc. + // Must be below every other rule. + ($shared:expr, $other:expr) => { + $crate::value::ser::to_value_in($shared.into(), &$other).unwrap() + }; +} + +// The json_internal macro above cannot invoke vec directly because it uses +// local_inner_macros. A vec invocation there would resolve to $crate::vec. +// Instead invoke vec here outside of local_inner_macros. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! json_internal_array { + ($shared:expr, $($content:tt)*) => { + { + let mut arr_value = $crate::value::node::Value::new_array($shared, 0); + $( + arr_value.append_value($content); + )* + arr_value + } + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! json_unexpected { + () => {}; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! json_expect_expr_comma { + ($e:expr , $($tt:tt)*) => {}; +} + +#[cfg(test)] +mod test { + use crate::value::value_trait::JsonValueTrait; + use std::collections::HashMap; + + #[test] + fn test_json_memory() { + assert!(json!(true).is_static()); + assert!(json!(false).is_static()); + assert!(json!(null).is_static()); + assert!(json!([]).is_static()); + assert!(json!({}).is_static()); + assert!(json!(123).is_static()); + assert!(json!(1.23).is_static()); + assert!(json!("123").is_root()); + assert!(json!("").is_root()); + assert!(json!({"1": 123}).is_root()); + assert!(json!([[[]]]).is_root()); + } + + #[test] + fn test_json_macro() { + assert!(json!(true).is_true()); + assert!(json!(false).is_false()); + assert!(json!(null).is_null()); + assert!(json!("123").is_str()); + assert!(json!(vec![1]).is_array()); + assert_eq!(json!(vec![1, 2, 3][2]).as_i64(), Some(3)); + + let buf = json!([1, 2, 3]); + let arr = json!([true, false, null, 1, 2, 3, "hi", 1 == 2, buf[1] == buf[2]]); + assert!(arr.is_array()); + assert!(arr[arr.len() - 1].is_false()); + + let key = "i"; + let key2 = "\"i\""; + let obj = json!({ + "a": true, + "b": false, + "c": null, + "array": vec![1, 2, 3], + "map": ({ + let mut map = HashMap::::new(); + map.insert("a".to_string(), "b".to_string()); + map + }), + "f": 2.333, + "g": "hi", + "h": 1 == 2, + key: { + key2: [buf[1] == buf[2], 1], + }, + }); + assert!(obj.is_object()); + assert!(obj["a"].is_true()); + assert!(obj["array"][0].as_u64().unwrap() == 1); + assert!(obj["map"]["a"].as_str().unwrap() == "b"); + assert!(obj[key][key2][1].as_u64().unwrap() == 1); + + let obj = json!({ + "a": { "b" : {"c": [[[]], {}, {}]} } + }); + assert!(obj["a"]["b"]["c"][0][0].is_array()); + } + + #[test] + fn test_array_macro() { + let arr = array![]; + assert!(arr.into_value().is_static()); + + let arr = array![true, false, null, 1, 2, 3, "hi", 1 == 2]; + assert!(arr[arr.len() - 1].is_false()); + + let buf = array![1, 2, 3]; + let arr = array![true, false, null, 1, 2, 3, "hi", 1 == 2, buf[1] == buf[2]]; + assert!(arr[arr.len() - 1].is_false()); + } + + #[test] + fn test_object_macro() { + let obj = object! {}; + assert!(obj.into_value().is_static()); + + let obj = object! { + "a": true, + "b": false, + "c": null, + "d": 1, + "e": 2, + "f": 3, + "g": "hi", + "h": 1 == 2, + }; + assert!(obj["a"].is_true()); + + let buf = array![1, 2, 3]; + let obj = object! { + "a": true, + "b": false, + "c": null, + "d": 1, + "e": 2, + "f": 3, + "g": "hi", + "h": 1 == 2, + "i": { + "i": [buf[1] == buf[2], 1], + }, + }; + assert!(obj["i"]["i"][1].as_u64().unwrap() == 1); + } +} diff --git a/src/value/mod.rs b/src/value/mod.rs index 1f74eb0..ded48e8 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -1,11 +1,26 @@ -mod index; -mod node; -mod value_trait; - -pub use index::{Index, IndexMut}; -pub(crate) use node::TOKEN; -pub use node::{ - dom_from_slice, dom_from_slice_unchecked, dom_from_str, Array, ArrayMut, Document, Object, - ObjectMut, Value, ValueMut, -}; -pub use value_trait::{JsonType, JsonValue}; +pub mod node; +pub use node::{Value, ValueRef}; + +pub use value_trait::{JsonContainerTrait, JsonType, JsonValueMutTrait, JsonValueTrait}; +pub mod alloctor; +pub mod array; +pub mod de; +mod from; +pub mod index; +pub mod shared; +#[macro_use] +mod macros; +pub mod object; +mod partial_eq; +pub mod ser; +pub mod value_trait; +pub use array::Array; +pub use object::Object; +mod tryfrom; + +pub use ser::to_value; + +pub use de::from_value; + +const MAX_STR_SIZE: usize = u32::MAX as usize; +const PTR_BITS: usize = 48; diff --git a/src/value/node.rs b/src/value/node.rs index ee79f1f..4dea824 100644 --- a/src/value/node.rs +++ b/src/value/node.rs @@ -1,341 +1,464 @@ -use super::value_trait::{JsonType, JsonValue}; -use super::Index; -use super::IndexMut; -use crate::error::make_error; +use super::alloctor::SyncBump; +use super::index::Index; +use super::index::IndexMut; +use super::object::Pair; +use super::shared::Shared; +use super::value_trait::JsonContainerTrait; +use super::value_trait::JsonValueMutTrait; use crate::error::Result; use crate::parser::Parser; use crate::pointer::{JsonPointer, PointerNode}; -use crate::reader::UncheckedSliceRead; +use crate::reader::PaddedSliceRead; +use crate::reader::Reader; use crate::serde::tri; +use crate::util::arc::Arc; +use crate::util::taggedptr::TaggedPtr; use crate::util::utf8::from_utf8; +use crate::value::alloctor::AllocatorTrait; +use crate::value::array::Array; +use crate::value::from::get_shared_or_new; +use crate::value::object::Object; +use crate::value::value_trait::JsonValueTrait; use crate::visitor::JsonVisitor; -use crate::{to_string, Number}; +use crate::JsonType; +use crate::Number; use bumpalo::Bump; use core::mem::size_of; -use serde::de::Visitor; use serde::ser::{Error, Serialize, SerializeMap, SerializeSeq}; -use serde::Deserialize; use std::alloc::Layout; -use std::marker::PhantomData; -use std::mem::{transmute, MaybeUninit}; -use std::ops; +use std::fmt::Debug; +use std::fmt::Display; +use std::fmt::Formatter; +use std::mem::{transmute, ManuallyDrop, MaybeUninit}; use std::ptr::NonNull; use std::slice::{from_raw_parts, from_raw_parts_mut}; +use std::str::from_utf8_unchecked; -/// Value is a node in the DOM tree. -pub struct Value<'dom> { - typ: NodeMeta, - val: NodeValue<'dom>, +/// Represents any valid JSON value. +pub struct Value { + pub(crate) meta: Meta, + pub(crate) data: Data, } -impl<'dom> Default for Value<'dom> { - fn default() -> Self { - Self::new_uinit() - } -} - -impl From for Value<'_> { - fn from(val: bool) -> Self { - Self::new_bool(val) +unsafe impl Sync for Value {} +unsafe impl Send for Value {} + +impl Clone for Value { + /// Clone the value, if the value is a root node, we will create a new allocator for it. + /// + /// # Example + /// + /// ``` + /// use sonic_rs::json; + /// + /// let a = json!({"a": [1, 2, 3]}); + /// assert_eq!(a, a.clone()); + /// + /// ``` + fn clone(&self) -> Self { + match self.get_type() { + JsonType::Array | JsonType::Object if !self.is_empty() => { + let (shared, _) = get_shared_or_new(); + let mut v = self.clone_in(shared); + v.mark_root(); + v + } + JsonType::String => { + let s = self.str(); + // TODO: optimize static string + if s.is_empty() { + return Value::new_str("", std::ptr::null()); + } + let (shared, _) = get_shared_or_new(); + let mut v = Value::copy_str(s, shared); + v.mark_root(); + v + } + JsonType::Array if self.is_empty() => Value::new_array(std::ptr::null(), 0), + JsonType::Object if self.is_empty() => Value::new_object(std::ptr::null(), 0), + _ => { + let mut v = Value { + meta: self.meta, + data: self.data, + }; + v.mark_shared(std::ptr::null()); + v + } + } } } -impl From for Value<'_> { - fn from(val: u64) -> Self { - Self::new_u64(val) - } -} +impl Debug for Value { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let array_children = if self.is_array() { + Some(self.children::().unwrap_or(&[])) + } else { + None + }; -impl From for Value<'_> { - fn from(val: i64) -> Self { - Self::new_i64(val) - } -} + let object_children = if self.is_object() { + Some(self.children::().unwrap_or(&[])) + } else { + None + }; -impl TryFrom for Value<'_> { - type Error = crate::Error; + let shared = if self.is_static() { + None + } else { + Some(self.arc_shared()) + }; - fn try_from(value: f64) -> std::result::Result { - Self::new_f64(value) - .ok_or_else(|| make_error("NaN or Infinity is not a valid JSON value".to_string())) + let ret = f + .debug_struct("Value") + .field("data", &format!("{}", self)) + .field("is_root", &self.is_root()) + .field("shared_address", &self.meta.ptr()) + .field("shared", &shared) + .field("array_children", &array_children) + .field("object_children", &object_children) + .finish(); + std::mem::forget(shared); + ret } } -impl<'dom> std::fmt::Debug for Value<'dom> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(to_string(self).unwrap_or_else(|e| e.to_string()).as_str()) +impl Default for Value { + fn default() -> Self { + Value::new() } } -/// Object is a JSON object. -#[derive(Debug, Copy, Clone)] -pub struct Object<'dom>(&'dom Value<'dom>); - -/// ObjectMut is a mutable JSON object. -#[derive(Debug)] -pub struct ObjectMut<'dom>(ValueMut<'dom>); - -impl<'dom> Object<'dom> { - pub fn capacity(&self) -> usize { - self.0.capacity() - } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - pub fn contains_key(&self, key: &str) -> bool { - self.get(key).is_some() - } - - pub fn get(&self, key: &str) -> Option<&Value<'dom>> { - self.0.get_key(key) - } - - pub fn len(&self) -> usize { - self.0.len() +impl Value { + /// Convert into `Object`. If the value is not an object, return `None`. + /// + #[inline] + pub fn into_object(self) -> Option { + if self.is_object() { + Some(Object(self)) + } else { + None + } } -} -impl<'dom> ObjectMut<'dom> { - pub fn allocator(&self) -> &'dom Bump { - self.0.alloc + /// Convert into `Array`. If the value is not an array, return `None`. + /// + #[inline] + pub fn into_array(self) -> Option { + if self.is_array() { + Some(Array(self)) + } else { + None + } } - pub fn is_empty(&self) -> bool { - self.as_ref().is_empty() + pub(crate) fn is_root(&self) -> bool { + (self.meta.tag() & ROOT_MASK) == 0b1100 } - pub fn capacity(&self) -> usize { - self.as_ref().capacity() + pub(crate) fn is_inlined(&self) -> bool { + self.meta.tag() < STRING && !self.is_static() } - pub fn contains_key(&self, key: &str) -> bool { - self.as_ref().contains_key(key) + pub(crate) fn is_shared(&self) -> bool { + !self.is_root() && !self.is_static() } - pub fn len(&self) -> usize { - self.as_ref().len() + pub(crate) fn unmark_root(&mut self) { + let tag = self.meta.tag(); + if tag >= STRING { + self.meta.set_tag(tag & UNROOT_MASK); + } } - pub fn get(&'dom self, key: &str) -> Option<&Value<'dom>> { - self.0.get(key) + pub(crate) fn unset_root(&mut self) { + drop(self.arc_shared()); } - pub fn get_mut(&'dom mut self, key: &str) -> Option> { - if let Some(node) = self.0.val.get_mut(key) { - Some(ValueMut { - val: node, - alloc: self.0.alloc, - }) + #[doc(hidden)] + #[inline] + pub fn mark_root(&mut self) { + let tag = self.meta.tag(); + if tag >= STRING { + self.meta.set_tag(tag | ROOT_MASK); } else { - None + self.meta.set_ptr(std::ptr::null()); } } - // return old value if the k is exitsted - pub fn insert(&mut self, k: &str, v: Value<'dom>) -> Option> { - if let Some(node) = self.0.val.get_mut(k) { - let old = node.take(); - *(node) = v; - Some(old) - } else { - self.0 - .val - .append_object((Value::new_str(k, self.0.alloc), v), self.0.alloc); - None + pub(crate) fn clone_in(&self, shared: &Shared) -> Self { + // let arc_shared = + match self.get_type() { + JsonType::Array => { + let mut arr = Value::new_array(shared, self.len()); + for v in self.children::().unwrap() { + arr.append_value(v.clone_in(shared)); + } + arr + } + JsonType::Object => { + let mut obj = Value::new_object(shared, self.len()); + for (k, v) in self.children::<(Value, Value)>().unwrap() { + obj.append_pair((k.clone_in(shared), v.clone_in(shared))); + } + obj + } + JsonType::String => Value::copy_str(self.as_str().unwrap(), shared), + _ => { + let mut v = Value { + meta: self.meta, + data: self.data, + }; + v.mark_shared(shared); + v + } } } - pub fn remove(&mut self, k: &str) -> Option> { - self.0.val.remove_in_object(k) + #[inline] + pub(crate) fn set_type(&mut self, typ: u64) { + self.meta.set_tag(typ); } - pub fn pop(&mut self) -> Option> { - if self.is_empty() { - None - } else { - let children = self.0.val.children_mut_unchecked::(); - let node = children[children.len() - 1].take(); - self.0.val.add_len(-1); - Some(node) + pub(crate) fn drop_slow(&mut self) { + if self.is_array() { + for child in self.children_mut_unchecked::() { + child.drop_slow(); + } + } else if self.is_object() { + for child in self.children_mut_unchecked::<(Value, Value)>() { + child.0.drop_slow(); + child.1.drop_slow(); + } } - } - pub fn reserve(&mut self, addtional: usize) { - self.0.val.reserve_object(addtional, self.0.alloc); + if self.is_root() { + drop(self.arc_shared()); + } } +} - // as_ref only used in internal, so safe here. - fn as_ref(&self) -> Object<'dom> { - unsafe { *(self as *const Self as *const Object<'dom>) } +impl Display for Value { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", crate::to_string(self).expect("invalid value")) } } -/// Array is a JSON array. -#[derive(Debug, Copy, Clone)] -pub struct Array<'dom>(&'dom Value<'dom>); +// Value Status: +// IsRoot: have a refcnt for the shared allocator and it is often string, non-empty array, non-empty object +// IsnotRoot: the children nodes, it is owned by the root node +// IsCombined: the children maybe a root, it have other allocators +// IsFlatten: the node or its children donot have any allocators -/// ArrayMut is a mutable JSON array. -pub struct ArrayMut<'dom>(ValueMut<'dom>); +// The drop policy: +// IsRoot + IsCombined: -> drop traverse +// IsnotRoot + IsCombined: -> drop traverse +// IsRoot + IsnotCombined: -> drop directly, refcnt - 1 +// IsnotRoot + IsnotCombined: -> ignore it -impl<'dom> Array<'dom> { - pub fn capacity(&self) -> usize { - self.0.capacity() - } +// To make sure correctness, when we drop a node that is not a root node, we must mark Shared as combined. +// such as an assignment operation: `array[1] = new_value`. +// In the internal codes, we manually drop the value, and only mark Shared as combined in necessary. +impl Drop for Value { + fn drop(&mut self) { + if self.is_static() { + return; + } - pub fn is_empty(&self) -> bool { - self.0.len() == 0 - } + // optimize the drop overhead + // when nodes been Combined and there may be inserted root node, we must traverse the tree + if self.shared().is_combined() { + self.drop_slow(); + return; + } - pub fn len(&self) -> usize { - self.0.len() + if self.is_root() { + drop(self.arc_shared()); + } else { + // If value is not root, it maybe dropped in place, and insert a new allocator in the document, + // we mark Combined flag in the shared, to notify the root node to traverse the tree when dropping root. + self.shared().set_combined() + } } } -impl<'dom> ops::Deref for Array<'dom> { - type Target = [Value<'dom>]; - - #[inline] - fn deref(&self) -> &Self::Target { - self.0.children_unchecked() - } +#[derive(Copy, Clone)] +pub(crate) union Meta { + ptr: TaggedPtr, + val: u64, } -impl<'dom> ArrayMut<'dom> { - pub fn push(&mut self, node: Value<'dom>) { - self.0.val.append_array(node, self.0.alloc) - } - - pub fn pop(&mut self) -> Option> { - if self.is_empty() { - None - } else { - let children = self.0.val.children_mut_unchecked::(); - let node = children[children.len() - 1].take(); - self.0.val.add_len(-1); - Some(node) +pub(crate) const TYPE_MASK: u64 = (std::mem::align_of::() as u64) - 1; +pub(crate) const ROOT_MASK: u64 = 0b1100; +pub(crate) const UNROOT_MASK: u64 = 0b1011; +/// shared ptr: | hi | valid ptr | tag | +pub(crate) const SHARED_PTR_MASK: u64 = 0x0000FFFFFFFFFFFF & !TYPE_MASK; +/// str ptr: | hi | valid str ptr | +pub(crate) const STR_PTR_MASK: u64 = 0x0000FFFFFFFFFFFF; + +/// Encoding format: +/// static node +pub(crate) const NULL: u64 = 0b0000; +pub(crate) const FALSE: u64 = 0b0001; +pub(crate) const TRUE: u64 = 0b0010; +pub(crate) const _: u64 = 0b0011; +pub(crate) const FLOAT: u64 = 0b0100; +pub(crate) const UNSIGNED: u64 = 0b0101; +pub(crate) const SIGNED: u64 = 0b0110; +pub(crate) const _: u64 = 0b0111; +/// dynamic node +pub(crate) const STRING: u64 = 0b1000; +pub(crate) const _: u64 = 0b1001; +pub(crate) const ARRAY: u64 = 0b1010; +pub(crate) const OBJECT: u64 = 0b1011; +pub(crate) const ROOT_STRING: u64 = 0b1100; +pub(crate) const _: u64 = 0b1101; +pub(crate) const ROOT_ARRAY: u64 = 0b1110; +pub(crate) const ROOT_OBJECT: u64 = 0b1111; + +impl Meta { + pub(crate) const fn new(typ: u64, shared: *const Shared) -> Self { + Self { + ptr: TaggedPtr::new(shared, typ as usize), } } - pub fn is_empty(&self) -> bool { - self.as_ref().is_empty() + pub(crate) fn ptr(&self) -> *const Shared { + unsafe { (self.val & SHARED_PTR_MASK) as *const _ } } - pub fn len(&self) -> usize { - self.as_ref().len() + pub(crate) fn set_ptr(&mut self, ptr: *const Shared) { + unsafe { + self.ptr.set_ptr(ptr); + } } - pub fn capacity(&self) -> usize { - self.as_ref().capacity() + pub(crate) fn set_tag(&mut self, tag: u64) { + unsafe { + self.ptr.set_tag(tag as usize); + } } - pub fn reserve(&mut self, addtional: usize) { - self.0.val.reserve_array(addtional, self.0.alloc); + pub(crate) fn tag(&self) -> u64 { + unsafe { self.ptr.tag() as u64 } } +} - pub fn allocator(&self) -> &'dom Bump { - self.0.alloc - } +#[derive(Copy, Clone)] +pub(crate) union Data { + pub(crate) uval: u64, + pub(crate) ival: i64, + pub(crate) fval: f64, + pub(crate) sval: *const u8, + pub(crate) achildren: *mut Value, + pub(crate) ochildren: *mut Pair, + pub(crate) parent: u64, + pub(crate) info: NonNull, +} - // as_ref only used in internal, so safe here. - fn as_ref(&self) -> Array<'dom> { - unsafe { *(self as *const Self as *const Array<'dom>) } +impl Debug for Data { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + unsafe { + match self.parent { + 0 => write!(f, "parent: null"), + _ => write!(f, "parent: {}", self.parent), + } + } } } -impl<'dom> ops::Deref for ArrayMut<'dom> { - type Target = [Value<'dom>]; - - #[inline] - fn deref(&self) -> &Self::Target { - self.0.val.children_unchecked() - } +// Metanode is used to store the length and capacity of the array and object. and should be aligned as Values. +#[derive(Debug)] +pub(crate) struct MetaNode { + len: u64, + cap: u64, + _pad: u64, } -impl<'dom> ops::DerefMut for ArrayMut<'dom> { - #[inline] - fn deref_mut(&mut self) -> &mut [Value<'dom>] { - self.0.val.children_mut_unchecked() +impl MetaNode { + fn from_nodes(slice: &mut [Value]) -> &Self { + debug_assert!(slice.len() >= Value::MEAT_NODE_COUNT); + unsafe { &mut *(slice.as_mut_ptr() as *mut MetaNode) } } } -#[derive(Debug, Copy, Clone)] -struct NodeMeta(u64); - -#[derive(Copy, Clone)] -union NodeValue<'dom> { - uval: u64, - ival: i64, - fval: f64, - parent: u64, - nptr: NonNull>, - first: NonNull, - - str_ptr: *const u8, - own_ptr: *mut u8, - _lifetime: PhantomData<&'dom Document>, +thread_local! { + static NODE_BUF: std::cell::RefCell>> = std::cell::RefCell::new(Vec::new()); } -impl<'a> JsonValue for Value<'a> { - type ValueType<'dom> = &'dom Value<'dom> where Self: 'dom; +impl super::value_trait::JsonValueTrait for Value { + type ValueType<'v> = &'v Value where Self: 'v; + #[inline] fn get_type(&self) -> JsonType { - const TYPE_MASK: u64 = 0b111; - ((self.typ.0 & TYPE_MASK) as u8).into() + match self.typ() { + NULL => JsonType::Null, + FALSE | TRUE => JsonType::Boolean, + SIGNED | UNSIGNED | FLOAT => JsonType::Number, + STRING | ROOT_STRING => JsonType::String, + ARRAY | ROOT_ARRAY => JsonType::Array, + OBJECT | ROOT_OBJECT => JsonType::Object, + _ => unreachable!(), + } } + #[inline] fn as_number(&self) -> Option { match self.typ() { - Value::UNSIGNED => self.as_u64().map(|u| u.into()), - Value::SIGNED => self.as_i64().map(|i| i.into()), - Value::FLOAT => self.as_f64().and_then(Number::from_f64), + UNSIGNED => self.as_u64().map(|u| u.into()), + SIGNED => self.as_i64().map(|i| i.into()), + FLOAT => self.as_f64().and_then(Number::from_f64), _ => None, } } + #[inline] fn as_i64(&self) -> Option { match self.typ() { - Value::SIGNED => Some(self.i64()), - Value::UNSIGNED if self.u64() <= i64::MAX as u64 => Some(self.u64() as i64), + SIGNED => Some(self.i64()), + UNSIGNED if self.u64() <= i64::MAX as u64 => Some(self.u64() as i64), _ => None, } } + #[inline] fn as_u64(&self) -> Option { match self.typ() { - Value::UNSIGNED => Some(self.u64()), - Value::SIGNED if self.i64() >= 0 => Some(self.i64() as u64), + UNSIGNED => Some(self.u64()), + SIGNED if self.i64() >= 0 => Some(self.i64() as u64), _ => None, } } + #[inline] fn as_f64(&self) -> Option { match self.typ() { - Value::UNSIGNED => Some(self.u64() as f64), - Value::SIGNED => Some(self.i64() as f64), - Value::FLOAT => Some(self.f64()), + UNSIGNED => Some(self.u64() as f64), + SIGNED => Some(self.i64() as f64), + FLOAT => Some(self.f64()), _ => None, } } + #[inline] fn as_bool(&self) -> Option { match self.typ() { - Value::TRUE => Some(true), - Value::FALSE => Some(false), + TRUE => Some(true), + FALSE => Some(false), _ => None, } } + #[inline] fn as_str(&self) -> Option<&str> { - if self.typ() == Value::STRING { + if self.is_str() { Some(self.str()) } else { None } } - fn pointer<'dom>(&'dom self, path: &JsonPointer) -> Option> { + #[inline] + fn pointer(&self, path: &JsonPointer) -> Option> { let mut node = self; for p in path { if let Some(next) = node.at_pointer(p) { @@ -347,390 +470,433 @@ impl<'a> JsonValue for Value<'a> { Some(node) } - fn get<'dom, I: Index>(&'_ self, index: I) -> Option> { + #[inline] + fn get(&self, index: I) -> Option> { index.value_index_into(self) } } -impl<'dom> Value<'dom> { - const NULL: u64 = (JsonType::Null as u64); - const FALSE: u64 = (JsonType::Boolean as u64); - const TRUE: u64 = (JsonType::Boolean as u64) | (1 << 3); - const UNSIGNED: u64 = (JsonType::Number as u64); - const SIGNED: u64 = (JsonType::Number as u64) | (1 << 3); - const FLOAT: u64 = (JsonType::Number as u64) | (2 << 3); - const ARRAY: u64 = (JsonType::Array as u64); - const OBJECT: u64 = (JsonType::Object as u64); - const STRING: u64 = (JsonType::String as u64); - - // type bits - const LEN_BITS: u64 = 8; - - // the count of meta node - // layout as: - // [ meta nodes ][array/object children..] - const MEAT_NODE_COUNT: usize = size_of::() / size_of::(); -} +impl JsonContainerTrait for Value { + type ArrayType = Array; + type ObjectType = Object; -impl<'dom> Value<'dom> { - /// Create a new `Value` from a null - #[inline(always)] - pub const fn new_uinit() -> Self { - Self { - typ: NodeMeta(Self::NULL), - val: NodeValue { uval: 0 }, + #[inline] + fn as_array(&self) -> Option<&Self::ArrayType> { + if self.is_array() { + Some(unsafe { transmute(self) }) + } else { + None } } - /// Create a new `Value` from a i64 - #[inline(always)] - pub const fn new_i64(val: i64) -> Self { - Self { - typ: NodeMeta(Self::SIGNED), - val: NodeValue { ival: val }, + #[inline] + fn as_object(&self) -> Option<&Self::ObjectType> { + if self.is_object() { + Some(unsafe { transmute(self) }) + } else { + None } } +} - /// Create a new `Value` from a f64, if not finite return None. - #[inline(always)] - pub fn new_f64(val: f64) -> Option { - // not support f64::NAN and f64::INFINITY - if val.is_finite() { - Some(Self { - typ: NodeMeta(Self::FLOAT), - val: NodeValue { fval: val }, - }) +impl JsonValueMutTrait for Value { + type ValueType = Value; + type ArrayType = Array; + type ObjectType = Object; + + #[inline] + fn as_object_mut(&mut self) -> Option<&mut Self::ObjectType> { + if self.is_object() { + Some(unsafe { transmute(self) }) } else { None } } - /// Create a new `Value` from a f64. Not checking the f64 is finite. - /// # Safety - /// The f64 must be finite. Because JSON RFC NOT support `NaN` and `Infinity`. - #[inline(always)] - pub unsafe fn new_f64_unchecked(val: f64) -> Self { - Self { - typ: NodeMeta(Self::FLOAT), - val: NodeValue { fval: val }, + #[inline] + fn as_array_mut(&mut self) -> Option<&mut Self::ArrayType> { + if self.is_array() { + Some(unsafe { transmute(self) }) + } else { + None } } - /// Create a new `Value` from a u64 - #[inline(always)] - pub const fn new_u64(val: u64) -> Self { - Self { - typ: NodeMeta(Self::UNSIGNED), - val: NodeValue { uval: val }, + #[inline] + fn pointer_mut(&mut self, path: &JsonPointer) -> Option<&mut Self::ValueType> { + let mut node = self; + for p in path { + if let Some(next) = node.at_pointer_mut(p) { + node = next; + } else { + return None; + } } + Some(node) } - /// Create a new `Value` from a bool - #[inline(always)] - pub const fn new_bool(val: bool) -> Self { - Self { - typ: NodeMeta(if val { Self::TRUE } else { Self::FALSE }), - val: NodeValue { uval: 0 }, - } + #[inline] + fn get_mut(&mut self, index: I) -> Option<&mut Self::ValueType> { + index.index_into_mut(self) } +} - /// Create a new `Value` from a empty object - #[inline(always)] - pub const fn new_object() -> Self { - Self { - typ: NodeMeta(JsonType::Object as u64), - val: NodeValue { uval: 0 }, +/// ValueRef is a immutable reference helper for Value. +/// +/// # Example +/// +/// ``` +/// use sonic_rs::{ValueRef, json, JsonValueTrait}; +/// +/// let v = json!({ +/// "name": "Xiaoming", +/// "age": 18, +/// }); +/// +/// match v.as_ref() { +/// ValueRef::Object(obj) => { +/// assert_eq!(obj.get(&"name").unwrap().as_str().unwrap(), "Xiaoming"); +/// assert_eq!(obj.get(&"age").unwrap().as_i64().unwrap(), 18); +/// }, +/// _ => unreachable!(), +/// } +/// ``` +/// +pub enum ValueRef<'a> { + Null, + Bool(bool), + Number(Number), + String(&'a str), + Array(&'a Array), + Object(&'a Object), +} + +impl Value { + const PADDING_SIZE: usize = 64; + pub(crate) const MEAT_NODE_COUNT: usize = 1; + + /// Create a new `null` Value. It is also the default value of `Value`. + /// + #[inline] + pub const fn new() -> Self { + Value { + // without shared allocator + meta: Meta::new(NULL, std::ptr::null()), + data: Data { uval: 0 }, + } + } + + /// Create a reference `ValueRef` from a `&Value`. + /// + /// # Example + /// + /// ``` + /// use sonic_rs::{ValueRef, json, JsonValueTrait}; + /// + /// let v = json!({ + /// "name": "Xiaoming", + /// "age": 18, + /// }); + /// + /// match v.as_ref() { + /// ValueRef::Object(obj) => { + /// assert_eq!(obj.get(&"name").unwrap().as_str().unwrap(), "Xiaoming"); + /// assert_eq!(obj.get(&"age").unwrap().as_i64().unwrap(), 18); + /// }, + /// _ => unreachable!(), + /// } + /// ``` + /// + #[inline] + pub fn as_ref(&self) -> ValueRef<'_> { + match self.typ() { + NULL => ValueRef::Null, + FALSE => ValueRef::Bool(false), + TRUE => ValueRef::Bool(true), + UNSIGNED => ValueRef::Number(self.as_u64().unwrap().into()), + SIGNED => ValueRef::Number(self.as_i64().unwrap().into()), + FLOAT => ValueRef::Number(Number::from_f64(self.as_f64().unwrap()).unwrap()), + STRING | ROOT_STRING => ValueRef::String(self.as_str().unwrap()), + ARRAY | ROOT_ARRAY => ValueRef::Array(self.as_array().unwrap()), + OBJECT | ROOT_OBJECT => ValueRef::Object(self.as_object().unwrap()), + _ => unreachable!(), } } - /// Create a new `Value` from a empty array - #[inline(always)] - pub const fn new_array() -> Self { - Self { - typ: NodeMeta(JsonType::Array as u64), - val: NodeValue { uval: 0 }, - } + /// Create a new string Value from a `&'static str` with zero-copy. + #[inline] + pub fn from_static_str(val: &'static str) -> Self { + let mut v = Value { + meta: Meta::new(STRING, std::ptr::null()), + data: Data { sval: val.as_ptr() }, + }; + v.set_str_len(val.len()); + v } - /// create a new owned string value with the alloctor - #[inline(always)] - pub fn new_str(val: &str, alloc: &'dom Bump) -> Self { - let val = alloc.alloc_str(val); - Self { - typ: NodeMeta(Self::STRING | ((val.len() as u64) << Self::LEN_BITS)), - val: NodeValue { - str_ptr: val.as_bytes().as_ptr(), - }, + #[doc(hidden)] + #[inline] + pub fn new_u64(val: u64, share: *const Shared) -> Self { + Value { + meta: Meta::new(UNSIGNED, share), + data: Data { uval: val }, } } - /// create a new string from static - #[inline(always)] - pub fn new_str_static(val: &'static str) -> Self { - Self { - typ: NodeMeta(Self::STRING | ((val.len() as u64) << Self::LEN_BITS)), - val: NodeValue { - str_ptr: val.as_bytes().as_ptr(), - }, - } + #[doc(hidden)] + #[inline] + pub fn new_in(share: Arc) -> Self { + let mut value = Value { + meta: Meta::new(NULL, share.inner_ptr() as *const _), + data: Data { uval: 0 }, + }; + value.mark_root(); + std::mem::forget(share); + value } - /// create a new borrow string, lifetime of Value will limited by str - #[inline(always)] - pub fn new_str_borrow(val: &str) -> Self { - Self { - typ: NodeMeta(Self::STRING | ((val.len() as u64) << Self::LEN_BITS)), - val: NodeValue { - str_ptr: val.as_bytes().as_ptr(), - }, + #[doc(hidden)] + #[inline] + pub fn new_i64(val: i64, share: *const Shared) -> Self { + Value { + meta: Meta::new(SIGNED, share), + data: Data { ival: val }, } } - pub fn as_array(&'dom self) -> Option> { - if self.is_array() { - Some(Array(self)) - } else { - None + #[doc(hidden)] + #[inline] + pub(crate) unsafe fn new_f64_unchecked(val: f64, share: *const Shared) -> Self { + Value { + meta: Meta::new(FLOAT, share), + data: Data { fval: val }, } } - pub fn as_object(&'dom self) -> Option> { - if self.is_object() { - Some(Object(self)) + #[doc(hidden)] + #[inline] + pub fn new_f64(val: f64, share: *const Shared) -> Option { + if val.is_finite() { + Some(Value { + meta: Meta::new(FLOAT, share), + data: Data { fval: val }, + }) } else { None } } - fn typ(&self) -> u64 { - self.typ.0 & 0xff + #[doc(hidden)] + #[inline] + pub fn new_null(share: *const Shared) -> Self { + Value { + meta: Meta::new(NULL, share), + data: Data { uval: 0 }, + } } - fn pointer_mut(&mut self, path: &JsonPointer) -> Option<&mut Self> { - let mut node = self; - for p in path { - if let Some(next) = node.at_pointer_mut(p) { - node = next; - } else { - return None; - } + #[doc(hidden)] + #[inline] + pub fn new_array(share: *const Shared, capacity: usize) -> Self { + let mut array = Value { + meta: Meta::new(ARRAY, share), + data: Data { + achildren: std::ptr::null_mut(), + }, + }; + if capacity == 0 { + return array; } - Some(node) + array.reserve::(capacity); + array } - fn get_mut(&mut self, index: I) -> Option<&mut Self> { - index.index_into_mut(self) + #[inline(always)] + fn at_pointer(&self, p: &PointerNode) -> Option<&Self> { + match p { + PointerNode::Key(key) => self.get_key(key), + PointerNode::Index(index) => self.get_index(*index), + } } - fn take(&mut self) -> Self { - let node = Self { - val: self.val, - typ: self.typ, - }; - self.set_null(); - node + #[inline(always)] + fn at_pointer_mut(&mut self, p: &PointerNode) -> Option<&mut Self> { + match p { + PointerNode::Key(key) => self.get_key_mut(key).map(|v| v.0), + PointerNode::Index(index) => self.get_index_mut(*index), + } } - pub(crate) fn get_index(&self, index: usize) -> Option<&Self> { - debug_assert!(self.is_array(), "{:?}", self); - if let Some(s) = self.children::() { - if index < s.len() { - return Some(&s[index]); - } + #[doc(hidden)] + #[inline] + pub fn new_bool(val: bool, share: *const Shared) -> Self { + Value { + meta: Meta::new(if val { TRUE } else { FALSE }, share), + data: Data { uval: 0 }, } - None } - pub(crate) fn get_index_mut(&mut self, index: usize) -> Option<&mut Self> { - debug_assert!(self.is_array()); - if let Some(s) = self.children_mut::() { - if index < s.len() { - return Some(&mut s[index]); - } - } - None + #[doc(hidden)] + #[inline] + pub fn new_str(val: &str, share: *const Shared) -> Self { + let mut v = Value { + meta: Meta::new(STRING, share), + // TODO: optimize + data: Data { sval: val.as_ptr() }, + }; + v.set_str_len(val.len()); + v } - pub(crate) fn get_key(&self, key: &str) -> Option<&Self> { - debug_assert!(self.is_object()); - if let Some(kv) = self.children::<(Self, Self)>() { - for (k, v) in kv { - assert!(k.is_str()); - if k.equal_str(key) { - return Some(v); - } - } - } - None + #[doc(hidden)] + #[inline] + pub fn copy_str(src: &str, share: &Shared) -> Self { + let s = share.alloc.alloc_str(src); + let mut v = Value { + meta: Meta::new(STRING, share), + data: Data { sval: s.as_ptr() }, + }; + v.set_str_len(s.len()); + v } - pub(crate) fn get_key_offset(&self, key: &str) -> Option { - debug_assert!(self.is_object()); - if let Some(kv) = self.children::<(Self, Self)>() { - for (i, pair) in kv.iter().enumerate() { - debug_assert!(pair.0.is_str()); - if pair.0.equal_str(key) { - return Some(i); - } - } - } - None + // create a new owned allocator, and copied the string + #[doc(hidden)] + #[inline] + pub fn new_str_owned>(src: S) -> Self { + let shared = unsafe { &*Shared::new_ptr() }; + let s = shared.alloc.alloc_str(src.as_ref()); + let mut v = Value { + meta: Meta::new(ROOT_STRING, shared), + data: Data { sval: s.as_ptr() }, + }; + v.set_str_len(s.len()); + v } - pub(crate) fn get_key_mut(&mut self, key: &str) -> Option<&mut Self> { - if let Some(kv) = self.children_mut::<(Self, Self)>() { - for (k, v) in kv.iter_mut() { - debug_assert!(k.is_str()); - if k.equal_str(key) { - return Some(v); - } - } + #[doc(hidden)] + pub fn new_object(share: *const Shared, capacity: usize) -> Self { + let mut object = Value { + meta: Meta::new(OBJECT, share), + data: Data { + achildren: std::ptr::null_mut(), + }, + }; + if capacity == 0 { + return object; } - None + object.reserve::(capacity); + object } - #[inline(always)] - fn at_pointer(&self, p: &PointerNode) -> Option<&Self> { - match p { - PointerNode::Key(key) => self.get_key(key), - PointerNode::Index(index) => self.get_index(*index), + pub(crate) fn check_shared(&mut self) -> &Shared { + debug_assert!(self.is_container() || self.is_str()); + if self.is_static() { + self.mark_shared(Shared::new_ptr()); } + self.shared() } - #[inline(always)] - fn at_pointer_mut(&mut self, p: &PointerNode) -> Option<&mut Self> { - match p { - PointerNode::Key(key) => self.get_key_mut(key), - PointerNode::Index(index) => self.get_index_mut(*index), - } + pub(crate) fn shared(&self) -> &Shared { + let addr = self.meta.ptr(); + debug_assert!(!addr.is_null(), "the ptr of Shared is null"); + debug_assert!((addr as usize) % 8 == 0, "the ptr of Shared is incorrect"); + unsafe { &*addr } } - fn reserve_array(&mut self, additional: usize, alloc: &'dom Bump) { - debug_assert!(self.is_array()); - let new_cap = self.len() + additional; - if new_cap > self.capacity() { - let children = alloc.alloc_slice_fill_default(new_cap + Self::MEAT_NODE_COUNT); - if self.capacity() == 0 { - let first = MetaNode::from_nodes(children); - first.cap = new_cap as u64; - self.set_meta_ptr(first); - return; - } - let old = self.children::().unwrap(); - unsafe { - let src = old.as_ptr(); - let dst = - children[Self::MEAT_NODE_COUNT..old.len() + Self::MEAT_NODE_COUNT].as_mut_ptr(); - let count = self.len(); - std::ptr::copy_nonoverlapping(src, dst, count); - } - let first = MetaNode::from_nodes(children); - first.cap = new_cap as u64; - self.set_meta_ptr(first); - } + #[inline] + pub(crate) fn arc_shared(&self) -> Arc { + let addr = self.meta.ptr(); + debug_assert!(!addr.is_null(), "the ptr of Shared is null"); + debug_assert!((addr as usize) % 8 == 0, "the ptr of Shared is incorrect"); + unsafe { Arc::from_raw(addr) } } - fn reserve_object(&mut self, additional: usize, alloc: &'dom Bump) { - debug_assert!(self.is_object()); - let new_cap = self.len() + additional; - if new_cap > self.capacity() { - let children: &mut [Value] = - alloc.alloc_slice_fill_default(new_cap * 2 + Self::MEAT_NODE_COUNT); - if self.capacity() == 0 { - let first = MetaNode::from_nodes(children); - first.cap = new_cap as u64; - self.set_meta_ptr(first); - return; - } - let old = self.children::<(Self, Self)>().unwrap(); - let len = old.len() * 2; - let old = unsafe { from_raw_parts(old.as_ptr() as *const Value, len) }; - unsafe { - let src = old.as_ptr(); - let dst = - children[Self::MEAT_NODE_COUNT..old.len() + Self::MEAT_NODE_COUNT].as_mut_ptr(); - std::ptr::copy_nonoverlapping(src, dst, len); - } - let first = MetaNode::from_nodes(children); - first.cap = new_cap as u64; - self.set_meta_ptr(first); - } + #[inline] + pub(crate) fn shared_clone(&self) -> Arc { + let addr = self.meta.ptr(); + debug_assert!(!addr.is_null(), "the ptr of Shared is null"); + debug_assert!((addr as usize) % 8 == 0, "the ptr of Shared is incorrect"); + unsafe { Arc::clone_from_raw(addr) } } - fn set_meta_ptr(&mut self, first: &mut MetaNode) { - self.val.first = unsafe { NonNull::new_unchecked(first) }; + /// node is flat, such as null, true, false, number and new empty array or object + #[doc(hidden)] + #[inline] + pub fn is_static(&self) -> bool { + self.meta.ptr().is_null() } - fn equal_str(&self, val: &str) -> bool { - debug_assert!(self.is_str()); - self.str().len() == val.len() && self.str() == val + pub(crate) fn is_container(&self) -> bool { + self.is_array() || self.is_object() } - pub(crate) fn len(&self) -> usize { - debug_assert!(self.is_object() || self.is_str() || self.is_array()); - self.typ.0 as usize >> 8 + #[doc(hidden)] + #[inline] + pub fn mark_shared(&mut self, shared: *const Shared) { + self.meta.set_ptr(shared); } - fn has_children(&self) -> bool { - unsafe { self.val.uval != 0 } + pub(crate) fn shared_parts(&self) -> *const Shared { + self.meta.ptr() } - fn capacity(&self) -> usize { - debug_assert!(self.is_object() || self.is_array()); - if self.has_children() { - let first = unsafe { self.val.first.as_ref() }; - first.cap as usize - } else { - 0 + unsafe fn raw_allocator(&self) -> &Bump { + unsafe { &*self.shared().alloc.0.data_ptr() } + } + + pub(crate) fn get_index(&self, index: usize) -> Option<&Self> { + debug_assert!(self.is_array(), "{:?}", self); + if let Some(s) = self.children::() { + if index < s.len() { + return Some(&s[index]); + } } + None } - fn append_array(&mut self, node: Self, alloc: &'dom Bump) { - self.reserve_array(1, alloc); - debug_assert!(self.capacity() > self.len()); - let children = self.children_mut_unchecked::(); - let len = children.len(); + pub(crate) fn get_index_mut(&mut self, index: usize) -> Option<&mut Self> { + debug_assert!(self.is_array()); + if let Some(s) = self.children_mut::() { + if index < s.len() { + return Some(&mut s[index]); + } + } + None + } + + #[inline] + pub(crate) fn set_str_len(&mut self, len: usize) { + // check length and the exisit ptr is valid unsafe { - *children.as_mut_ptr().add(len) = node; + debug_assert!(len < crate::value::MAX_STR_SIZE); + debug_assert!(self.meta.val >> 48 == 0); + debug_assert!(self.data.uval >> 48 == 0); + let hi = len >> 16; + let lo = len & 0xFFFF; + self.meta.val |= (hi as u64) << 48; + self.data.uval |= (lo as u64) << 48; } - self.add_len(1); } - pub(crate) fn append_object(&mut self, pair: (Self, Self), alloc: &'dom Bump) -> &mut Self { - self.reserve_object(1, alloc); - let children = self.children_mut_unchecked::<(Self, Self)>(); - let len = children.len(); - let ret = unsafe { - let ptr = children.as_mut_ptr().add(len); - *ptr = pair; - &mut (*ptr).1 - }; - self.add_len(1); - ret + #[inline] + pub(crate) fn get_key(&self, key: &str) -> Option<&Self> { + self.get_key_value(key).map(|(_, v)| v) } - fn remove_in_object(&mut self, k: &str) -> Option { + pub(crate) fn get_key_value(&self, key: &str) -> Option<(&str, &Self)> { debug_assert!(self.is_object()); - if let Some(i) = self.get_key_offset(k) { - let children = self.children_mut_unchecked::<(Self, Self)>(); - let node = (children[i].0.take(), children[i].1.take()); - // move the later nodes to first - let len: usize = children.len(); - unsafe { - let dst = children.as_mut_ptr().add(i); - let src = children.as_ptr().add(i + 1); - - let size = (len - i - 1) * size_of::(); - std::ptr::copy(src, dst, size); + if let Some(kv) = self.children::<(Self, Self)>() { + for (k, v) in kv { + let k = k.as_str().expect("key is not string"); + if k == key { + return Some((k, v)); + } } - self.add_len(-1); - Some(node.1) - } else { - None } + None } - // if object, return as a doubled size slice pub(crate) fn children(&self) -> Option<&[T]> { if self.has_children() { Some(self.children_unchecked::()) @@ -739,309 +905,387 @@ impl<'dom> Value<'dom> { } } - fn children_unchecked(&self) -> &[T] { - unsafe { - let start = self.val.nptr.as_ptr().add(Self::MEAT_NODE_COUNT); - let ptr = start as *const T; - let len = self.len(); - from_raw_parts(ptr, len) + pub(crate) unsafe fn children_ptr(&self) -> *const T { + if self.has_children() { + self.data.achildren.add(Self::MEAT_NODE_COUNT).cast() + } else { + NonNull::::dangling().as_ptr() } } - fn children_mut(&mut self) -> Option<&mut [T]> { + #[inline] + pub(crate) unsafe fn children_mut_ptr(&mut self) -> *mut T { if self.has_children() { - Some(self.children_mut_unchecked::()) + self.data.achildren.add(Self::MEAT_NODE_COUNT).cast() } else { - None + NonNull::::dangling().as_ptr() } } - fn children_mut_unchecked(&mut self) -> &mut [T] { + #[inline] + fn children_unchecked(&self) -> &[T] { unsafe { - let start = self.val.nptr.as_ptr().add(Self::MEAT_NODE_COUNT); - let ptr = start as *mut T; + let start = self.data.achildren.add(Self::MEAT_NODE_COUNT); + let ptr = start as *const T; let len = self.len(); - from_raw_parts_mut(ptr, len) + from_raw_parts(ptr, len) } } - fn str(&self) -> &str { - debug_assert!(self.typ() == Self::STRING); - let s = unsafe { - let ptr = self.val.own_ptr; + #[inline] + fn children_unchecked_mut(&mut self) -> &mut [T] { + unsafe { + let start = self.data.achildren.add(Self::MEAT_NODE_COUNT); + let ptr = start as *mut T; let len = self.len(); - let slice = std::slice::from_raw_parts(ptr, len); - std::str::from_utf8_unchecked(slice) - }; - s - } - - fn array(&self) -> &[Self] { - if self.len() == 0 { - return &[]; + from_raw_parts_mut(ptr, len) } - let slice = unsafe { - let ptr = self.val.nptr; - let len = self.len(); - // add 1 to skip the metanode - std::slice::from_raw_parts(ptr.as_ptr().add(1), len) - }; - slice } - fn object(&self) -> &[(Self, Self)] { - if self.len() == 0 { - return &[]; + #[inline] + pub(crate) fn get_key_offset(&self, key: &str) -> Option { + debug_assert!(self.is_object()); + if let Some(kv) = self.children::<(Self, Self)>() { + for (i, pair) in kv.iter().enumerate() { + debug_assert!(pair.0.is_str()); + if pair.0.equal_str(key) { + return Some(i); + } + } } - let slice = unsafe { - let ptr = self.val.nptr.as_ptr().add(1); - let len = self.len(); - // add 1 to skip the metanode - std::slice::from_raw_parts(ptr as *const (Self, Self), len) - }; - slice - } - - fn set_null(&mut self) { - self.typ.0 = Self::NULL; - } - - fn set_len(&mut self, len: usize) { - debug_assert!(self.len() == 0); - self.typ.0 |= (len as u64) << Self::LEN_BITS; + None } - fn add_len(&mut self, inc: isize) { - if inc > 0 { - self.typ.0 += (inc as u64) << Self::LEN_BITS; - } else { - self.typ.0 -= ((-inc) as u64) << Self::LEN_BITS; + #[inline] + pub(crate) fn get_key_mut(&mut self, key: &str) -> Option<(&mut Self, usize)> { + if let Some(kv) = self.children_mut::<(Self, Self)>() { + for (i, (k, v)) in kv.iter_mut().enumerate() { + debug_assert!(k.is_str()); + if k.equal_str(key) { + return Some((v, i)); + } + } } + None } - fn set_bool(&mut self, val: bool) { - if val { - self.typ.0 = Self::TRUE; - } else { - self.typ.0 = Self::FALSE; + #[inline] + pub(crate) fn insert_value(&mut self, index: usize, src: Value) { + debug_assert!(self.is_array()); + self.reserve::(1); + let children = self.children_mut_unchecked::>(); + let len = children.len(); + assert!( + index <= children.len(), + "index({}) should <= len({})", + index, + len + ); + if index < len { + unsafe { + std::ptr::copy( + children.as_ptr().add(index), + children.as_mut_ptr().add(index + 1), + len - index, + ); + } + } + unsafe { + let dst = &mut *children.as_mut_ptr().add(index); + write_value(dst, src, self.shared()); + self.add_len(1); } } - fn i64(&self) -> i64 { - unsafe { self.val.ival } - } - - fn u64(&self) -> u64 { - unsafe { self.val.uval } + #[inline] + fn equal_str(&self, val: &str) -> bool { + debug_assert!(self.is_str()); + self.str().len() == val.len() && self.str() == val } - fn f64(&self) -> f64 { - unsafe { self.val.fval } + #[inline] + pub(crate) fn capacity(&self) -> usize { + debug_assert!(self.is_object() || self.is_array()); + if self.has_children() { + unsafe { self.data.info.as_ref().cap as usize } + } else { + 0 + } } -} - -struct MetaNode { - cap: u64, - _remain: u64, -} -impl MetaNode { - fn from_nodes<'dom>(slice: &'dom mut [Value]) -> &'dom mut Self { - debug_assert!(slice.len() >= Value::MEAT_NODE_COUNT); - unsafe { &mut *(slice.as_mut_ptr() as *mut MetaNode) } + #[inline] + fn allocator(&self) -> &SyncBump { + &self.shared().alloc } -} - -struct ValueInner { - _typ: u64, - _val: u64, -} -pub struct Document { - root: ValueInner, - alloc: Bump, -} + #[inline] + pub(crate) fn clear(&mut self) { + debug_assert!(self.is_object() || self.is_array()); -unsafe impl Send for Document {} + if self.is_empty() { + return; + } -impl std::fmt::Debug for Document { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.as_value().fmt(f) + // we need traverse the tree to drop the children + if self.shared().is_combined() { + if self.is_array() { + for child in self.children_mut_unchecked::() { + child.drop_slow(); + } + } else if self.is_object() { + for child in self.children_mut_unchecked::<(Value, Value)>() { + child.0.drop_slow(); + child.1.drop_slow(); + } + } + } + unsafe { self.set_len(0) } } -} -impl Default for Document { - fn default() -> Self { - Self::new() + #[inline] + pub(crate) fn remove_index(&mut self, index: usize) -> Value { + debug_assert!(self.is_array()); + let children = self.children_mut_unchecked::(); + let len = children.len(); + assert!( + index < len, + "remove index({}) should be < len({})", + index, + len + ); + let val = children[index].take(); + unsafe { + std::ptr::copy_nonoverlapping( + children.as_ptr().add(index + 1), + children.as_mut_ptr().add(index), + len - index - 1, + ); + } + self.add_len(-1); + val } -} - -/// Parse a json into a document. -pub fn dom_from_str(json: &str) -> Result { - let mut dom = Document::new(); - dom.parse_bytes_impl(json.as_bytes())?; - Ok(dom) -} - -/// Parse a json into a document. -/// -/// If the json is valid utf-8, recommend to use `dom_from_slice_unchecked` instead. -pub fn dom_from_slice(json: &[u8]) -> Result { - // validate the utf-8 at first for slice - let json = { - let json = from_utf8(json)?; - json.as_bytes() - }; - let mut dom = Document::new(); - dom.parse_bytes_impl(json)?; - Ok(dom) -} - -/// Parse a json into a document. -/// -/// # Safety -/// The json must be valid utf-8. -pub unsafe fn dom_from_slice_unchecked(json: &[u8]) -> Result { - let mut dom = Document::new(); - dom.parse_bytes_impl(json)?; - Ok(dom) -} - -/// ValueMut is a mutable reference to a `Value`. -#[derive(Debug)] -pub struct ValueMut<'dom> { - val: &'dom mut Value<'dom>, - alloc: &'dom Bump, -} - -impl<'d> JsonValue for ValueMut<'d> { - type ValueType<'dom> = &'dom Value<'dom> where Self: 'dom; - - fn as_bool(&self) -> Option { - self.val.as_bool() - } + #[inline] + pub(crate) fn remove_pair_index(&mut self, index: usize) -> (Value, Value) { + debug_assert!(self.is_object()); + let children = self.children_mut_unchecked::(); + let len = children.len(); + assert!( + index < len, + "remove index({}) should be < len({})", + index, + len + ); - fn as_number(&self) -> Option { - self.val.as_number() + // key is always not a root, ignored it + let children = self.children_mut_unchecked::<(Self, Self)>(); + // key will be dropped + let key = children[index].0.take(); + let val = children[index].1.take(); + unsafe { + let dst = children.as_mut_ptr().add(index); + let src = children.as_ptr().add(index + 1); + let size = len - index - 1; + std::ptr::copy(src, dst, size); + } + self.add_len(-1); + (key, val) } - fn get_type(&self) -> JsonType { - self.val.get_type() + #[inline] + pub(crate) fn remove_key(&mut self, k: &str) -> Option { + debug_assert!(self.is_object()); + if let Some(i) = self.get_key_offset(k) { + let (_, val) = self.remove_pair_index(i); + Some(val) + } else { + None + } } - fn as_str(&self) -> Option<&str> { - self.val.as_str() + pub(crate) fn iter(&self) -> std::slice::Iter<'_, T> { + self.children::().unwrap_or(&[]).iter() } - fn get(&'_ self, index: I) -> Option> { - index.value_index_into(self.val) + pub(crate) fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { + self.children_mut::().unwrap_or(&mut []).iter_mut() } - fn pointer(&'_ self, path: &JsonPointer) -> Option> { - self.val.pointer(path) + /// Take the value from the node, and set the node as a empty node. + /// Take will creat a new root node. + /// + /// # Examples + /// ``` + /// use sonic_rs::json; + /// use sonic_rs::JsonValueTrait; + /// + /// let mut value = json!({"a": 123}); + /// assert_eq!(value.take()["a"], 123); + /// assert!(value.is_null()); + /// + /// let mut value = json!(null); + /// assert!(value.take().is_null()); + /// assert!(value.is_null()); + /// ``` + #[inline] + pub fn take(&mut self) -> Self { + replace_value(self, Value::default()) } -} -impl<'dom> ValueMut<'dom> { - pub fn allocator(&self) -> &'dom Bump { - self.alloc + #[inline] + pub(crate) unsafe fn set_len(&mut self, len: usize) { + debug_assert!(self.is_object() || self.is_array()); + let meta = unsafe { self.data.info.as_mut() }; + meta.len = len as u64; } - pub fn into_object_mut(self) -> Option> { - if self.is_object() { - Some(ObjectMut(self)) - } else { - None + #[inline] + pub(crate) fn grow(&mut self, capacity: usize) { + if self.is_static() { + self.mark_shared(Shared::new_ptr()); + self.mark_root(); } - } + let old = self.children::(); + let nodes = capacity * (size_of::() / size_of::()) + Self::MEAT_NODE_COUNT; + let new_buffer: *mut Value = self.allocator().alloc_slice(nodes).as_mut_ptr(); - pub fn into_array_mut(self) -> Option> { - if self.is_array() { - Some(ArrayMut(self)) - } else { - None + if let Some(children) = old { + unsafe { + let src = children.as_ptr(); + let dst: *mut T = new_buffer.add(Self::MEAT_NODE_COUNT).cast(); + std::ptr::copy_nonoverlapping(src, dst, children.len()); + } } + + // set the capacity and length + let first: &mut MetaNode = unsafe { &mut *new_buffer.cast() }; + first.cap = capacity as u64; + first.len = old.map_or(0, |s| s.len()) as u64; + self.data.achildren = new_buffer.cast(); } - pub fn pointer_mut(&'dom mut self, path: &JsonPointer) -> Option> { - if let Some(val) = self.val.pointer_mut(path) { - Some(Self { - val, - alloc: self.alloc, - }) + #[inline] + pub(crate) fn reserve(&mut self, additional: usize) { + debug_assert!(self.is_object() || self.is_array()); + debug_assert!(size_of::() == size_of::() || size_of::() == size_of::()); + + let cur_cap = self.capacity(); + let required_cap = self + .len() + .checked_add(additional) + .expect("capacity overflow"); + let default_cap = if size_of::() == size_of::() { + super::array::DEFAULT_ARRAY_CAP } else { - None + super::object::DEFAULT_OBJ_CAP + }; + + if required_cap > self.capacity() { + let cap = std::cmp::max(cur_cap * 2, required_cap); + let cap = std::cmp::max(default_cap, cap); + self.grow::(cap); } } - pub fn get_mut(&'dom mut self, index: I) -> Option> { - if let Some(val) = index.index_into_mut(self.val) { - Some(Self { - val, - alloc: self.alloc, - }) - } else { - None - } + #[doc(hidden)] + #[inline] + pub fn append_value(&mut self, val: Value) -> &mut Value { + debug_assert!(self.is_array()); + self.reserve::(1); + + let children = self.children_mut_unchecked::>(); + let len = children.len(); + let end = unsafe { &mut *children.as_mut_ptr().add(len) }; + write_value(end, val, self.shared()); + self.add_len(1); + let ret = unsafe { end.assume_init_mut() }; + ret } - pub fn take(&mut self) -> Value<'dom> { - self.val.take() + #[doc(hidden)] + #[inline] + pub fn append_pair(&mut self, pair: Pair) -> &mut Pair { + debug_assert!(self.is_object()); + self.reserve::(1); + + let children = self.children_mut_unchecked::<(MaybeUninit, MaybeUninit)>(); + let len = children.len(); + + let end_key = unsafe { &mut (*children.as_mut_ptr().add(len)).0 }; + let end_value = unsafe { &mut (*children.as_mut_ptr().add(len)).1 }; + write_value(end_key, pair.0, self.shared()); + write_value(end_value, pair.1, self.shared()); + self.add_len(1); + unsafe { &mut *(end_key as *mut _ as *mut Pair) } } -} -impl Document { - const PADDING_SIZE: usize = 64; + fn add_len(&mut self, additional: isize) { + debug_assert!(self.is_array() || self.is_object()); + let meta = unsafe { self.data.info.as_mut() }; + meta.len = (meta.len as isize + additional) as u64; + } - pub fn new() -> Document { - Self { - alloc: Bump::new(), - root: ValueInner { _typ: 0, _val: 0 }, + #[inline] + pub(crate) fn pop(&mut self) -> Option { + debug_assert!(self.is_array()); + if self.is_empty() { + return None; } - } - pub fn as_value(&self) -> &Value { - unsafe { transmute(&self.root) } + let children = self.children_mut_unchecked::(); + let len = children.len(); + let val = children[len - 1].take(); + self.add_len(-1); + Some(val) } - pub fn as_value_mut(&'_ mut self) -> ValueMut<'_> { - ValueMut { - val: unsafe { transmute(&mut self.root) }, - alloc: &self.alloc, + #[inline] + pub(crate) fn pop_pair(&mut self) -> Option { + debug_assert!(self.is_object()); + if self.is_empty() { + return None; } + + let children = self.children_mut_unchecked::(); + let len = children.len(); + let pair = (children[len - 1].0.take(), children[len - 1].1.take()); + self.add_len(-1); + Some(pair) + } + + #[inline] + fn has_children(&self) -> bool { + unsafe { self.data.achildren as usize != 0 } } - pub fn as_array_mut(&'_ mut self) -> Option> { - if self.as_value().is_array() { - Some(ArrayMut(ValueMut { - val: unsafe { transmute(&mut self.root) }, - alloc: &self.alloc, - })) + #[inline] + pub(crate) fn children_mut(&mut self) -> Option<&mut [T]> { + if self.has_children() { + Some(self.children_mut_unchecked::()) } else { None } } - pub fn as_object_mut(&'_ mut self) -> Option> { - if self.as_value().is_object() { - Some(ObjectMut(ValueMut { - val: unsafe { transmute(&mut self.root) }, - alloc: &self.alloc, - })) - } else { - None + #[inline] + fn children_mut_unchecked(&mut self) -> &mut [T] { + unsafe { + let start = self.data.achildren.add(Self::MEAT_NODE_COUNT); + let ptr = start as *mut T; + let len = self.len(); + from_raw_parts_mut(ptr, len) } } - fn parse_bytes_impl(&mut self, json: &[u8]) -> Result<()> { - let alloc = &self.alloc; + #[inline(never)] + pub(crate) fn parse_with_padding(&mut self, json: &[u8]) -> Result { + let alloc = unsafe { self.raw_allocator() }; let len = json.len(); // allocate the padding buffer for the input json let real_size = len + Self::PADDING_SIZE; let layout = Layout::array::(real_size).map_err(Error::custom)?; - let dst = alloc.try_alloc_layout(layout).map_err(Error::custom)?; + let dst = alloc.alloc_layout(layout); let json_buf = unsafe { let dst = dst.as_ptr(); std::ptr::copy_nonoverlapping(json.as_ptr(), dst, len); @@ -1050,274 +1294,404 @@ impl Document { *(dst.add(len)) = b'x'; *(dst.add(len + 1)) = b'"'; *(dst.add(len + 2)) = b'x'; - std::slice::from_raw_parts_mut(dst, len + Self::PADDING_SIZE) }; - let slice = UncheckedSliceRead::new(json_buf); + let slice = PaddedSliceRead::new(json_buf); let mut parser = Parser::new(slice); - // a simple wrapper for visitor - #[derive(Debug)] - struct DocumentVisitor<'a> { - alloc: &'a Bump, - nodes: Vec>, - parent: usize, - } - - impl<'a> DocumentVisitor<'a> { - // the array and object's logic is same. - fn visit_container(&mut self, len: usize) -> bool { - let visitor = self; - let alloc = visitor.alloc; - let parent = visitor.parent; - let old = unsafe { visitor.nodes[parent].val.parent as usize }; - visitor.parent = old; - if len > 0 { - unsafe { - let visited_children = &visitor.nodes[(parent + 1)..]; - let real_count = visited_children.len() + Value::MEAT_NODE_COUNT; - let layout = { - if let Ok(layout) = Layout::array::(real_count) { - layout - } else { - return false; - } - }; - let mut children = { - if let Ok(c) = alloc.try_alloc_layout(layout) { - c - } else { - return false; - } - }; - - // copy visited nodes into document - let src = visited_children.as_ptr(); - let dst = children.as_ptr() as *mut Value; - let dst = dst.add(Value::MEAT_NODE_COUNT); - std::ptr::copy_nonoverlapping(src, dst, visited_children.len()); - - // set the capacity and length - let meta = &mut *(children.as_mut() as *mut _ as *mut MetaNode); - meta.cap = len as u64; - let container = &mut visitor.nodes[parent]; - container.set_len(len); - container.val.nptr = - NonNull::new_unchecked(children.as_mut() as *mut _ as *mut Value); - - // must reset the length, because we copy the children into bumps - visitor.nodes.set_len(parent + 1); - } - } - true + // optimize: use a pre-allocated vec. + // If json is valid, the max number of value nodes should be + // half of the valid json length + 2. like as [1,2,3,1,2,3...] + // if the capacity is not enough, we will return a error. + let nodes = NODE_BUF.with(|buf| { + let mut nodes = buf.borrow_mut(); + nodes.clear(); + nodes.reserve((json.len() / 2) + 2); + unsafe { + let ptr = (&mut *nodes) as *mut Vec>; + &mut *ptr } + }); - fn push_node(&mut self, node: Value<'static>) -> bool { - if self.nodes.len() == self.nodes.capacity() { - false - } else { - self.nodes.push(node); - true - } + let mut visitor = DocumentVisitor { + shared: unsafe { &*(self.shared() as *const Shared) }, + nodes: nodes.into(), + parent: 0, + }; + parser.parse_value_with_padding(&mut visitor)?; + self.data = visitor.nodes()[0].data; + self.meta = visitor.nodes()[0].meta; + self.mark_root(); + Ok(parser.read.index()) + } + + #[inline(never)] + pub(crate) fn parse_without_padding<'de, R: Reader<'de>>( + &mut self, + parser: &mut Parser, + ) -> Result<()> { + let remain_len = parser.read.remain(); + let nodes = NODE_BUF.with(|buf| { + let mut nodes = buf.borrow_mut(); + nodes.clear(); + nodes.reserve((remain_len / 2) + 2); + unsafe { + let ptr = (&mut *nodes) as *mut Vec>; + &mut *ptr } + }); + + let mut visitor = DocumentVisitor { + shared: unsafe { &*(self.shared() as *const Shared) }, + nodes: nodes.into(), + parent: 0, + }; + parser.parse_value_without_padding(&mut visitor)?; + self.data = visitor.nodes()[0].data; + self.meta = visitor.nodes()[0].meta; + self.mark_root(); + Ok(()) + } + + fn typ(&self) -> u64 { + self.meta.tag() + } + + fn i64(&self) -> i64 { + unsafe { self.data.ival } + } + + fn u64(&self) -> u64 { + unsafe { self.data.uval } + } + + fn f64(&self) -> f64 { + unsafe { self.data.fval } + } + + fn str(&self) -> &str { + unsafe { + let ptr = (self.data.uval & STR_PTR_MASK) as *const u8; + let len = self.str_len(); + let slice = std::slice::from_raw_parts(ptr, len); + from_utf8_unchecked(slice) } + } - impl<'de, 'a: 'de> JsonVisitor<'de> for DocumentVisitor<'a> { - #[inline(always)] - fn visit_bool(&mut self, val: bool) -> bool { - self.push_node(Value::new_bool(val)) - } + pub(crate) fn str_len(&self) -> usize { + debug_assert!(self.is_str()); + unsafe { + let hi = (self.meta.val >> 48) as usize; + let lo = (self.data.uval >> 48) as usize; + hi << 16 | lo + } + } - #[inline(always)] - fn visit_f64(&mut self, val: f64) -> bool { - // # Safety - // we have checked the f64 in parsing number. - let node = unsafe { Value::new_f64_unchecked(val) }; - self.push_node(node) + pub(crate) fn len(&self) -> usize { + unsafe { + if (self.data.achildren as usize) == 0 { + return 0; } + self.data.info.as_ref().len as usize + } + } - #[inline(always)] - fn visit_i64(&mut self, val: i64) -> bool { - self.push_node(Value::new_i64(val)) - } + pub(crate) fn is_empty(&self) -> bool { + self.len() == 0 + } - #[inline(always)] - fn visit_u64(&mut self, val: u64) -> bool { - self.push_node(Value::new_u64(val)) - } + fn array(&self) -> &[Value] { + if self.is_empty() { + return &[]; + } + unsafe { + let children = self.data.achildren; + let meta = &*(children as *const MetaNode); + from_raw_parts(children.add(Value::MEAT_NODE_COUNT), meta.len as usize) + } + } - #[inline(always)] - fn visit_array_start(&mut self, _hint: usize) -> bool { - let ret = self.push_node(Value::new_array()); - // record the parent container position - let len = self.nodes.len(); - self.nodes[len - 1].val.parent = self.parent as u64; - self.parent = len - 1; - ret - } + fn object(&self) -> &[(Value, Value)] { + if self.is_empty() { + return &[]; + } + unsafe { + let children = self.data.achildren; + let meta = &*(children as *const MetaNode); + from_raw_parts( + children.add(Value::MEAT_NODE_COUNT) as *mut Pair, + meta.len as usize, + ) + } + } - #[inline(always)] - fn visit_array_end(&mut self, len: usize) -> bool { - self.visit_container(len) - } + #[inline] + pub(crate) fn state(&mut self) -> ValueState<'_> { + if self.is_static() { + ValueState::Static(self) + } else if self.is_root() { + ValueState::Root(self) + } else if self.is_inlined() { + ValueState::Inlined(self) + } else { + ValueState::Shared(self) + } + } +} - #[inline(always)] - fn visit_object_start(&mut self, _hint: usize) -> bool { - let ret = self.push_node(Value::new_object()); - let len = self.nodes.len(); - self.nodes[len - 1].val.parent = self.parent as u64; - self.parent = len - 1; - ret - } +pub(crate) enum ValueState<'a> { + // Value without a shared allocator + Static(&'a mut Value), + // Value with a share allocator + Shared(&'a mut Value), + // Value is root and with a owned allocator + Root(&'a mut Value), + // Value is static but is a children and with shared allocator ptr + Inlined(&'a mut Value), +} - #[inline(always)] - fn visit_object_end(&mut self, len: usize) -> bool { - self.visit_container(len) - } +#[derive(Default, Debug)] +pub(crate) struct OwnedValue(Value); - #[inline(always)] - fn visit_null(&mut self) -> bool { - self.push_node(Value::new_uinit()) - } +impl From for Value { + #[inline] + fn from(v: OwnedValue) -> Self { + v.0 + } +} - #[inline(always)] - fn visit_str(&mut self, value: &str) -> bool { - let alloc = self.alloc; - let value = alloc.alloc_str(value); - self.push_node(Value::new_str_borrow(value)) - } +// Replace dst with a new `OwnedValue`, and return the old `Value` as a `OwnedValue`. +#[inline] +pub(crate) fn replace_value(dst: &mut Value, mut src: Value) -> Value { + match dst.state() { + ValueState::Static(dst) => { + let old = std::mem::replace(dst, src); + return old; + } + ValueState::Shared(_) | ValueState::Inlined(_) => {} + ValueState::Root(dst) => return std::mem::replace(dst, src), + } - #[inline(always)] - fn visit_borrowed_str(&mut self, value: &'de str) -> bool { - self.push_node(Value::new_str_borrow(value)) + let dst_shared = dst.shared(); + match src.state() { + ValueState::Static(src) | ValueState::Inlined(src) => { + src.mark_shared(dst_shared); + } + ValueState::Root(src) => { + if std::ptr::eq(src.shared_parts(), dst_shared) { + drop(src.arc_shared()); + src.unmark_root(); + } else { + dst_shared.set_combined(); } + } + ValueState::Shared(_) => unreachable!("should not be shared"), + } - #[inline(always)] - fn visit_key(&mut self, key: &str) -> bool { - self.visit_str(key) - } + // make old from `Shared` into `Owned` + let mut old = std::mem::replace(dst, src); + old.mark_root(); + if old.is_root() { + std::mem::forget(old.shared_clone()); + } + old +} - #[inline(always)] - fn visit_borrowed_key(&mut self, key: &'de str) -> bool { - self.visit_borrowed_str(key) +// Write dst with a new `OwnedValue`. The dst is a uninitialized value and should not be drop. +// The uninitialized value is allocated in the `shared` allocator. +#[inline] +pub(crate) fn write_value(dst: &mut MaybeUninit, mut src: Value, shared: &Shared) { + match src.state() { + ValueState::Static(sv) => { + sv.mark_shared(shared); + dst.write(src); + } + ValueState::Root(sv) => { + if std::ptr::eq(sv.shared_parts(), shared) { + sv.unmark_root(); + drop(sv.arc_shared()); + } else { + shared.set_combined(); } + dst.write(src); + } + ValueState::Shared(sv) | ValueState::Inlined(sv) => { + assert!( + std::ptr::eq(sv.shared_parts(), shared), + "should be same allocator" + ); + dst.write(src); } - - let alloc = &self.alloc; - // optimize: use a pre-allocated vec. - // If json is valid, the max number of value nodes should be - // half of the valid json length + 2. like as [1,2,3,1,2,3...] - // if the capacity is not enough, we will return a error. - let nodes = Vec::with_capacity((json.len() / 2) + 2); - let parent = 0; - let mut visitor = DocumentVisitor { - alloc, - nodes, - parent, - }; - parser.parse_value_goto(&mut visitor)?; - // check trailing spaces - parser.parse_trailing()?; - self.root = unsafe { transmute(visitor.nodes[0].take()) }; - Ok(()) } } -impl JsonValue for Document { - type ValueType<'dom> = &'dom Value<'dom> where Self: 'dom; +// a simple wrapper for visitor +pub(crate) struct DocumentVisitor<'a> { + pub(crate) shared: &'a Shared, + pub(crate) nodes: NonNull>>, + pub(crate) parent: usize, +} - fn get_type(&self) -> JsonType { - self.as_value().get_type() +impl<'a> DocumentVisitor<'a> { + // the array and object's logic is same. + fn visit_container(&mut self, len: usize) -> bool { + let visitor = self; + let alloc = unsafe { &*visitor.shared.alloc.0.data_ptr() }; + let parent = visitor.parent; + let old = unsafe { visitor.nodes()[parent].data.parent as usize }; + visitor.parent = old; + if len == 0 { + let container = &mut visitor.nodes()[parent]; + container.data.achildren = std::ptr::null_mut(); + return true; + } + unsafe { + let visited_children = &visitor.nodes()[(parent + 1)..]; + let real_count = visited_children.len() + Value::MEAT_NODE_COUNT; + let layout = { + if let Ok(layout) = Layout::array::(real_count) { + layout + } else { + return false; + } + }; + let mut children = alloc.alloc_layout(layout); + // copy visited nodes into document + let src = visited_children.as_ptr(); + let dst = children.as_ptr() as *mut ManuallyDrop; + let dst = dst.add(Value::MEAT_NODE_COUNT); + std::ptr::copy_nonoverlapping(src, dst, visited_children.len()); + + // set the capacity and length + let meta = &mut *(children.as_mut() as *mut _ as *mut MetaNode); + meta.cap = len as u64; + meta.len = len as u64; + let container = &mut visitor.nodes()[parent]; + container.data.achildren = children.as_mut() as *mut _ as *mut Value; + // must reset the length, because we copy the children into bumps + visitor.nodes().set_len(parent + 1); + } + true } - fn as_bool(&self) -> Option { - self.as_value().as_bool() + #[inline(always)] + fn push_node(&mut self, node: Value) -> bool { + if self.nodes().len() == self.nodes().capacity() { + false + } else { + self.nodes().push(ManuallyDrop::new(node)); + true + } } - fn as_number(&self) -> Option { - self.as_value().as_number() + #[inline(always)] + fn shared(&self) -> *const Shared { + self.shared } - fn as_str(&self) -> Option<&str> { - self.as_value().as_str() + #[inline(always)] + fn nodes(&mut self) -> &mut Vec> { + unsafe { self.nodes.as_mut() } } +} - fn get(&self, index: I) -> Option> { - self.as_value().get(index) +impl<'de, 'a: 'de> JsonVisitor<'de> for DocumentVisitor<'a> { + #[inline(always)] + fn visit_bool(&mut self, val: bool) -> bool { + self.push_node(Value::new_bool(val, self.shared as *const _)) } - fn pointer(&self, path: &JsonPointer) -> Option> { - self.as_value().pointer(path) + #[inline(always)] + fn visit_f64(&mut self, val: f64) -> bool { + // # Safety + // we have checked the f64 in parsing number. + let node = unsafe { Value::new_f64_unchecked(val, self.shared as *const _) }; + self.push_node(node) } -} -use serde::de; -use std::result::Result as StdResult; -struct DomKey; + #[inline(always)] + fn visit_i64(&mut self, val: i64) -> bool { + self.push_node(Value::new_i64(val, self.shared as *const _)) + } -pub(crate) const TOKEN: &str = "$sonic_rs::private::Document"; + #[inline(always)] + fn visit_u64(&mut self, val: u64) -> bool { + self.push_node(Value::new_u64(val, self.shared as *const _)) + } -// Serde for document -impl<'de> Deserialize<'de> for Document { - fn deserialize(deserializer: D) -> StdResult - where - D: ::serde::Deserializer<'de>, - { - struct DomVisitor; + #[inline(always)] + fn visit_array_start(&mut self, _hint: usize) -> bool { + let ret = self.push_node(Value::new_array(self.shared as *const _, 0)); + // record the parent container position + let len = self.nodes().len(); + self.nodes()[len - 1].data.parent = self.parent as u64; + self.parent = len - 1; + ret + } - impl<'de> Visitor<'de> for DomVisitor { - type Value = Document; + #[inline(always)] + fn visit_array_end(&mut self, len: usize) -> bool { + self.visit_container(len) + } - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("a valid json") - } + #[inline(always)] + fn visit_object_start(&mut self, _hint: usize) -> bool { + let ret = self.push_node(Value::new_object(self.shared as *const _, 0)); + let len = self.nodes().len(); + self.nodes()[len - 1].data.parent = self.parent as u64; + self.parent = len - 1; + ret + } - fn visit_bytes(self, dom_binary: &[u8]) -> StdResult - where - E: de::Error, - { - // we pass the document from dom_binary - unsafe { - assert!(dom_binary.len() == size_of::()); - let mut dom: MaybeUninit = MaybeUninit::zeroed(); - std::ptr::copy_nonoverlapping( - dom_binary.as_ptr() as *const Document, - dom.as_mut_ptr(), - 1, - ); - Ok(dom.assume_init()) - } - } - } + #[inline(always)] + fn visit_object_end(&mut self, len: usize) -> bool { + self.visit_container(len) + } - deserializer.deserialize_newtype_struct(TOKEN, DomVisitor) + #[inline(always)] + fn visit_null(&mut self) -> bool { + self.push_node(Value::new_null(self.shared as *const _)) } -} -impl Serialize for Document { - #[inline] - fn serialize(&self, serializer: S) -> std::result::Result - where - S: ::serde::Serializer, - { - self.as_value().serialize(serializer) + // this api should never used for parsing with padding buffer + #[inline(always)] + fn visit_str(&mut self, value: &str) -> bool { + let alloc = unsafe { &*self.shared.alloc.0.data_ptr() }; + let value = alloc.alloc_str(value); + self.push_node(Value::new_str(value, self.shared as *const _)) + } + + #[inline(always)] + fn visit_borrowed_str(&mut self, value: &'de str) -> bool { + self.push_node(Value::new_str(value, self.shared as *const _)) + } + + #[inline(always)] + fn visit_key(&mut self, key: &str) -> bool { + self.visit_str(key) + } + + #[inline(always)] + fn visit_borrowed_key(&mut self, key: &'de str) -> bool { + self.visit_borrowed_str(key) } } -impl<'dom> Serialize for Value<'dom> { + +impl Serialize for Value { #[inline] fn serialize(&self, serializer: S) -> std::result::Result where S: ::serde::Serializer, { match self.typ() { - Self::NULL => serializer.serialize_unit(), - Self::TRUE => serializer.serialize_bool(true), - Self::FALSE => serializer.serialize_bool(false), - Self::SIGNED => serializer.serialize_i64(self.i64()), - Self::UNSIGNED => serializer.serialize_u64(self.u64()), - Self::FLOAT => serializer.serialize_f64(self.f64()), - Self::STRING => serializer.serialize_str(self.str()), - Self::ARRAY => { + NULL => serializer.serialize_unit(), + TRUE => serializer.serialize_bool(true), + FALSE => serializer.serialize_bool(false), + SIGNED => serializer.serialize_i64(self.i64()), + UNSIGNED => serializer.serialize_u64(self.u64()), + FLOAT => serializer.serialize_f64(self.f64()), + STRING | ROOT_STRING => serializer.serialize_str(self.str()), + ARRAY | ROOT_ARRAY => { let nodes = self.array(); let mut seq = tri!(serializer.serialize_seq(Some(nodes.len()))); for n in nodes { @@ -1325,7 +1699,7 @@ impl<'dom> Serialize for Value<'dom> { } seq.end() } - Self::OBJECT => { + OBJECT | ROOT_OBJECT => { let entrys = self.object(); let mut map = tri!(serializer.serialize_map(Some(entrys.len()))); for (k, v) in entrys { @@ -1338,19 +1712,49 @@ impl<'dom> Serialize for Value<'dom> { } } +pub fn dom_from_slice(json: &[u8]) -> Result { + // validate the utf-8 at first for slice + let json = { + let json = from_utf8(json)?; + json.as_bytes() + }; + + let mut dom = Value::new_null(Shared::new_ptr()); + dom.parse_with_padding(json)?; + Ok(dom) +} + +pub fn dom_from_slice_unchecked(json: &[u8]) -> Result { + let mut dom = Value::new_null(Shared::new_ptr()); + dom.parse_with_padding(json)?; + Ok(dom) +} + +pub fn dom_from_str(json: &str) -> Result { + // validate the utf-8 at first for slice + let json = { + let json = from_utf8(json.as_bytes())?; + json.as_bytes() + }; + + let mut dom = Value::new_null(Shared::new_ptr()); + dom.parse_with_padding(json)?; + Ok(dom) +} + #[cfg(test)] mod test { - use super::*; + use crate::from_slice; use crate::{ error::{make_error, Result}, pointer, }; - use std::{collections::HashMap, path::Path}; + use std::path::Path; fn test_value(data: &str) -> Result<()> { let serde_value: serde_json::Result = serde_json::from_str(data); - let dom = dom_from_slice(data.as_bytes()); + let dom: Result = from_slice(data.as_bytes()); if let Ok(serde_value) = serde_value { let dom = dom.unwrap(); let sonic_out = crate::to_string(&dom)?; @@ -1379,7 +1783,7 @@ mod test { fn diff_json(data: &str) { let serde_value: serde_json::Value = serde_json::from_str(data).unwrap(); - let dom = dom_from_slice(data.as_bytes()).unwrap(); + let dom: Value = from_slice(data.as_bytes()).unwrap(); let sonic_out = crate::to_string(&dom).unwrap(); let serde_value2: serde_json::Value = serde_json::from_str(&sonic_out).unwrap(); let expect = serde_json::to_string_pretty(&serde_value).unwrap(); @@ -1441,7 +1845,7 @@ mod test { } #[test] - fn test_node_from_files() { + fn test_node_from_files3() { use std::fs::DirEntry; let path = env!("CARGO_MANIFEST_DIR").to_string() + "/benches/testdata/"; println!("dir is {}", path); @@ -1483,7 +1887,7 @@ mod test { ]; for data in testdata { - let ret = dom_from_slice(data.as_bytes()); + let ret: Result = from_slice(data.as_bytes()); assert!(ret.is_err(), "failed json is {}", data); } } @@ -1531,9 +1935,7 @@ mod test { #[test] fn test_value_is() { - let dom = dom_from_str(TEST_JSON).unwrap(); - let value = dom.as_value(); - assert!(dom.get("bool").is_true()); + let value = dom_from_str(TEST_JSON).unwrap(); assert!(value.get("bool").is_boolean()); assert!(value.get("bool").is_true()); assert!(value.get("uint").is_u64()); @@ -1550,181 +1952,91 @@ mod test { #[test] fn test_value_get() { - let dom = dom_from_str(TEST_JSON).unwrap(); - let value = dom.as_value(); - assert_eq!(dom.get("int").as_i64().unwrap(), -1); + let value = dom_from_str(TEST_JSON).unwrap(); assert_eq!(value.get("int").as_i64().unwrap(), -1); assert_eq!(value["array"].get(0).as_i64().unwrap(), 1); - assert_eq!(dom.pointer(&pointer!["array", 2]).as_i64().unwrap(), 3); assert_eq!(value.pointer(&pointer!["array", 2]).as_u64().unwrap(), 3); - - assert_eq!( - dom.pointer(&pointer!["object", "a"]).as_str().unwrap(), - "aaa" - ); assert_eq!( value.pointer(&pointer!["object", "a"]).as_str().unwrap(), "aaa" ); - assert_eq!(dom.pointer(&pointer!["objempty", "a"]).as_str(), None); assert_eq!(value.pointer(&pointer!["objempty", "a"]).as_str(), None); - assert_eq!(dom.pointer(&pointer!["arrempty", 1]).as_str(), None); assert_eq!(value.pointer(&pointer!["arrempty", 1]).as_str(), None); - assert!(!dom.pointer(&pointer!["unknown"]).is_str()); assert!(!value.pointer(&pointer!["unknown"]).is_str()); } - #[test] - fn test_value_object() { - let mut dom = dom_from_str(TEST_JSON).unwrap(); - let value = dom.as_value(); - assert!(value.is_object()); - - let object = value.as_object().unwrap(); - assert_eq!(object.len(), 10); - assert!(object.get("bool").as_bool().unwrap()); - - let mut object = dom.as_object_mut().unwrap(); - object.insert("inserted", Value::new_bool(true)); - assert_eq!(object.len(), 11); - assert!(object.contains_key("inserted")); - assert!(object.remove("inserted").unwrap().is_true()); - assert!(!object.contains_key("inserted")); - - object.reserve(12); - assert_eq!(object.capacity(), 22); - - object.insert("inserted", Value::new_bool(true)); - assert!(object.contains_key("inserted")); - } - - #[test] - fn test_value_object_empty() { - let mut dom = dom_from_str(TEST_JSON).unwrap(); - let value = dom.as_value_mut(); - assert!(value.is_object()); - - let mut object = value.into_object_mut().unwrap(); - let mut empty = object - .get_mut("objempty") - .and_then(|s| s.into_object_mut()) - .unwrap(); - - assert_eq!(empty.len(), 0); - empty.insert( - "inserted", - Value::new_str("new inserted", empty.allocator()), - ); - empty.insert("inserted2", Value::new_bool(true)); - assert_eq!(empty.len(), 2); - assert!(empty.remove("inserted2").is_true()); - assert!(empty.contains_key("inserted")); - let value = empty.get_mut("inserted").unwrap().take(); - assert!(value.as_str().unwrap() == "new inserted"); - } - - #[test] - fn test_value_array() { - let mut dom = dom_from_str(TEST_JSON).unwrap(); - let mut root = dom.as_value_mut(); - let value = root.get_mut("array").unwrap(); - assert!(value.is_array()); - let mut array = value.into_array_mut().unwrap(); - assert_eq!(array.len(), 3); - assert_eq!(array[1].as_u64().unwrap(), 2); - array.push(Value::new_str_static("pushed")); - assert!(array[3].is_str()); - array.pop(); - assert!(array[2].is_number()); - assert_eq!(array.len(), 3); - - let iter = array.iter(); - assert_eq!(iter.len(), 3); - for (i, v) in iter.enumerate() { - assert_eq!(v.as_u64().unwrap(), (i + 1) as u64); - } - } - - #[test] - fn test_value_array_empty() { - let mut dom = dom_from_str(TEST_JSON).unwrap(); - let mut root = dom.as_value_mut(); - let mut empty = root - .get_mut("arrempty") - .and_then(|s| s.into_array_mut()) - .unwrap(); - - assert_eq!(empty.len(), 0); - empty.push(Value::new_str("new inserted", empty.allocator())); - empty.push(Value::new_bool(true)); - assert_eq!(empty.len(), 2); - assert!(empty.pop().is_true()); - let value = empty.get_mut(0).unwrap().take(); - assert!(value.as_str().unwrap() == "new inserted"); - } - #[test] fn test_invalid_utf8() { + use crate::from_slice; + use crate::from_slice_unchecked; + let data = [b'"', 0x80, 0x90, b'"']; - let dom = dom_from_slice(&data); + let ret: Result = from_slice(&data); assert_eq!( - dom.err().unwrap().to_string(), + ret.err().unwrap().to_string(), "Invalid UTF-8 characters in json at line 1 column 1\n\n\t\"��\"\n\t.^..\n" ); - let dom = unsafe { dom_from_slice_unchecked(&data) }; - assert!(dom.is_ok()); + + let dom: Result = unsafe { from_slice_unchecked(&data) }; + assert!(dom.is_ok(), "{}", dom.unwrap_err()); let data = [b'"', b'"', 0x80]; - let dom = dom_from_slice(&data); + let dom: Result = from_slice(&data); assert_eq!( dom.err().unwrap().to_string(), "Invalid UTF-8 characters in json at line 1 column 2\n\n\t\"\"�\n\t..^\n" ); let data = [0x80, b'"', b'"']; - let dom = dom_from_slice(&data); + let dom: Result = unsafe { from_slice_unchecked(&data) }; assert_eq!( dom.err().unwrap().to_string(), - "Invalid UTF-8 characters in json at line 1 column 0\n\n\t�\"\"\n\t^..\n" + "Invalid JSON value at line 1 column 0\n\n\t�\"\"\n\t^..\n" ); } #[test] - fn test_string_borrow() { - let s = String::from("borrowed"); - let value2 = Value::new_str_borrow(&s); - - let mut map = HashMap::new(); - map.insert("v2", value2); - - assert_eq!(to_string(&map).unwrap().as_str(), r#"{"v2":"borrowed"}"#); - } - - #[test] - fn test_value_from() { - assert_eq!(Value::from(1_u64).as_u64().unwrap(), 1); - assert_eq!(Value::from(-1_i64).as_i64().unwrap(), -1); - - assert!(Value::try_from(f64::INFINITY).is_err()); - assert!(Value::try_from(f64::NAN).is_err()); + fn test_value_serde() { + use crate::{array, object}; + use serde::Deserialize; + use serde::Serialize; + #[derive(Deserialize, Debug, Serialize, PartialEq)] + struct Foo { + value: Value, + object: Object, + array: Array, + } + + let foo: Foo = crate::from_str( + r#" + { + "value": "hello", + "object": {"a": "b"}, + "array": [1,2,3] + }"#, + ) + .unwrap(); + + assert_eq!(ManuallyDrop::new(foo.value.arc_shared()).refcnt(), 3); assert_eq!( - Value::try_from(f64::MAX).unwrap().as_f64().unwrap(), - f64::MAX + foo, + Foo { + value: Value::from("hello"), + object: object! {"a": "b"}, + array: array![1, 2, 3], + } ); - } - #[test] - fn test_document_serde() { - use crate::{Deserialize, Serialize}; - #[derive(Serialize, Deserialize)] - struct Person { - any: Document, - } - let json = r#"{"any": {"name": "John", "age": 30}}"#; - let person: Person = crate::from_str(json).unwrap(); - assert_eq!(person.any.get("name").as_str().unwrap(), "John"); + let _ = crate::from_str::( + r#"{ + "value": "hello", + "object": {"a": "b"}, + "array": [1,2,3 + }"#, + ) + .unwrap_err(); } } diff --git a/src/value/object.rs b/src/value/object.rs new file mode 100644 index 0000000..d55da40 --- /dev/null +++ b/src/value/object.rs @@ -0,0 +1,981 @@ +use super::from::SharedCtxGuard; +use super::node::replace_value; +use super::shared::Shared; +use super::value_trait::JsonValueTrait; +use crate::serde::tri; +use crate::util::reborrow::DormantMutRef; +use crate::value::node::Value; +use std::marker::PhantomData; + +/// Represents the JSON object. It is a key-value array. Its order is as same as origin JSON. +/// +/// The key is not sorted and the find operation is O(n). If you are hea Recommend to use `BTreeMap` or `HashMap` instead. +/// +/// # Warning +/// `Object` is allowed to have duplicated keys. If you want to use it as a map, recommend to use `BTreeMap` or `HashMap` instead. +/// +#[derive(Debug, Clone, Eq, PartialEq)] +#[repr(transparent)] +pub struct Object(pub(crate) Value); + +impl Default for Object { + fn default() -> Self { + Self::new() + } +} + +#[doc(hidden)] +pub type Pair = (Value, Value); + +pub(crate) const DEFAULT_OBJ_CAP: usize = 4; + +impl Object { + /// Returns the inner `Value`. + /// + #[inline] + pub fn into_value(self) -> Value { + self.0 + } + + /// Create a new empty object. + /// + #[inline] + pub const fn new() -> Object { + let value = Value { + meta: super::node::Meta::new(super::node::ROOT_OBJECT, std::ptr::null()), + data: super::node::Data { + achildren: std::ptr::null_mut(), + }, + }; + Object(value) + } + + /// Create a new empty object with capacity. + /// + #[inline] + pub fn with_capacity(capacity: usize) -> Self { + let mut v = Self::new(); + v.0.reserve::(capacity); + v + } + + /// Clear the object, make it as empty but keep the allocated memory. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{json, object}; + /// + /// let mut obj = object!{"a": 1, "b": true, "c": null}; + /// obj.clear(); + /// assert!(obj.is_empty()); + /// assert!(obj.capacity() >= 3); + /// ``` + /// + #[inline] + pub fn clear(&mut self) { + self.0.clear(); + } + + /// Returns the capacity of the object. + #[inline] + pub fn capacity(&self) -> usize { + self.0.capacity() + } + + /// Returns a reference to the value corresponding to the key. + /// + /// The key may be [`AsRef`]. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{json, object}; + /// + /// let mut obj = object!{"a": 1, "b": true, "c": null}; + /// obj.insert(&"d", "e"); + /// assert_eq!(obj.get(&"d").unwrap(), "e"); + /// assert_eq!(obj.get(&"f"), None); + /// assert_eq!(obj.get(&"a").unwrap(), 1); + /// ``` + /// + #[inline] + pub fn get>(&self, key: &Q) -> Option<&Value> { + self.0.get_key(key.as_ref()) + } + + /// Returns `true` if the map contains a value for the specified key. + /// + /// The key may be [`AsRef`]. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{object}; + /// + /// let mut obj = object!{"a": 1, "b": true, "c": null}; + /// obj.insert(&"d", "e"); + /// assert_eq!(obj.contains_key(&"d"), true); + /// assert_eq!(obj.contains_key(&"a"), true); + /// assert_eq!(obj.contains_key(&"e"), false); + /// ``` + /// + #[inline] + pub fn contains_key>(&self, key: &Q) -> bool { + self.get(key).is_some() + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// The key may be [`AsRef`]. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{object}; + /// + /// let mut obj = object!{"a": 1, "b": true, "c": null}; + /// obj.insert(&"d", "e"); + /// + /// *(obj.get_mut(&"d").unwrap()) = "f".into(); + /// assert_eq!(obj.contains_key(&"d"), true); + /// assert_eq!(obj["d"], "f"); + /// ``` + /// + #[inline] + pub fn get_mut>(&mut self, key: &Q) -> Option<&mut Value> { + self.0.get_key_mut(key.as_ref()).map(|v| v.0) + } + + /// Returns the key-value pair corresponding to the supplied key. + /// + /// The key may be [`AsRef`]. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{object, Value}; + /// + /// let mut obj = object!{"a": 1, "b": true, "c": null}; + /// obj.insert(&"d", "e"); + /// + /// assert_eq!(obj.get_key_value(&"d").unwrap(), ("d", &Value::from("e"))); + /// assert_eq!(obj.get_key_value(&"a").unwrap(), ("a", &Value::from(1))); + /// assert_eq!(obj.get_key_value(&"e"), None); + /// ``` + /// + #[inline] + pub fn get_key_value>(&self, key: &Q) -> Option<(&str, &Value)> { + self.0.get_key_value(key.as_ref()) + } + + /// Inserts a key-value pair into the object. The `Value` is converted from `V`. + /// + /// The key may be [`AsRef`]. + /// + /// If the object did not have this key present, [`None`] is returned. + /// + /// If the object did have this key present, the value is updated, and the old + /// value is returned. The key is not updated, though; this matters for + /// types that can be `==` without being identical. See the [module-level + /// documentation] for more. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{object, json, Value}; + /// + /// let mut obj = object!{"a": 1, "b": true, "c": null}; + /// assert_eq!(obj.len(), 3); + /// assert_eq!(obj.insert(&"d", "e"), None); + /// assert_eq!(obj.len(), 4); + /// assert_eq!(obj["d"], "e"); + /// assert_eq!(obj.insert(&"d", "f").unwrap(), "e"); + /// assert_eq!(obj["d"], "f"); + /// assert_eq!(obj.len(), 4); + /// assert_eq!(obj.insert(&"d", json!("h")).unwrap(), "f"); + /// assert_eq!(obj["d"], "h"); + /// assert_eq!(obj.insert(&"i", Value::from("j")), None); + /// assert_eq!(obj.len(), 5); + /// ``` + /// + #[inline] + pub fn insert, V: Into>(&mut self, key: &K, value: V) -> Option { + match self.entry(key) { + Entry::Occupied(mut entry) => Some(entry.insert(value)), + Entry::Vacant(entry) => { + entry.insert(value); + None + } + } + } + + /// Removes a key from the object, returning the value at the key if the key + /// was previously in the object. + /// + /// The key may be [`AsRef`]. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{object}; + /// + /// let mut obj = object!{"a": 1, "b": true, "c": null}; + /// assert_eq!(obj.remove(&"d"), None); + /// assert_eq!(obj.remove(&"a").unwrap(), 1); + /// ``` + /// + #[inline] + pub fn remove>(&mut self, key: &Q) -> Option { + self.0.remove_key(key.as_ref()) + } + + /// Removes a key from the object, returning the stored key and value if the + /// key was previously in the obj. + /// + /// The key may be [`AsRef`]. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{object}; + /// + /// let mut obj = object!{"a": 1, "b": true, "c": null}; + /// assert_eq!(obj.remove_entry(&"d"), None); + /// let (key, val) = obj.remove_entry(&"a").unwrap(); + /// assert_eq!(key, "a"); + /// assert_eq!(val, 1); + /// ``` + /// + #[inline] + pub fn remove_entry<'k, Q: AsRef>(&mut self, key: &'k Q) -> Option<(&'k str, Value)> { + self.0.remove_key(key.as_ref()).map(|v| (key.as_ref(), v)) + } + + /// Returns the number of key-value paris in the object. + #[inline] + pub fn len(&self) -> usize { + self.0.len() + } + + /// Returns true if the object contains no key-value pairs. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns an immutable iterator over the key-value pairs of the object. + #[inline] + pub fn iter(&self) -> Iter<'_> { + Iter(self.0.iter::()) + } + + /// Returns an mutable iterator over the key-value pairs of the object. + #[inline] + pub fn iter_mut(&mut self) -> IterMut<'_> { + IterMut(self.0.iter_mut::()) + } + + /// Gets the given key's corresponding entry in the object for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{object, Value}; + /// + /// let mut obj = object!{}; + /// + /// for i in 0..10 { + /// obj.entry(&i.to_string()).or_insert(1); + /// } + /// + /// for i in 0..10 { + /// obj.entry(&i.to_string()).and_modify(|v| *v = Value::from(i + 1)); + /// } + /// + /// assert_eq!(obj[&"1"], 2); + /// assert_eq!(obj[&"2"], 3); + /// assert_eq!(obj[&"3"], 4); + /// assert_eq!(obj.get(&"10"), None); + /// ``` + /// + #[inline] + pub fn entry<'a, Q: AsRef>(&'a mut self, key: &Q) -> Entry<'a> { + let (obj, mut dormant_obj) = DormantMutRef::new(self); + match obj.0.get_key_mut(key.as_ref()) { + None => { + // check flat + let obj_re = unsafe { dormant_obj.reborrow() }; + if obj_re.0.is_static() { + obj_re.0.mark_shared(Shared::new_ptr()); + obj_re.0.mark_root(); + } + let shared = obj_re.0.shared(); + let key = Value::copy_str(key.as_ref(), shared); + Entry::Vacant(VacantEntry { + key, + dormant_obj, + _marker: PhantomData, + }) + } + Some((handle, offset)) => { + Entry::Occupied(OccupiedEntry::new(handle, offset, dormant_obj)) + } + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all pairs `(k, v)` for which `f(&k, &mut v)` returns `false`. + /// The elements are visited in unsorted (and unspecified) order. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::object; + /// + /// let mut obj = object!{"a": 1, "b": true, "c": null}; + /// obj.retain(|key, _| key == "a"); + /// assert_eq!(obj.len(), 1); + /// assert_eq!(obj["a"], 1); + /// ``` + #[inline] + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&str, &mut Value) -> bool, + { + if self.is_empty() { + return; + } + let start: *mut Pair = unsafe { self.0.children_mut_ptr::() }; + let mut cur = start; + for (k, v) in self.0.iter_mut::() { + let key = k.as_str().unwrap(); + if f(key, v) { + if !std::ptr::eq(k, cur as *mut Value) { + unsafe { std::ptr::copy_nonoverlapping((k as *mut Value).cast(), cur, 1) }; + } + cur = unsafe { cur.add(1) }; + } else { + // drop the old value + v.take(); + } + } + unsafe { + let new_len = cur.offset_from(start) as usize; + self.0.set_len(new_len); + } + } + + /// Moves all elements from other into self, leaving other empty. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{object, json}; + /// + /// let mut a = object!{}; + /// let mut b = object!{"a": null, "b": 1}; + /// a.append(&mut b); + /// + /// assert_eq!(a, object!{"a": null, "b": 1}); + /// assert!(b.is_empty()); + /// ``` + #[inline] + pub fn append(&mut self, other: &mut Self) { + while let Some((k, v)) = other.0.pop_pair() { + self.0.append_pair((k, v)); + } + } + + /// Reserves capacity for at least additional more elements to be inserted in the given. + /// + /// # Examples + /// ``` + /// use sonic_rs::object; + /// let mut obj = object!{}; + /// obj.reserve(1); + /// assert!(obj.capacity() >= 1); + /// + /// obj.reserve(10); + /// assert!(obj.capacity() >= 10); + /// ``` + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.0.reserve::(additional); + } +} + +/// A view into a single occupied location in a `Object`. +pub struct OccupiedEntry<'a> { + handle: &'a mut Value, + offset: usize, + dormant_obj: DormantMutRef<'a, Object>, + _marker: PhantomData<&'a mut Pair>, +} + +impl<'a> OccupiedEntry<'a> { + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{object, Value}; + /// use sonic_rs::value::object::Entry; + /// + /// let mut obj = object!{"a": 1, "b": true, "c": null}; + /// + /// if let Entry::Occupied(entry) = obj.entry(&"a") { + /// assert_eq!(entry.get(), 1); + /// } + /// + /// if let Entry::Occupied(entry) = obj.entry(&"b") { + /// assert_eq!(entry.get(), true); + /// } + /// + /// ``` + #[inline] + pub fn get(&self) -> &Value { + self.handle + } + + /// Gets a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{object, Value}; + /// use sonic_rs::value::object::Entry; + /// + /// let mut obj = object!{"a": 1, "b": true, "c": null}; + /// obj.insert(&"a", Value::from("hello")); + /// + /// if let Entry::Occupied(mut entry) = obj.entry(&"a") { + /// assert_eq!(entry.get_mut(), &Value::from("hello")); + /// } + /// + /// if let Entry::Occupied(mut entry) = obj.entry(&"b") { + /// assert_eq!(entry.get_mut(), &true); + /// } + /// dbg!(&obj); + /// ``` + #[inline] + pub fn get_mut(&mut self) -> &mut Value { + self.handle + } + + /// Converts the entry into a mutable reference to its value. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{object, Value}; + /// use sonic_rs::value::object::Entry; + /// + /// let mut obj = object!{"a": 1, "b": true, "c": null}; + /// obj.insert(&"a", Value::from("hello")); + /// + /// if let Entry::Occupied(mut entry) = obj.entry(&"a") { + /// let vref = entry.into_mut(); + /// assert_eq!(vref, &mut Value::from("hello")); + /// *vref = Value::from("world"); + /// } + /// + /// assert_eq!(obj["a"], "world"); + /// ``` + #[inline] + pub fn into_mut(self) -> &'a mut Value { + self.handle + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::object; + /// use sonic_rs::value::object::Entry; + /// + /// let mut obj = object!{"a": 1, "b": true, "c": null}; + /// + /// if let Entry::Occupied(mut entry) = obj.entry(&"a") { + /// assert_eq!(entry.insert("hello"), 1); + /// } + /// if let Entry::Occupied(mut entry) = obj.entry(&"a") { + /// assert_eq!(entry.insert("world"), "hello"); + /// } + /// + /// ``` + #[inline] + pub fn insert>(&mut self, val: T) -> Value { + let obj = unsafe { self.dormant_obj.reborrow() }; + let val = { + let _ = SharedCtxGuard::assign(obj.0.shared_parts()); + val.into() + }; + replace_value(self.handle, val) + } + + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// ``` + /// use sonic_rs::{object, Value}; + /// use sonic_rs::value::object::Entry; + /// + /// let mut obj = object!{"a": 1, "b": true, "c": null}; + /// + /// if let Entry::Occupied(mut entry) = obj.entry(&"a") { + /// assert_eq!(entry.remove(), 1); + /// } + /// + /// if let Entry::Occupied(mut entry) = obj.entry(&"b") { + /// assert_eq!(entry.remove(), true); + /// } + /// + /// if let Entry::Occupied(mut entry) = obj.entry(&"c") { + /// assert_eq!(entry.remove(), Value::default()); + /// } + /// assert!(obj.is_empty()); + /// ``` + #[inline] + pub fn remove(mut self) -> Value { + let obj = unsafe { self.dormant_obj.reborrow() }; + let (_, val) = obj.0.remove_pair_index(self.offset); + val + } + + #[inline] + pub(crate) fn new( + handle: &'a mut Value, + offset: usize, + dormant_obj: DormantMutRef<'a, Object>, + ) -> Self { + Self { + handle, + offset, + dormant_obj, + _marker: PhantomData, + } + } +} + +/// A view into a vacant entry in a `Object`. +pub struct VacantEntry<'a> { + pub(super) key: Value, + pub(super) dormant_obj: DormantMutRef<'a, Object>, + pub(super) _marker: PhantomData<&'a mut Pair>, +} + +impl<'a> VacantEntry<'a> { + /// Insert a value into the vacant entry and return a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::object; + /// use sonic_rs::value::object::Entry; + /// + /// let mut obj = object!{}; + /// + /// if let Entry::Vacant(entry) = obj.entry(&"hello") { + /// assert_eq!(entry.insert(1), &1); + /// } + /// assert_eq!(obj.get(&"hello").unwrap(), 1); + /// ``` + /// + pub fn insert>(self, val: T) -> &'a mut Value { + let obj = unsafe { self.dormant_obj.awaken() }; + obj.reserve(1); + let val = { + let _ = SharedCtxGuard::assign(obj.0.shared_parts()); + val.into() + }; + let pair = obj.0.append_pair((self.key, val)); + &mut pair.1 + } + + /// Get the key of the vacant entry. + pub fn key(&self) -> &str { + self.key.as_str().unwrap() + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +pub enum Entry<'a> { + /// A vacant Entry. + Vacant(VacantEntry<'a>), + /// An occupied Entry. + Occupied(OccupiedEntry<'a>), +} + +impl<'a> Entry<'a> { + /// Ensures a value is in the entry by inserting the default if empty, + /// Example: + /// ```rust + /// use sonic_rs::object; + /// + /// let mut obj = object!{}; + /// obj.entry(&"hello").or_insert(1); + /// assert_eq!(obj.get(&"hello").unwrap(), 1); + /// + /// obj.entry(&"hello").or_insert(2); + /// assert_eq!(obj.get(&"hello").unwrap(), 1); + /// ``` + #[inline] + pub fn or_insert>(self, default: T) -> &'a mut Value { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// Example: + /// ```rust + /// use sonic_rs::Object; + /// let mut obj = Object::new(); + /// obj.entry(&"hello").or_insert_with(|| 1.into() ); + /// assert_eq!(obj.get(&"hello").unwrap(), 1); + /// + /// obj.entry(&"hello").or_insert_with(|| 2.into() ); + /// assert_eq!(obj.get(&"hello").unwrap(), 1); + /// ``` + #[inline] + pub fn or_insert_with Value>(self, default: F) -> &'a mut Value { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default()), + } + } + + /// Return the key of the entry. + #[inline] + pub fn key(&self) -> &str { + match self { + Entry::Occupied(entry) => entry.handle.as_str().unwrap(), + Entry::Vacant(entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any potential inserts into the object. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::object; + /// use sonic_rs::value::object::Entry; + /// + /// let mut obj = object!{"a": 0, "b": true, "c": null}; + /// obj.entry(&"a").and_modify(|v| *v = 2.into()); + /// assert_eq!(obj.get(&"a").unwrap(), 2); + /// + /// obj.entry(&"a").and_modify(|v| *v = 2.into()).and_modify(|v| *v = 3.into()); + /// assert_eq!(obj.get(&"a").unwrap(), 3); + /// + /// obj.entry(&"d").and_modify(|v| *v = 3.into()); + /// assert_eq!(obj.get(&"d"), None); + /// + /// obj.entry(&"d").and_modify(|v| *v = 3.into()).or_insert(4); + /// assert_eq!(obj.get(&"d").unwrap(), 4); + /// ``` + /// + #[inline] + pub fn and_modify(self, f: F) -> Self { + match self { + Entry::Occupied(entry) => { + f(entry.handle); + Entry::Occupied(entry) + } + Entry::Vacant(entry) => Entry::Vacant(entry), + } + } + + /// Ensures a value is in the entry by inserting the default value if empty, and returns a mutable reference to the value in the entry. + /// # Examples + /// + /// ``` + /// use sonic_rs::{object, Value}; + /// use sonic_rs::value::object::Entry; + /// + /// let mut obj = object!{"c": null}; + /// assert_eq!(obj.entry(&"a").or_default(), &Value::default()); + /// assert_eq!(obj.entry(&"d").or_default(), &Value::default()); + /// ``` + #[inline] + pub fn or_default(self) -> &'a mut Value { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(Value::default()), + } + } + + /// Ensures a value is in the entry by inserting, if empty, the result of the default function. + /// This method allows for generating key-derived values for insertion by providing the default + /// function a reference to the key that was moved during the `.entry(key)` method call. + /// + /// The reference to the moved key is provided so that cloning or copying the key is + /// unnecessary, unlike with `.or_insert_with(|| ... )`. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::{object, Value}; + /// + /// let mut obj = object!{"c": null}; + /// + /// obj.entry(&"a").or_insert_with_key(|key | Value::from(key.len())); + /// assert_eq!(obj.get(&"a").unwrap(), 1); + /// + /// obj.entry(&"b").or_insert_with_key(|key | Value::from(key)); + /// assert_eq!(obj.get(&"b").unwrap(), "b"); + /// ``` + #[inline] + pub fn or_insert_with_key(self, default: F) -> &'a mut Value + where + F: FnOnce(&str) -> Value, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(mut entry) => { + let obj = unsafe { entry.dormant_obj.reborrow() }; + let value = { + let _ = SharedCtxGuard::assign(obj.0.shared_parts()); + default(entry.key()) + }; + entry.insert(value) + } + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +use std::iter::FusedIterator; +use std::slice; + +macro_rules! impl_entry_iter { + (($name:ident $($generics:tt)*): $item:ty) => { + impl $($generics)* Iterator for $name $($generics)* { + type Item = $item; + + #[inline] + fn next(&mut self) -> Option { + self.0.next().map(|(k, v)| (k.as_str().unwrap(), v)) + } + } + + impl $($generics)* DoubleEndedIterator for $name $($generics)* { + #[inline] + fn next_back(&mut self) -> Option { + self.0.next_back().map(|(k, v)| (k.as_str().unwrap(), v)) + } + } + + impl $($generics)* ExactSizeIterator for $name $($generics)* { + #[inline] + fn len(&self) -> usize { + self.0.len() + } + } + + impl $($generics)* FusedIterator for $name $($generics)* {} + }; +} + +/// An iterator over the entries of a `Object`. +pub struct Iter<'a>(slice::Iter<'a, (Value, Value)>); +impl_entry_iter!((Iter<'a>): (&'a str, &'a Value)); + +/// A mutable iterator over the entries of a `Object`. +pub struct IterMut<'a>(slice::IterMut<'a, (Value, Value)>); +impl_entry_iter!((IterMut<'a>): (&'a str, &'a mut Value)); + +/// An iterator over the keys of a `Object`. +pub struct Keys<'a>(Iter<'a>); + +impl<'a> Iterator for Keys<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option { + self.0.next().map(|(k, _)| k) + } +} + +impl<'a> DoubleEndedIterator for Keys<'a> { + #[inline] + fn next_back(&mut self) -> Option { + self.0.next_back().map(|(k, _)| k) + } +} + +impl<'a> ExactSizeIterator for Keys<'a> { + #[inline] + fn len(&self) -> usize { + self.0.len() + } +} + +impl<'a> FusedIterator for Keys<'a> {} + +macro_rules! impl_value_iter { + (($name:ident $($generics:tt)*): $item:ty) => { + impl $($generics)* Iterator for $name $($generics)* { + type Item = $item; + + #[inline] + fn next(&mut self) -> Option { + self.0.next().map(|(_, v)| v) + } + } + + impl $($generics)* DoubleEndedIterator for $name $($generics)* { + #[inline] + fn next_back(&mut self) -> Option { + self.0.next_back().map(|(_, v)| v) + } + } + + impl $($generics)* ExactSizeIterator for $name $($generics)* { + #[inline] + fn len(&self) -> usize { + self.0.len() + } + } + + impl $($generics)* FusedIterator for $name $($generics)* {} + }; +} + +/// An iterator over the values of a `Object`. +pub struct Values<'a>(Iter<'a>); +impl_value_iter!((Values<'a>): &'a Value); + +/// A mutable iterator over the values of a `Object`. +pub struct ValuesMut<'a>(IterMut<'a>); +impl_value_iter!((ValuesMut<'a>): &'a mut Value); + +impl<'a> IntoIterator for &'a Object { + type Item = (&'a str, &'a Value); + type IntoIter = Iter<'a>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a> IntoIterator for &'a mut Object { + type Item = (&'a str, &'a mut Value); + type IntoIter = IterMut<'a>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +impl<'a, Q: AsRef + ?Sized> std::ops::Index<&'a Q> for Object { + type Output = Value; + + #[inline] + fn index(&self, index: &'a Q) -> &Self::Output { + self.get(&index.as_ref()).unwrap() + } +} + +impl<'a, Q: AsRef + ?Sized> std::ops::IndexMut<&'a Q> for Object { + #[inline] + fn index_mut(&mut self, index: &'a Q) -> &mut Self::Output { + self.get_mut(&index.as_ref()).unwrap() + } +} + +////////////////////////////////////////////////////////////////////////////// + +impl serde::ser::Serialize for Object { + #[inline] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::ser::Serializer, + { + use serde::ser::SerializeMap; + let mut map = tri!(serializer.serialize_map(Some(self.len()))); + for (k, v) in self { + tri!(map.serialize_entry(k, v)); + } + map.end() + } +} + +impl<'de> serde::de::Deserialize<'de> for Object { + #[inline] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::de::Deserializer<'de>, + { + // deserialize to value at first + let value: Value = + deserializer.deserialize_newtype_struct(super::de::TOKEN, super::de::ValueVisitor)?; + if value.is_object() { + Ok(Object(value)) + } else { + Err(serde::de::Error::invalid_type( + serde::de::Unexpected::Other("not a object"), + &"object", + )) + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::object; + use crate::Array; + use crate::JsonValueMutTrait; + use crate::{from_str, to_string}; + + #[test] + fn test_object_serde() { + let json = r#"{"a": 1, "b": true, "c": null}"#; + let obj: Object = from_str(json).unwrap(); + assert_eq!(obj, object! {"a": 1, "b": true, "c": null}); + let json = to_string(&obj).unwrap(); + assert_eq!(json, r#"{"a":1,"b":true,"c":null}"#); + } + + #[test] + fn test_value_object() { + let mut val = crate::from_str::(r#"{"a": 123, "b": "hello"}"#); + let obj = val.as_object_mut().unwrap(); + + for i in 0..3 { + // push static node + let new_node = Value::new_u64(i, std::ptr::null()); + obj.insert(&"c", new_node); + assert_eq!(obj["c"], i); + + // push node with new allocator + let mut new_node = Array::default(); + new_node.push(Value::new_u64(i, std::ptr::null())); + obj.insert(&"d", new_node); + assert_eq!(obj["d"][0], i); + + // push node with self allocator + let mut new_node = Array::new_in(obj.0.shared_clone()); + new_node.push(Value::new_u64(i, std::ptr::null())); + obj.insert(&"e", new_node); + assert_eq!(obj["e"][0], i); + } + + for (i, v) in obj.iter_mut().enumerate() { + *(v.1) = Value::from(&i.to_string()); + } + + for (i, v) in obj.iter().enumerate() { + assert_eq!(v.1, &Value::from(&i.to_string())); + } + } +} diff --git a/src/value/partial_eq.rs b/src/value/partial_eq.rs new file mode 100644 index 0000000..ca23d49 --- /dev/null +++ b/src/value/partial_eq.rs @@ -0,0 +1,333 @@ +use super::object::Pair; +use crate::value::node::Value; +use crate::value::value_trait::{JsonContainerTrait, JsonValueTrait}; +use crate::JsonType; +use faststr::FastStr; +impl Eq for Value {} + +impl PartialEq for Value { + #[inline] + fn eq(&self, other: &Self) -> bool { + if std::ptr::eq(self, other) { + return true; + } + + if self.get_type() != other.get_type() { + return false; + } + + match self.get_type() { + JsonType::Boolean => self.as_bool() == other.as_bool(), + JsonType::Null => other.is_null(), + JsonType::Number => self.as_f64() == other.as_f64(), + JsonType::String => self.as_str() == other.as_str(), + JsonType::Array => { + let len = self.len(); + if len != other.len() { + return false; + } + let ours = self.children::(); + let theirs = other.children::(); + ours.iter().zip(theirs).all(|(a, b)| (*a) == b) + } + JsonType::Object => { + let len = self.len(); + if len != other.len() { + return false; + } + if len == 0 { + return true; + } + + for (k, v) in self.iter::() { + let key = k.as_str().unwrap(); + let matched = other.get(key).map(|v1| v == v1).unwrap_or(false); + if !matched { + return false; + } + } + true + } + JsonType::Raw => unreachable!("raw type is not implement in `Value`"), + } + } +} + +macro_rules! impl_str_eq { + ($($eq:ident [$($ty:ty)*])*) => { + $($( + impl PartialEq<$ty> for Value { + #[inline] + fn eq(&self, other: &$ty) -> bool { + let s: &str = other.as_ref(); + $eq(self, s) + } + } + + impl PartialEq for $ty { + #[inline] + fn eq(&self, other: &Value) -> bool { + let s: &str = self.as_ref(); + $eq(other, s) + } + } + + impl PartialEq<$ty> for &Value { + #[inline] + fn eq(&self, other: &$ty) -> bool { + let s: &str = other.as_ref(); + $eq(*self, s) + } + } + + impl PartialEq<$ty> for &mut Value { + #[inline] + fn eq(&self, other: &$ty) -> bool { + let s: &str = other.as_ref(); + $eq(*self, s) + } + } + )*)* + } +} + +impl_str_eq! { + eq_str[str String FastStr] +} + +impl PartialEq<&str> for Value { + #[inline] + fn eq(&self, other: &&str) -> bool { + eq_str(self, other) + } +} + +impl PartialEq for &str { + #[inline] + fn eq(&self, other: &Value) -> bool { + eq_str(other, self) + } +} + +/////////////////////////////////////////////////////////////////// +// Copied from serde_json + +#[inline] +fn eq_i64(value: &Value, other: i64) -> bool { + value.as_i64().map_or(false, |i| i == other) +} + +#[inline] +fn eq_u64(value: &Value, other: u64) -> bool { + value.as_u64().map_or(false, |i| i == other) +} + +#[inline] +fn eq_f64(value: &Value, other: f64) -> bool { + value.as_f64().map_or(false, |i| i == other) +} + +#[inline] +fn eq_bool(value: &Value, other: bool) -> bool { + value.as_bool().map_or(false, |i| i == other) +} + +#[inline] +fn eq_str(value: &Value, other: &str) -> bool { + value.as_str().map_or(false, |i| i == other) +} + +macro_rules! impl_numeric_eq { + ($($eq:ident [$($ty:ty)*])*) => { + $($( + impl PartialEq<$ty> for Value { + #[inline] + fn eq(&self, other: &$ty) -> bool { + $eq(self, *other as _) + } + } + + impl PartialEq for $ty { + #[inline] + fn eq(&self, other: &Value) -> bool { + $eq(other, *self as _) + } + } + + impl PartialEq<$ty> for &Value { + #[inline] + fn eq(&self, other: &$ty) -> bool { + $eq(*self, *other as _) + } + } + + impl PartialEq<$ty> for &mut Value { + #[inline] + fn eq(&self, other: &$ty) -> bool { + $eq(*self, *other as _) + } + } + )*)* + } +} + +impl_numeric_eq! { + eq_i64[i8 i16 i32 i64 isize] + eq_u64[u8 u16 u32 u64 usize] + eq_f64[f32 f64] + eq_bool[bool] +} + +////////////////////////////////////////////////////////////////////////////// + +macro_rules! impl_slice_eq { + ([$($vars:tt)*], $rhs:ty $(where $ty:ty: $bound:ident)?) => { + impl PartialEq<$rhs> for Array + where + Value: PartialEq, + $($ty: $bound)? + { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + let len = self.len(); + if len != other.len() { + return false; + } + let slf = self.as_ref(); + let other: &[U] = other.as_ref(); + slf.iter().zip(other).all(|(a, b)| *a == *b ) + } + } + + impl PartialEq<$rhs> for Value + where + Value: PartialEq, + $($ty: $bound)? + { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + self.as_array().map(|arr| arr == other).unwrap_or(false) + } + } + + + impl PartialEq for $rhs + where + Value: PartialEq, + $($ty: $bound)? + { + #[inline] + fn eq(&self, other: &Array) -> bool { + other == self + } + } + + impl PartialEq for $rhs + where + Value: PartialEq, + $($ty: $bound)? + { + #[inline] + fn eq(&self, other: &Value) -> bool { + other == self + } + } + } +} + +impl_slice_eq!([], &[U]); +impl_slice_eq!([], &mut [U]); +impl_slice_eq!([], [U]); +impl_slice_eq!([const N: usize], &[U; N]); +impl_slice_eq!([const N: usize], [U; N]); +impl_slice_eq!([], Vec); + +////////////////////////////////////////////////////////////////////////////// + +use super::array::Array; +use super::object::Object; + +// TODO: compare value with object/array. + +macro_rules! impl_container_eq { + ($($ty:ty)*) => { + $( + impl PartialEq<$ty> for Value { + #[inline] + fn eq(&self, other: &$ty) -> bool { + self == &other.0 + } + } + + impl PartialEq for $ty { + #[inline] + fn eq(&self, other: &Value) -> bool { + other == &self.0 + } + } + + impl PartialEq<$ty> for &Value { + #[inline] + fn eq(&self, other: &$ty) -> bool { + *self == &other.0 + } + } + + impl PartialEq<$ty> for &mut Value { + #[inline] + fn eq(&self, other: &$ty) -> bool { + *self == &other.0 + } + } + + impl PartialEq for &$ty { + #[inline] + fn eq(&self, other: &Value) -> bool { + other == &self.0 + } + } + + impl PartialEq for &mut $ty { + #[inline] + fn eq(&self, other: &Value) -> bool { + other == &self.0 + } + } + + )* + } +} + +impl_container_eq!(Array Object); + +#[cfg(test)] +mod test { + use crate::{array, json}; + use faststr::FastStr; + #[test] + fn test_slice_eq() { + assert_eq!(json!([1, 2, 3]), &[1, 2, 3]); + assert_eq!(array![1, 2, 3], &[1, 2, 3]); + assert_eq!(json!([1, 2, 3]), array![1, 2, 3].as_slice()); + + assert_eq!(json!([1, 2, 3]), vec![1, 2, 3]); + assert_eq!(vec![1, 2, 3], array![1, 2, 3]); + assert_eq!(array![1, 2, 3], &[1, 2, 3][..]); + assert_eq!(json!([1, 2, 3]), array![1, 2, 3].as_slice()); + } + + #[test] + fn test_str_eq() { + assert_eq!(json!("123"), FastStr::new("123")); + assert_eq!(json!("123"), "123"); + } + + #[test] + fn test_container_eq() { + assert_eq!(json!([1, 2, 3]), array![1, 2, 3]); + assert_eq!(array![1, 2, 3], json!([1, 2, 3])); + assert_eq!(json!({"a": 1, "b": 2}), json!({"b": 2, "a": 1})); + assert_eq!(json!({"a": 1, "b": 2}), object! {"a": 1, "b": 2}); + assert_eq!(object! {"a": 1, "b": 2}, json!({"a": 1, "b": 2})); + } +} diff --git a/src/value/ser.rs b/src/value/ser.rs new file mode 100644 index 0000000..552550e --- /dev/null +++ b/src/value/ser.rs @@ -0,0 +1,813 @@ +use super::shared::Shared; +use crate::error::{Error, ErrorCode, Result}; +use crate::util::arc::Arc; +use crate::value::node::Value; +use crate::JsonValueTrait; +use core::fmt::Display; +use serde::ser::{Impossible, Serialize}; +use std::ptr::NonNull; + +/// Convert a `T` into `sonic_rs::Value` which can represent any valid JSON data. +/// +/// # Example +/// +/// ``` +/// use serde::Serialize; +/// use sonic_rs::{json, to_value, Value}; +/// +/// #[derive(Serialize, Debug)] +/// struct User { +/// string: String, +/// number: i32, +/// array: Vec, +/// } +/// +/// let user = User{ +/// string: "hello".into(), +/// number: 123, +/// array: vec!["a".into(), "b".into(), "c".into()], +/// }; +/// let got: Value = sonic_rs::to_value(&user).unwrap(); +/// let expect = json!({ +/// "string": "hello", +/// "number": 123, +/// "array": ["a", "b", "c"], +/// }); +/// assert_eq!(got, expect); +/// ``` +/// +/// # Errors +/// +/// This conversion can fail if `T`'s implementation of `Serialize` decides to +/// fail, or if `T` contains a map with non-string keys. +/// +/// ``` +/// use std::collections::BTreeMap; +/// use sonic_rs::to_value; +/// +/// // The keys in this map are vectors, not strings. +/// let mut map = BTreeMap::new(); +/// map.insert(vec![32, 64], "x86"); +/// let err = to_value(&map).unwrap_err().to_string(); +/// assert!(err.contains("key must be string")); +/// +/// ``` +pub fn to_value(value: &T) -> Result +where + T: ?Sized + Serialize, +{ + let shared = Arc::new(Shared::new()); + let mut value = to_value_in( + unsafe { NonNull::new_unchecked(shared.data_ptr() as *mut _) }, + value, + )?; + if value.is_number() { + value.mark_shared(std::ptr::null()); + } else { + value.mark_root(); + std::mem::forget(shared); + } + Ok(value) +} + +// Not export this because it is mainly used in `json!`. +pub(crate) struct Serializer(NonNull); + +impl Serializer { + #[inline] + fn new_in(share: NonNull) -> Self { + Self(share) + } + + #[inline] + fn shared(&self) -> NonNull { + self.0 + } + + #[inline] + fn shared_ptr(&self) -> *const Shared { + self.0.as_ptr() + } + + #[inline] + fn shared_ref(&self) -> &Shared { + unsafe { self.0.as_ref() } + } +} + +use crate::serde::tri; +use std::string::ToString; + +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; + + #[inline] + fn serialize_unit(self) -> Result { + Ok(Value::new_null(self.shared_ptr())) + } + + #[inline] + fn serialize_bool(self, value: bool) -> Result { + Ok(Value::new_bool(value, self.shared_ptr())) + } + + #[inline] + fn serialize_i8(self, value: i8) -> Result { + self.serialize_i64(value as i64) + } + + #[inline] + fn serialize_i16(self, value: i16) -> Result { + self.serialize_i64(value as i64) + } + + #[inline] + fn serialize_i32(self, value: i32) -> Result { + self.serialize_i64(value as i64) + } + + fn serialize_i64(self, value: i64) -> Result { + Ok(Value::new_i64(value, self.shared_ptr())) + } + + fn serialize_i128(self, value: i128) -> Result { + if let Ok(value) = u64::try_from(value) { + Ok(Value::new_u64(value, self.shared_ptr())) + } else if let Ok(value) = i64::try_from(value) { + Ok(Value::new_i64(value, self.shared_ptr())) + } else { + // FIXME: print i128 in error message + Err(Error::syntax(ErrorCode::NumberOutOfRange, b"", 0)) + } + } + + #[inline] + fn serialize_u8(self, value: u8) -> Result { + self.serialize_u64(value as u64) + } + + #[inline] + fn serialize_u16(self, value: u16) -> Result { + self.serialize_u64(value as u64) + } + + #[inline] + fn serialize_u32(self, value: u32) -> Result { + self.serialize_u64(value as u64) + } + + #[inline] + fn serialize_u64(self, value: u64) -> Result { + Ok(Value::new_u64(value, self.shared_ptr())) + } + + fn serialize_u128(self, value: u128) -> Result { + if let Ok(value) = u64::try_from(value) { + Ok(Value::new_u64(value, self.shared_ptr())) + } else { + Err(Error::syntax(ErrorCode::NumberOutOfRange, b"", 0)) + } + } + + #[inline] + fn serialize_f32(self, value: f32) -> Result { + if value.is_finite() { + Ok(unsafe { Value::new_f64_unchecked(value as f64, self.shared_ptr()) }) + } else { + Err(Error::syntax(ErrorCode::FloatMustBeFinite, b"", 0)) + } + } + + #[inline] + fn serialize_f64(self, value: f64) -> Result { + if value.is_finite() { + Ok(unsafe { Value::new_f64_unchecked(value, self.shared_ptr()) }) + } else { + Err(Error::syntax(ErrorCode::FloatMustBeFinite, b"", 0)) + } + } + + #[inline] + fn serialize_char(self, value: char) -> Result { + Ok(Value::copy_str(&value.to_string(), self.shared_ref())) + } + + #[inline] + fn serialize_str(self, value: &str) -> Result { + Ok(Value::copy_str(value, self.shared_ref())) + } + + // parse bytes as a array with u64 + fn serialize_bytes(self, value: &[u8]) -> Result { + let mut array = Value::new_array(self.shared_ptr(), value.len()); + for b in value.iter() { + array.append_value(Value::new_u64((*b) as u64, self.shared_ptr())); + } + Ok(array) + } + + #[inline] + fn serialize_unit_struct(self, _name: &'static str) -> Result { + self.serialize_unit() + } + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result { + self.serialize_str(variant) + } + + #[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 object = Value::new_object(self.shared_ptr(), 1); + let pair = ( + Value::new_str(variant, self.shared_ptr()), + tri!(to_value_in(self.shared(), value)), + ); + object.append_pair(pair); + Ok(object) + } + + #[inline] + fn serialize_none(self) -> Result { + self.serialize_unit() + } + + #[inline] + fn serialize_some(self, value: &T) -> Result + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + #[inline] + fn serialize_seq(self, len: Option) -> Result { + Ok(SerializeVec { + shared: self.shared(), + vec: Value::new_array(self.shared_ptr(), len.unwrap_or_default()), + }) + } + + #[inline] + fn serialize_tuple(self, len: usize) -> Result { + self.serialize_seq(Some(len)) + } + + #[inline] + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result { + self.serialize_seq(Some(len)) + } + + #[inline] + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + Ok(SerializeTupleVariant { + shared: self.shared(), + static_name: Value::new_str(variant, self.shared_ptr()), + vec: Value::new_array(self.shared_ptr(), len), + }) + } + + #[inline] + fn serialize_map(self, len: Option) -> Result { + Ok(SerializeMap { + map: MapInner::Object { + object: Value::new_object(self.shared_ptr(), len.unwrap_or_default()), + next_key: None, + }, + shared: self.shared(), + }) + } + + #[inline] + fn serialize_struct(self, name: &'static str, len: usize) -> Result { + match name { + crate::serde::number::TOKEN => Ok(SerializeMap { + map: MapInner::RawNumber { out_value: None }, + shared: self.shared(), + }), + crate::serde::raw::TOKEN => Ok(SerializeMap { + map: MapInner::RawValue { out_value: None }, + shared: self.shared(), + }), + _ => self.serialize_map(Some(len)), + } + } + + #[inline] + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + Ok(SerializeStructVariant { + shared: self.shared(), + static_name: Value::new_str(variant, self.shared_ptr()), + object: Value::new_object(self.shared_ptr(), len), + }) + } + + #[inline] + fn collect_str(self, value: &T) -> Result + where + T: ?Sized + Display, + { + self.serialize_str(&value.to_string()) + } +} + +/// Serializing Rust seq into `Value`. +pub(crate) struct SerializeVec { + shared: NonNull, + vec: Value, +} + +/// Serializing Rust tuple variant into `Value`. +pub(crate) struct SerializeTupleVariant { + shared: NonNull, + static_name: Value, + vec: Value, +} + +/// Serializing Rust into `Value`. We has special handling for `Number`, `RawNumber` and `RawValue`. +pub(crate) struct SerializeMap { + map: MapInner, + shared: NonNull, +} + +enum MapInner { + Object { + object: Value, + next_key: Option, // object key is value + }, + RawNumber { + out_value: Option, + }, + RawValue { + out_value: Option, + }, +} + +/// Serializing Rust struct variant into `Value`. +pub(crate) struct SerializeStructVariant { + static_name: Value, + object: Value, + shared: NonNull, +} + +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.append_value(tri!(to_value_in(self.shared, value))); + Ok(()) + } + + fn end(self) -> Result { + Ok(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.append_value(tri!(to_value_in(self.shared, value))); + Ok(()) + } + + fn end(self) -> Result { + let mut object = Value::new_object(self.shared.as_ptr(), 1); + object.append_pair((self.static_name, self.vec)); + Ok(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, + { + match &mut self.map { + MapInner::Object { next_key, .. } => { + *next_key = Some(tri!(key.serialize(MapKeySerializer(self.shared)))); + Ok(()) + } + MapInner::RawNumber { .. } => unreachable!(), + MapInner::RawValue { .. } => unreachable!(), + } + } + + fn serialize_value(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + match &mut self.map { + MapInner::Object { object, next_key } => { + let key = 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"); + object.append_pair((key, tri!(to_value_in(self.shared, value)))); + Ok(()) + } + MapInner::RawNumber { .. } => unreachable!(), + MapInner::RawValue { .. } => unreachable!(), + } + } + + fn end(self) -> Result { + match self.map { + MapInner::Object { object, .. } => Ok(object), + MapInner::RawNumber { .. } => unreachable!(), + MapInner::RawValue { .. } => unreachable!(), + } + } +} + +// Serialize the map key into a Value. +struct MapKeySerializer(NonNull); + +impl MapKeySerializer { + fn shared_ptr(&self) -> *const Shared { + self.0.as_ptr() + } +} + +fn key_must_be_a_string() -> Error { + Error::syntax(ErrorCode::ValueKeyMustBeString, b"", 0) +} + +fn float_key_must_be_finite() -> Error { + Error::syntax(ErrorCode::FloatMustBeFinite, b"", 0) +} + +impl serde::Serializer for MapKeySerializer { + type Ok = Value; + type Error = Error; + + type SerializeSeq = Impossible; + type SerializeTuple = Impossible; + type SerializeTupleStruct = Impossible; + type SerializeTupleVariant = Impossible; + type SerializeMap = Impossible; + type SerializeStruct = Impossible; + type SerializeStructVariant = Impossible; + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result { + Ok(Value::new_str(variant, self.shared_ptr())) + } + + #[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 { + if value { + Ok(Value::new_str("true", self.shared_ptr())) + } else { + Ok(Value::new_str("false", self.shared_ptr())) + } + } + + fn serialize_i8(self, value: i8) -> Result { + self.serialize_i64(value as i64) + } + + fn serialize_i16(self, value: i16) -> Result { + self.serialize_i64(value as i64) + } + + fn serialize_i32(self, value: i32) -> Result { + self.serialize_i64(value as i64) + } + + fn serialize_i64(self, value: i64) -> Result { + self.serialize_str(itoa::Buffer::new().format(value)) + } + + fn serialize_u8(self, value: u8) -> Result { + self.serialize_u64(value as u64) + } + + fn serialize_u16(self, value: u16) -> Result { + self.serialize_u64(value as u64) + } + + fn serialize_u32(self, value: u32) -> Result { + self.serialize_u64(value as u64) + } + + // FIXME: optimize the copy overhead + fn serialize_u64(self, value: u64) -> Result { + self.serialize_str(itoa::Buffer::new().format(value)) + } + + fn serialize_f32(self, value: f32) -> Result { + if value.is_finite() { + self.serialize_str(ryu::Buffer::new().format_finite(value)) + } else { + Err(float_key_must_be_finite()) + } + } + + fn serialize_f64(self, value: f64) -> Result { + if value.is_finite() { + self.serialize_str(ryu::Buffer::new().format_finite(value)) + } else { + Err(float_key_must_be_finite()) + } + } + + #[inline] + fn serialize_char(self, value: char) -> Result { + self.serialize_str(&value.to_string()) + } + + #[inline] + fn serialize_str(self, value: &str) -> Result { + let shared = unsafe { self.0.as_ref() }; + Ok(Value::copy_str(value, shared)) + } + + 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()) + } + + fn collect_str(self, value: &T) -> Result + where + T: ?Sized + Display, + { + self.serialize_str(&value.to_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, + { + match &mut self.map { + MapInner::Object { .. } => serde::ser::SerializeMap::serialize_entry(self, key, value), + MapInner::RawNumber { out_value: _ } => { + todo!() + } + MapInner::RawValue { out_value: _ } => { + todo!() + } + } + } + + fn end(self) -> Result { + match self.map { + MapInner::Object { .. } => serde::ser::SerializeMap::end(self), + MapInner::RawNumber { out_value, .. } => { + Ok(out_value.expect("number value was not emitted")) + } + MapInner::RawValue { out_value, .. } => { + Ok(out_value.expect("raw value was not emitted")) + } + } + } +} + +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.object.append_pair(( + Value::new_str(key, self.shared.as_ptr()), + tri!(to_value_in(self.shared, value)), + )); + Ok(()) + } + + fn end(self) -> Result { + let mut object = Value::new_object(self.shared.as_ptr(), 1); + object.append_pair((self.static_name, self.object)); + Ok(object) + } +} + +#[doc(hidden)] +#[inline] +pub fn to_value_in(shared: NonNull, value: &T) -> Result +where + T: ?Sized + Serialize, +{ + let serializer = Serializer::new_in(shared); + value.serialize(serializer) +} + +#[cfg(test)] +mod test { + + #[test] + fn test_to_value() { + use crate::json; + use crate::to_value; + use crate::Value; + #[derive(Debug, serde::Serialize)] + struct User { + string: String, + number: i32, + array: Vec, + } + + let user = User { + string: "hello".into(), + number: 123, + array: vec!["a".into(), "b".into(), "c".into()], + }; + let got: Value = to_value(&user).unwrap(); + let expect = json!({ + "string": "hello", + "number": 123, + "array": ["a", "b", "c"], + }); + assert_eq!(got, expect); + + let got: Value = to_value("hello").unwrap(); + assert_eq!(got, "hello"); + + let got: Value = to_value(&123).unwrap(); + assert_eq!(got, 123); + } +} diff --git a/src/value/shared.rs b/src/value/shared.rs new file mode 100644 index 0000000..8087013 --- /dev/null +++ b/src/value/shared.rs @@ -0,0 +1,72 @@ +use super::alloctor::SyncBump; +use crate::util::{arc::Arc, taggedptr::TaggedPtr}; +use std::{ + fmt::{Debug, Formatter}, + mem::ManuallyDrop, + sync::atomic::AtomicBool, +}; + +// Represent a shared allocator. +#[derive(Debug)] +#[repr(align(16))] +#[doc(hidden)] +pub struct Shared { + pub(crate) alloc: SyncBump, + // Whether there are multiple allocator in the `Value` tree. + // the flag is conservative to make sure no memory leaks, more details see `Drop` comments. + pub(crate) combined: AtomicBool, +} + +impl Debug for Arc { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Shared") + .field("refcnt", &self.refcnt()) + .field("combined", &self.combined) + .field("allocator address", &self.alloc.0.data_ptr()) + .finish() + } +} + +impl Default for Shared { + fn default() -> Self { + Self::new() + } +} + +impl Shared { + pub(crate) fn new() -> Self { + Self { + alloc: SyncBump::new(), + combined: AtomicBool::new(false), + } + } + + #[doc(hidden)] + pub fn new_ptr() -> *const Shared { + ManuallyDrop::new(Arc::new(Shared::new())).data_ptr() + } + + /// there are no way to convert the `combined` from true to false + /// so we can use relaxed ordering here. + /// And The origin refcnt of Shared prevents other threads from erroneously deleting + // the shared allocator. + pub(crate) fn is_combined(&self) -> bool { + self.combined.load(std::sync::atomic::Ordering::Relaxed) + } + + /// The origin refcnt of Shared prevents other threads from erroneously deleting + // the shared allocator. + pub(crate) fn set_combined(&self) { + self.combined + .store(true, std::sync::atomic::Ordering::Relaxed); + } +} + +/// TaggedPtr is not arc +impl Clone for TaggedPtr { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for TaggedPtr {} diff --git a/src/value/tryfrom.rs b/src/value/tryfrom.rs new file mode 100644 index 0000000..7ee9b93 --- /dev/null +++ b/src/value/tryfrom.rs @@ -0,0 +1,53 @@ +use super::Value; +use crate::Number; + +impl TryFrom for Value { + type Error = crate::Error; + + /// Try convert a f32 to `Value`. If the float is NaN or infinity, return a error. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::Value; + /// use sonic_rs::JsonValueTrait; + /// + /// let f1: f32 = 2.333; + /// let x1: Value = f1.try_into().unwrap(); + /// assert_eq!(x1, f1); + /// + /// let x2: Value = f32::INFINITY.try_into().unwrap_or_default(); + /// let x3: Value = f32::NAN.try_into().unwrap_or_default(); + /// + /// assert!(x2.is_null() && x3.is_null()); + /// ``` + #[inline] + fn try_from(value: f32) -> Result { + Number::try_from(value).map(Into::into) + } +} + +impl TryFrom for Value { + /// Try convert a f64 to `Value`. If the float is NaN or infinity, return a error. + /// + /// # Examples + /// + /// ``` + /// use sonic_rs::Value; + /// use sonic_rs::JsonValueTrait; + /// + /// let f1: f64 = 2.333; + /// let x1: Value = f1.try_into().unwrap(); + /// assert_eq!(x1, 2.333); + /// + /// let x2: Value = f64::INFINITY.try_into().unwrap_or_default(); + /// let x3: Value = f64::NAN.try_into().unwrap_or_default(); + /// + /// assert!(x2.is_null() && x3.is_null()); + /// ``` + type Error = crate::Error; + #[inline] + fn try_from(value: f64) -> Result { + Number::try_from(value).map(Into::into) + } +} diff --git a/src/value/value_trait.rs b/src/value/value_trait.rs index 152661a..5ef8fd7 100644 --- a/src/value/value_trait.rs +++ b/src/value/value_trait.rs @@ -1,4 +1,6 @@ -use crate::{value::Index, JsonNumberTrait, JsonPointer, Number}; +use super::index::Index; +use super::index::IndexMut; +use crate::{JsonNumberTrait, JsonPointer, Number}; /// JsonType is an enum that represents the type of a JSON value. #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -13,6 +15,11 @@ pub enum JsonType { Raw = 6, } +/* +Static: NULL, TRUE, FALSE +INT, Uint, Float, String, Array, Object, Raw +*/ + impl From for JsonType { fn from(value: u8) -> Self { match value { @@ -29,10 +36,10 @@ impl From for JsonType { } /// A trait for all JSON values. Used by `Value` and `LazyValue`. -pub trait JsonValue: Sized { - type ValueType<'dom> +pub trait JsonValueTrait { + type ValueType<'v> where - Self: 'dom; + Self: 'v; /// get the type of the `JsonValue`. fn get_type(&self) -> JsonType; @@ -138,11 +145,41 @@ pub trait JsonValue: Sized { fn pointer(&self, path: &JsonPointer) -> Option>; } +/// A trait for all JSON object or array values. Used by `Value`. +pub trait JsonContainerTrait { + type ObjectType; + type ArrayType; + + /// Returns the object if the `JsonValue` is an `object`. + fn as_object(&self) -> Option<&Self::ObjectType>; + + /// Returns the array if the `JsonValue` is an `object`. + fn as_array(&self) -> Option<&Self::ArrayType>; +} + +/// A trait for all JSON values. Used by `Value` and `LazyValue`. +pub trait JsonValueMutTrait { + type ValueType; + type ObjectType; + type ArrayType; + + /// Returns the mutable object if the `JsonValue` is an `object`. + fn as_object_mut(&mut self) -> Option<&mut Self::ObjectType>; + + /// Returns the mutable array if the `JsonValue` is an `array`. + fn as_array_mut(&mut self) -> Option<&mut Self::ArrayType>; + + /// Returns the value from pointer path if the `JsonValue` is an `array` or `object` + fn pointer_mut(&mut self, path: &JsonPointer) -> Option<&mut Self::ValueType>; + + /// Returns the value from index if the `JsonValue` is an `array` or `object` + /// The index may be usize or &str. The `usize` is for array, the `&str` is for object. + fn get_mut(&mut self, index: I) -> Option<&mut Self::ValueType>; +} + // A helper trait for Option types -impl JsonValue for Option { - type ValueType<'dom> = V::ValueType<'dom> - where - V:'dom, Self: 'dom; +impl JsonValueTrait for Option { + type ValueType<'v> = V::ValueType<'v> where V:'v, Self: 'v; fn as_bool(&self) -> Option { self.as_ref().and_then(|v| v.as_bool()) @@ -181,11 +218,43 @@ impl JsonValue for Option { } } +impl JsonContainerTrait for Option { + type ArrayType = V::ArrayType; + type ObjectType = V::ObjectType; + + fn as_array(&self) -> Option<&Self::ArrayType> { + self.as_ref().and_then(|v| v.as_array()) + } + + fn as_object(&self) -> Option<&Self::ObjectType> { + self.as_ref().and_then(|v| v.as_object()) + } +} + +impl JsonValueMutTrait for Option { + type ValueType = V::ValueType; + type ArrayType = V::ArrayType; + type ObjectType = V::ObjectType; + + fn as_array_mut(&mut self) -> Option<&mut Self::ArrayType> { + self.as_mut().and_then(|v| v.as_array_mut()) + } + fn as_object_mut(&mut self) -> Option<&mut Self::ObjectType> { + self.as_mut().and_then(|v| v.as_object_mut()) + } + + fn pointer_mut(&mut self, path: &JsonPointer) -> Option<&mut Self::ValueType> { + self.as_mut().and_then(|v| v.pointer_mut(path)) + } + + fn get_mut(&mut self, index: I) -> Option<&mut Self::ValueType> { + self.as_mut().and_then(|v| v.get_mut(index)) + } +} + // A helper trait for Result types -impl JsonValue for Result { - type ValueType<'dom> = V::ValueType<'dom> - where - V:'dom, Self: 'dom; +impl JsonValueTrait for Result { + type ValueType<'v> = V::ValueType<'v> where V:'v, Self: 'v; fn as_bool(&self) -> Option { self.as_ref().ok().and_then(|v| v.as_bool()) @@ -224,11 +293,42 @@ impl JsonValue for Result { } } -// A helper trait for reference types -impl JsonValue for &V { - type ValueType<'dom> = V::ValueType<'dom> - where - V:'dom, Self: 'dom; +impl JsonContainerTrait for Result { + type ArrayType = V::ArrayType; + type ObjectType = V::ObjectType; + fn as_array(&self) -> Option<&Self::ArrayType> { + self.as_ref().ok().and_then(|v| v.as_array()) + } + + fn as_object(&self) -> Option<&Self::ObjectType> { + self.as_ref().ok().and_then(|v| v.as_object()) + } +} + +impl JsonValueMutTrait for Result { + type ValueType = V::ValueType; + type ArrayType = V::ArrayType; + type ObjectType = V::ObjectType; + + fn as_array_mut(&mut self) -> Option<&mut Self::ArrayType> { + self.as_mut().ok().and_then(|v| v.as_array_mut()) + } + + fn as_object_mut(&mut self) -> Option<&mut Self::ObjectType> { + self.as_mut().ok().and_then(|v| v.as_object_mut()) + } + + fn pointer_mut(&mut self, path: &JsonPointer) -> Option<&mut Self::ValueType> { + self.as_mut().ok().and_then(|v| v.pointer_mut(path)) + } + + fn get_mut(&mut self, index: I) -> Option<&mut Self::ValueType> { + self.as_mut().ok().and_then(|v| v.get_mut(index)) + } +} + +impl JsonValueTrait for &V { + type ValueType<'v> = V::ValueType<'v> where V:'v, Self: 'v; fn as_bool(&self) -> Option { (*self).as_bool() @@ -267,45 +367,37 @@ impl JsonValue for &V { } } -// A helper trait for reference types -impl JsonValue for &mut V { - type ValueType<'dom> = V::ValueType<'dom> - where - V:'dom, Self: 'dom; +impl JsonContainerTrait for &V { + type ArrayType = V::ArrayType; + type ObjectType = V::ObjectType; - fn as_bool(&self) -> Option { - (**self).as_bool() - } - - fn as_f64(&self) -> Option { - (**self).as_f64() + fn as_array(&self) -> Option<&Self::ArrayType> { + (*self).as_array() } - fn as_i64(&self) -> Option { - (**self).as_i64() - } - - fn as_u64(&self) -> Option { - (**self).as_u64() + fn as_object(&self) -> Option<&Self::ObjectType> { + (*self).as_object() } +} - fn as_number(&self) -> Option { - (**self).as_number() - } +impl JsonValueMutTrait for &mut V { + type ValueType = V::ValueType; + type ArrayType = V::ArrayType; + type ObjectType = V::ObjectType; - fn get_type(&self) -> JsonType { - (**self).get_type() + fn as_array_mut(&mut self) -> Option<&mut Self::ArrayType> { + (*self).as_array_mut() } - fn as_str(&self) -> Option<&str> { - (**self).as_str() + fn as_object_mut(&mut self) -> Option<&mut Self::ObjectType> { + (*self).as_object_mut() } - fn get(&self, index: I) -> Option> { - (**self).get(index) + fn get_mut(&mut self, index: I) -> Option<&mut Self::ValueType> { + (**self).get_mut(index) } - fn pointer(&self, path: &JsonPointer) -> Option> { - (**self).pointer(path) + fn pointer_mut(&mut self, path: &JsonPointer) -> Option<&mut Self::ValueType> { + (*self).pointer_mut(path) } } diff --git a/src/writer.rs b/src/writer.rs index fc64a45..4f2c6c0 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -55,7 +55,7 @@ impl WriterExt for Writer { } } -impl WriterExt for &mut W { +impl WriterExt for &mut W { #[inline(always)] unsafe fn add_len(&mut self, additional: usize) { (*self).add_len(additional) @@ -67,7 +67,7 @@ impl WriterExt for &mut W { } } -impl WriterExt for Box { +impl WriterExt for Box { #[inline(always)] unsafe fn add_len(&mut self, additional: usize) { (**self).add_len(additional)