From 9690c7e1ea3131a4b24263746e2b5fdae5e5a83a Mon Sep 17 00:00:00 2001 From: Martin Bartlett Date: Thu, 21 Dec 2023 17:40:33 +0100 Subject: [PATCH 01/11] Tests all passing --- Cargo.toml | 24 ++++---- README.md | 16 ++++-- examples/create_from_str_array.rs | 8 +-- src/borrowed.rs | 90 ++++++++++++++++++++++++++++++ src/lib.rs | 88 ++++++++++++++--------------- src/owned.rs | 90 ++++++++++++++++++++++++++++++ src/parser/mod.rs | 2 +- src/parser/string_repr.rs | 14 ++--- src/parser/uri_fragment.rs | 2 +- src/ptr.rs | 93 ++----------------------------- tests/macros.rs | 1 + tests/parsing.rs | 23 +++----- tests/push_pop.rs | 7 +-- tests/rfc.rs | 23 ++++---- 14 files changed, 283 insertions(+), 198 deletions(-) create mode 100644 src/borrowed.rs create mode 100644 src/owned.rs diff --git a/Cargo.toml b/Cargo.toml index ec1dfc5..8e768df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,24 +1,20 @@ [package] -authors = ["Nathaniel Ringo "] -description = "A crate for parsing and using JSON pointers, as specified in RFC 6901." -documentation = "https://docs.rs/json-pointer" -homepage = "https://github.com/remexre/json-pointer" +authors = ["Nathaniel Ringo ", "Martin Bartlett "] +description = "A crate for parsing and using JSON pointers with simd_json, as specified in RFC 6901." +documentation = "https://docs.rs/json-pointer-simd" +homepage = "https://github.com/remexre/json-pointer-simd" license = "MIT" -name = "json-pointer" +name = "json-pointer-simd" readme = "README.md" -repository = "https://github.com/remexre/json-pointer" -version = "0.3.2" - -[badges] - -[badges.travis-ci] -branch = "master" -repository = "remexre/json-pointer" +repository = "https://github.com/remexre/json-pointer-simd" +version = "0.1.0" +edition = "2021" [dependencies] -serde_json = "^1.0.2" +simd-json = "0.13.4" [dev-dependencies] lazy_static = "^0.2.8" quickcheck = "^0.4.1" regex = "^0.2.2" +once_cell = "1.19.0" diff --git a/README.md b/README.md index 3ddd41e..c451c29 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,22 @@ # json-pointer +This crate is a straight conversion of the [json-pointer]() crate, but for use +with `simd_json` instead of `serde_json`. While simde_json and serde_json expose +similar APIs, neither attempts to implement the traits of the other, making an +across-the-board generic implementation quite difficult to achieve. So, instead, I +opted to fork the original project and adapt it to simd_json Value types. The fact +is that if you persuaded by the benefits of simd_json, you can pretty much drop it +in to standard ser/deser workloads in place of serde_json. + +I also made some updates to the code to use the 2021 semantics of Rust. + +Otherwise, all the code, examples, and tests are those of the original author. + A crate for parsing and using JSON pointers, as specified in [RFC 6901](https://tools.ietf.org/html/rfc6901). Unlike the `pointer` method built into `serde_json`, this handles both validating JSON Pointers before use and the URI Fragment Identifier Representation. -[![Build Status](https://travis-ci.org/remexre/json-pointer.svg?branch=master)](https://travis-ci.org/remexre/json-pointer) -[![crates.io](https://img.shields.io/crates/v/json-pointer.svg)](https://crates.io/crates/json-pointer) -[![Documentation](https://docs.rs/json-pointer/badge.svg)](https://docs.rs/json-pointer) - ## Creating a JSON Pointer JSON pointers can be created with a literal `[&str]`, or parsed from a `String`. diff --git a/examples/create_from_str_array.rs b/examples/create_from_str_array.rs index 7ccb416..69c0dc0 100644 --- a/examples/create_from_str_array.rs +++ b/examples/create_from_str_array.rs @@ -1,8 +1,6 @@ -extern crate json_pointer; -#[macro_use] -extern crate serde_json; - -use json_pointer::JsonPointer; +use json_pointer_simd::JsonPointer; +use simd_json::json; +use json_pointer_simd::JsonPointerValueGetter; fn main() { let ptr = JsonPointer::new([ diff --git a/src/borrowed.rs b/src/borrowed.rs new file mode 100644 index 0000000..f106cc8 --- /dev/null +++ b/src/borrowed.rs @@ -0,0 +1,90 @@ +use std::ops::{Index, IndexMut}; +use crate::{JsonPointer, JsonPointerValueGetter, IndexError}; + +/// Implement getting for SIMD JSON Borrowed values +/// +impl<'value,S: AsRef, C: AsRef<[S]>> JsonPointerValueGetter> for JsonPointer { + + /// Attempts to get a reference to a value from the given JSON value, + /// returning an error if it can't be found. + fn get<'json>(&self, val: &'json simd_json::BorrowedValue<'value>) -> Result<&'json simd_json::BorrowedValue<'value>, IndexError> { + self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| { + let tok = tok.as_ref(); + match *val { + simd_json::BorrowedValue::Object(ref obj) => obj.get(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), + simd_json::BorrowedValue::Array(ref arr) => { + let idx = if tok == "-" { + arr.len() + } else if let Ok(idx) = tok.parse() { + idx + } else { + return Err(IndexError::NoSuchKey(tok.to_owned())); + }; + arr.get(idx).ok_or(IndexError::OutOfBounds(idx)) + }, + _ => Err(IndexError::NotIndexable), + } + })) + } + + /// Attempts to get a mutable reference to a value from the given JSON + /// value, returning an error if it can't be found. + fn get_mut<'json>(&self, val: &'json mut simd_json::BorrowedValue<'value>) -> Result<&'json mut simd_json::BorrowedValue<'value>, IndexError> { + self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| { + let tok = tok.as_ref(); + match *val { + simd_json::BorrowedValue::Object(ref mut obj) => obj.get_mut(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), + simd_json::BorrowedValue::Array(ref mut arr) => { + let idx = if tok == "-" { + arr.len() + } else if let Ok(idx) = tok.parse() { + idx + } else { + return Err(IndexError::NoSuchKey(tok.to_owned())); + }; + arr.get_mut(idx).ok_or(IndexError::OutOfBounds(idx)) + }, + _ => Err(IndexError::NotIndexable), + } + })) + } + + /// Attempts to get an owned value from the given JSON value, returning an + /// error if it can't be found. + fn get_owned(&self, val: simd_json::BorrowedValue<'value>) -> Result, IndexError> { + self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| { + let tok = tok.as_ref(); + match val { + simd_json::BorrowedValue::Object(mut obj) => obj.remove(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), + simd_json::BorrowedValue::Array(mut arr) => { + let idx = if tok == "-" { + arr.len() + } else if let Ok(idx) = tok.parse() { + idx + } else { + return Err(IndexError::NoSuchKey(tok.to_owned())); + }; + if idx >= arr.len() { + Err(IndexError::OutOfBounds(idx)) + } else { + Ok(arr.swap_remove(idx)) + } + }, + _ => Err(IndexError::NotIndexable), + } + })) + } +} + +impl<'a, S: AsRef, C: AsRef<[S]>> Index<&'a JsonPointer> for simd_json::BorrowedValue<'a> { + type Output = simd_json::BorrowedValue<'a>; + fn index(&self, ptr: &'a JsonPointer) -> &simd_json::BorrowedValue<'a> { + ptr.get(self).unwrap() + } +} + +impl<'a, S: AsRef, C: AsRef<[S]>> IndexMut<&'a JsonPointer> for simd_json::BorrowedValue<'a> { + fn index_mut(&mut self, ptr: &'a JsonPointer) -> &mut simd_json::BorrowedValue<'a> { + ptr.get_mut(self).unwrap() + } +} diff --git a/src/lib.rs b/src/lib.rs index ee1ab05..9e71d30 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,30 +1,22 @@ -//! A crate for parsing and using JSON pointers, as specified in [RFC +//! A crate for parsing and using JSON pointers with simd_json values, as specified in [RFC //! 6901](https://tools.ietf.org/html/rfc6901). Unlike the `pointer` method //! built into `serde_json`, this handles both validating JSON Pointers before //! use and the URI Fragment Identifier Representation. //! -//! [![Build Status](https://travis-ci.org/remexre/json-pointer.svg?branch=master)](https://travis-ci.org/remexre/json-pointer) -//! [![crates.io](https://img.shields.io/crates/v/json-pointer.svg)](https://crates.io/crates/json-pointer) -//! [![Documentation](https://docs.rs/json-pointer/badge.svg)](https://docs.rs/json-pointer) -//! //! ## Creating a JSON Pointer //! //! JSON pointers can be created with a literal `[&str]`, or parsed from a `String`. //! //! ```rust -//! extern crate json_pointer; -//! -//! use json_pointer::JsonPointer; +//! use json_pointer_simd::{JsonPointer,JsonPointerValueGetter}; //! -//! fn main() { -//! let from_strs = JsonPointer::new([ -//! "foo", -//! "bar", -//! ]); -//! let parsed = "/foo/bar".parse::>().unwrap(); +//! let from_strs = JsonPointer::new([ +//! "foo", +//! "bar", +//! ]); +//! let parsed = "/foo/bar".parse::>().unwrap(); //! -//! assert_eq!(from_strs.to_string(), parsed.to_string()); -//! } +//! assert_eq!(from_strs.to_string(), parsed.to_string()); //! ``` //! //! ## Using a JSON Pointer @@ -33,27 +25,21 @@ //! and mutable references to the appropriate value, respectively. //! //! ```rust -//! extern crate json_pointer; -//! #[macro_use] -//! extern crate serde_json; +//! use simd_json::json; +//! use json_pointer_simd::{JsonPointer,JsonPointerValueGetter}; //! -//! use json_pointer::JsonPointer; -//! -//! fn main() { -//! let ptr = "/foo/bar".parse::>().unwrap(); -//! -//! let document = json!({ -//! "foo": { -//! "bar": 0, -//! "baz": 1, -//! }, -//! "quux": "xyzzy" -//! }); +//! let ptr = "/foo/bar".parse::>().unwrap(); //! -//! let indexed = ptr.get(&document).unwrap(); +//! let document = json!({ +//! "foo": { +//! "bar": 0, +//! "baz": 1, +//! }, +//! "quux": "xyzzy" +//! }); +//! let indexed = ptr.get(&document).unwrap(); //! -//! assert_eq!(indexed, &json!(0)); -//! } +//! assert_eq!(indexed, &json!(0)); //! ``` //! //! ## URI Fragment Identifier Representation @@ -65,25 +51,39 @@ //! crate does not support parsing full URIs. //! //! ```rust -//! extern crate json_pointer; +//! use json_pointer_simd::{JsonPointer,JsonPointerValueGetter}; //! -//! use json_pointer::JsonPointer; -//! -//! fn main() { -//! let str_ptr = "/f%o".parse::>().unwrap(); -//! let uri_ptr = "#/f%25o".parse::>().unwrap(); +//! let str_ptr = "/f%o".parse::>().unwrap(); +//! let uri_ptr = "#/f%25o".parse::>().unwrap(); //! -//! assert_eq!(str_ptr, uri_ptr); -//! } +//! assert_eq!(str_ptr, uri_ptr); //! ``` #![deny(missing_docs)] -extern crate serde_json; - mod parser; +mod owned; +mod borrowed; mod ptr; pub use parser::ParseError; pub use ptr::IndexError; pub use ptr::JsonPointer; + +/// +/// The trait that provides access to the data referenced by the JsonPointer. +/// This trait is implemented for both [OwnedValue] and [BorrowedValue]. +/// +pub trait JsonPointerValueGetter + where V: simd_json::base::TypedValue { + + /// Attempts to get a reference to a value from the given JSON value, + /// returning an error if it can't be found. + fn get<'json>(&self, val: &'json V) -> Result<&'json V, IndexError>; + /// Attempts to get a mutable reference to a value from the given JSON + /// value, returning an error if it can't be found. + fn get_mut<'json>(&self, val: &'json mut V) -> Result<&'json mut V, IndexError>; + /// Attempts to get an owned value from the given JSON value, returning an + /// error if it can't be found. + fn get_owned(&self, val: V) -> Result; +} diff --git a/src/owned.rs b/src/owned.rs new file mode 100644 index 0000000..7eaf7e7 --- /dev/null +++ b/src/owned.rs @@ -0,0 +1,90 @@ +use std::ops::{Index, IndexMut}; +use crate::{JsonPointer, JsonPointerValueGetter, IndexError}; + +/// Implement getting for SIMD JSON Owned values +/// +impl, C: AsRef<[S]>> JsonPointerValueGetter for JsonPointer { + + /// Attempts to get a reference to a value from the given JSON value, + /// returning an error if it can't be found. + fn get<'json>(&self, val: &'json simd_json::OwnedValue) -> Result<&'json simd_json::OwnedValue, IndexError> { + self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| { + let tok = tok.as_ref(); + match *val { + simd_json::OwnedValue::Object(ref obj) => obj.get(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), + simd_json::OwnedValue::Array(ref arr) => { + let idx = if tok == "-" { + arr.len() + } else if let Ok(idx) = tok.parse() { + idx + } else { + return Err(IndexError::NoSuchKey(tok.to_owned())); + }; + arr.get(idx).ok_or(IndexError::OutOfBounds(idx)) + }, + _ => Err(IndexError::NotIndexable), + } + })) + } + + /// Attempts to get a mutable reference to a value from the given JSON + /// value, returning an error if it can't be found. + fn get_mut<'json>(&self, val: &'json mut simd_json::OwnedValue) -> Result<&'json mut simd_json::OwnedValue, IndexError> { + self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| { + let tok = tok.as_ref(); + match *val { + simd_json::OwnedValue::Object(ref mut obj) => obj.get_mut(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), + simd_json::OwnedValue::Array(ref mut arr) => { + let idx = if tok == "-" { + arr.len() + } else if let Ok(idx) = tok.parse() { + idx + } else { + return Err(IndexError::NoSuchKey(tok.to_owned())); + }; + arr.get_mut(idx).ok_or(IndexError::OutOfBounds(idx)) + }, + _ => Err(IndexError::NotIndexable), + } + })) + } + + /// Attempts to get an owned value from the given JSON value, returning an + /// error if it can't be found. + fn get_owned(&self, val: simd_json::OwnedValue) -> Result { + self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| { + let tok = tok.as_ref(); + match val { + simd_json::OwnedValue::Object(mut obj) => obj.remove(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), + simd_json::OwnedValue::Array(mut arr) => { + let idx = if tok == "-" { + arr.len() + } else if let Ok(idx) = tok.parse() { + idx + } else { + return Err(IndexError::NoSuchKey(tok.to_owned())); + }; + if idx >= arr.len() { + Err(IndexError::OutOfBounds(idx)) + } else { + Ok(arr.swap_remove(idx)) + } + }, + _ => Err(IndexError::NotIndexable), + } + })) + } +} + +impl<'a, S: AsRef, C: AsRef<[S]>> Index<&'a JsonPointer> for simd_json::OwnedValue { + type Output = simd_json::OwnedValue; + fn index(&self, ptr: &'a JsonPointer) -> &simd_json::OwnedValue { + ptr.get(self).unwrap() + } +} + +impl<'a, S: AsRef, C: AsRef<[S]>> IndexMut<&'a JsonPointer> for simd_json::OwnedValue { + fn index_mut(&mut self, ptr: &'a JsonPointer) -> &mut simd_json::OwnedValue { + ptr.get_mut(self).unwrap() + } +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 0c9c4d5..30cbec0 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,7 +1,7 @@ mod string_repr; mod uri_fragment; -use JsonPointer; +use crate::JsonPointer; /// A parser for JSON pointers. If the string starts with a `#`, it is parsed /// as a URI fragment. Otherwise, it is parsed in the string representation. diff --git a/src/parser/string_repr.rs b/src/parser/string_repr.rs index a3ba145..e0e37f2 100644 --- a/src/parser/string_repr.rs +++ b/src/parser/string_repr.rs @@ -1,7 +1,6 @@ //! A parser for JSON pointers. - -use JsonPointer; -use parser::ParseError; +use crate::parser::ParseError; +use crate::JsonPointer; /// A single token encountered when parsing a JSON pointer. #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] @@ -23,10 +22,9 @@ pub enum Escape { /// The `/` character, which is escaped as `~1`. Slash = 1, } - -impl Into for Escape { - fn into(self) -> char { - match self { +impl From for char { + fn from(val: Escape) -> Self { + match val { Escape::Tilde => '~', Escape::Slash => '/', } @@ -43,7 +41,7 @@ pub fn parse>(ii: II) -> Result 0).unwrap_or(false) { + if iter.next().map(|s| !s.is_empty()).unwrap_or(false) { return Err(ParseError::NoLeadingSlash); } diff --git a/src/parser/uri_fragment.rs b/src/parser/uri_fragment.rs index 6424502..e682a69 100644 --- a/src/parser/uri_fragment.rs +++ b/src/parser/uri_fragment.rs @@ -1,4 +1,4 @@ -use parser::ParseError; +use crate::parser::ParseError; /// An iterator that unescapes URI fragments. pub struct UnescapeIter> { diff --git a/src/ptr.rs b/src/ptr.rs index 57aeeb0..d9d84a7 100644 --- a/src/ptr.rs +++ b/src/ptr.rs @@ -1,19 +1,19 @@ use parser::{parse, ParseError}; -use serde_json::Value; use std::fmt::{Display, Formatter}; use std::fmt::Result as FmtResult; use std::fmt::Write; use std::marker::PhantomData; -use std::ops::{Index, IndexMut}; use std::str::FromStr; +use crate::parser; + /// A JSON Pointer. /// /// Create a new JSON pointer with [`JsonPointer::new`](#method.new), or parse one from a /// string with [`str::parse()`](https://doc.rust-lang.org/std/primitive.str.html#method.parse). #[derive(Clone, Debug, Eq, PartialEq)] pub struct JsonPointer, C: AsRef<[S]>> { - ref_toks: C, + pub(crate) ref_toks: C, _phantom: PhantomData, } @@ -21,87 +21,17 @@ impl, C: AsRef<[S]>> JsonPointer { /// Creates a new JsonPointer from the given reference tokens. pub fn new(ref_toks: C) -> JsonPointer { JsonPointer { - ref_toks: ref_toks, + ref_toks, _phantom: PhantomData, } } - /// Attempts to get a reference to a value from the given JSON value, - /// returning an error if it can't be found. - pub fn get<'json>(&self, val: &'json Value) -> Result<&'json Value, IndexError> { - self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| { - let tok = tok.as_ref(); - match *val { - Value::Object(ref obj) => obj.get(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), - Value::Array(ref arr) => { - let idx = if tok == "-" { - arr.len() - } else if let Ok(idx) = tok.parse() { - idx - } else { - return Err(IndexError::NoSuchKey(tok.to_owned())); - }; - arr.get(idx).ok_or(IndexError::OutOfBounds(idx)) - }, - _ => Err(IndexError::NotIndexable), - } - })) - } - - /// Attempts to get a mutable reference to a value from the given JSON - /// value, returning an error if it can't be found. - pub fn get_mut<'json>(&self, val: &'json mut Value) -> Result<&'json mut Value, IndexError> { - self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| { - let tok = tok.as_ref(); - match *val { - Value::Object(ref mut obj) => obj.get_mut(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), - Value::Array(ref mut arr) => { - let idx = if tok == "-" { - arr.len() - } else if let Ok(idx) = tok.parse() { - idx - } else { - return Err(IndexError::NoSuchKey(tok.to_owned())); - }; - arr.get_mut(idx).ok_or(IndexError::OutOfBounds(idx)) - }, - _ => Err(IndexError::NotIndexable), - } - })) - } - - /// Attempts to get an owned value from the given JSON value, returning an - /// error if it can't be found. - pub fn get_owned(&self, val: Value) -> Result { - self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| { - let tok = tok.as_ref(); - match val { - Value::Object(mut obj) => obj.remove(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), - Value::Array(mut arr) => { - let idx = if tok == "-" { - arr.len() - } else if let Ok(idx) = tok.parse() { - idx - } else { - return Err(IndexError::NoSuchKey(tok.to_owned())); - }; - if idx >= arr.len() { - Err(IndexError::OutOfBounds(idx)) - } else { - Ok(arr.swap_remove(idx)) - } - }, - _ => Err(IndexError::NotIndexable), - } - })) - } - /// Converts a JSON pointer to a string in URI Fragment Identifier /// Representation, including the leading `#`. pub fn uri_fragment(&self) -> String { fn legal_fragment_byte(b: u8) -> bool { match b { - 0x21 | 0x24 | 0x26...0x3b | 0x3d | 0x3f...0x5a | 0x5f | 0x61...0x7a => true, + 0x21 | 0x24 | 0x26..=0x3b | 0x3d | 0x3f..=0x5a | 0x5f | 0x61..=0x7a => true, _ => false, } } @@ -166,16 +96,3 @@ pub enum IndexError { /// The pointer pointed to an out-of-bounds value in an array. OutOfBounds(usize), } - -impl<'a, S: AsRef, C: AsRef<[S]>> Index<&'a JsonPointer> for Value { - type Output = Value; - fn index(&self, ptr: &'a JsonPointer) -> &Value { - ptr.get(self).unwrap() - } -} - -impl<'a, S: AsRef, C: AsRef<[S]>> IndexMut<&'a JsonPointer> for Value { - fn index_mut(&mut self, ptr: &'a JsonPointer) -> &mut Value { - ptr.get_mut(self).unwrap() - } -} diff --git a/tests/macros.rs b/tests/macros.rs index ff4b230..a68a3f6 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -1,3 +1,4 @@ +#[allow(unused_macros)] macro_rules! assert_unparse { ($expr:expr) => { let ptr = $expr.parse::>().unwrap(); diff --git a/tests/parsing.rs b/tests/parsing.rs index 9d846f0..3d0cc60 100644 --- a/tests/parsing.rs +++ b/tests/parsing.rs @@ -1,21 +1,14 @@ -extern crate json_pointer; -#[macro_use] -extern crate lazy_static; -#[macro_use] -extern crate quickcheck; -extern crate regex; #[macro_use] mod macros; -use json_pointer::JsonPointer; -use quickcheck::TestResult; +use json_pointer_simd::JsonPointer; +use once_cell::sync::Lazy; +use quickcheck::{quickcheck, TestResult}; use regex::Regex; -lazy_static! { - static ref JSON_POINTER_REGEX: Regex = Regex::new("^(/([^/~]|~[01])*)*$").unwrap(); - static ref URI_FRAGMENT_REGEX: Regex = Regex::new("^#(/([^A-Za-z0-9._!$&'()*+,;=@/?-]|~[01]|%[0-9a-fA-F]{2})*)*$").unwrap(); -} +static JSON_POINTER_REGEX: Lazy = Lazy::new(||Regex::new("^(/([^/~]|~[01])*)*$").unwrap()); +static URI_FRAGMENT_REGEX: Lazy = Lazy::new(||Regex::new("^#(/([^A-Za-z0-9._!$&'()*+,;=@/?-]|~[01]|%[0-9a-fA-F]{2})*)*$").unwrap()); quickcheck! { @@ -26,12 +19,12 @@ fn faithful_parse(s: String) -> TestResult { let ok = match s.parse::>() { Ok(ptr) => if s.chars().next() == Some('#') { if URI_FRAGMENT_REGEX.is_match(&s) { - (s == ptr.uri_fragment()) + s == ptr.uri_fragment() } else { return TestResult::discard(); } } else { - (s == ptr.to_string()) + s == ptr.to_string() }, Err(_) => return TestResult::discard(), }; @@ -49,7 +42,7 @@ fn parses_all_valid(s: String) -> bool { let matches_regex = JSON_POINTER_REGEX.is_match(&s) || URI_FRAGMENT_REGEX.is_match(&s); let parses = s.parse::>().is_ok(); - (matches_regex == parses) + matches_regex == parses } } diff --git a/tests/push_pop.rs b/tests/push_pop.rs index 3334212..719d95a 100644 --- a/tests/push_pop.rs +++ b/tests/push_pop.rs @@ -1,8 +1,5 @@ -extern crate json_pointer; -#[macro_use] -extern crate quickcheck; - -use json_pointer::JsonPointer; +use quickcheck::quickcheck; +use json_pointer_simd::JsonPointer; use quickcheck::TestResult; quickcheck! { diff --git a/tests/rfc.rs b/tests/rfc.rs index 61d17ab..6f7dde2 100644 --- a/tests/rfc.rs +++ b/tests/rfc.rs @@ -1,14 +1,11 @@ -extern crate json_pointer; -#[macro_use] -extern crate lazy_static; -#[macro_use] -extern crate serde_json; +use json_pointer_simd::JsonPointer; +use json_pointer_simd::JsonPointerValueGetter; +use once_cell::sync::Lazy; +use simd_json::OwnedValue; +use simd_json::json; -use json_pointer::JsonPointer; -use serde_json::Value; - -lazy_static! { - static ref JSON: Value = json!({ +static JSON: Lazy = Lazy::new(|| + json!({ "foo": ["bar", "baz"], "": 0, "a/b": 1, @@ -19,8 +16,8 @@ lazy_static! { "k\"l": 6, " ": 7, "m~n": 8, - }); -} + }) +); macro_rules! rfc_tests { ($($ptr:expr => $json:tt;)*) => { @@ -30,7 +27,7 @@ macro_rules! rfc_tests { fn rfc_tests() { $({ let ptr = $ptr.parse::>().unwrap(); - assert_eq!(ptr.get(&JSON).unwrap(), &json!($json)); + assert_eq!(ptr.get(Lazy::get(&JSON).unwrap()).unwrap(), &json!($json)); })* } } From ceb390a490a131da5f45c82ba7ddecaffcff3eaf Mon Sep 17 00:00:00 2001 From: Martin Bartlett Date: Thu, 21 Dec 2023 18:10:43 +0100 Subject: [PATCH 02/11] Clippy lints - test still failing --- src/borrowed.rs | 12 ++++++------ src/owned.rs | 12 ++++++------ src/parser/mod.rs | 2 +- src/ptr.rs | 5 +---- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/borrowed.rs b/src/borrowed.rs index f106cc8..be71e94 100644 --- a/src/borrowed.rs +++ b/src/borrowed.rs @@ -8,7 +8,7 @@ impl<'value,S: AsRef, C: AsRef<[S]>> JsonPointerValueGetter(&self, val: &'json simd_json::BorrowedValue<'value>) -> Result<&'json simd_json::BorrowedValue<'value>, IndexError> { - self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| { + self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { let tok = tok.as_ref(); match *val { simd_json::BorrowedValue::Object(ref obj) => obj.get(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), @@ -24,13 +24,13 @@ impl<'value,S: AsRef, C: AsRef<[S]>> JsonPointerValueGetter Err(IndexError::NotIndexable), } - })) + }) } /// Attempts to get a mutable reference to a value from the given JSON /// value, returning an error if it can't be found. fn get_mut<'json>(&self, val: &'json mut simd_json::BorrowedValue<'value>) -> Result<&'json mut simd_json::BorrowedValue<'value>, IndexError> { - self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| { + self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { let tok = tok.as_ref(); match *val { simd_json::BorrowedValue::Object(ref mut obj) => obj.get_mut(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), @@ -46,13 +46,13 @@ impl<'value,S: AsRef, C: AsRef<[S]>> JsonPointerValueGetter Err(IndexError::NotIndexable), } - })) + }) } /// Attempts to get an owned value from the given JSON value, returning an /// error if it can't be found. fn get_owned(&self, val: simd_json::BorrowedValue<'value>) -> Result, IndexError> { - self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| { + self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { let tok = tok.as_ref(); match val { simd_json::BorrowedValue::Object(mut obj) => obj.remove(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), @@ -72,7 +72,7 @@ impl<'value,S: AsRef, C: AsRef<[S]>> JsonPointerValueGetter Err(IndexError::NotIndexable), } - })) + }) } } diff --git a/src/owned.rs b/src/owned.rs index 7eaf7e7..5ae0a84 100644 --- a/src/owned.rs +++ b/src/owned.rs @@ -8,7 +8,7 @@ impl, C: AsRef<[S]>> JsonPointerValueGetter /// Attempts to get a reference to a value from the given JSON value, /// returning an error if it can't be found. fn get<'json>(&self, val: &'json simd_json::OwnedValue) -> Result<&'json simd_json::OwnedValue, IndexError> { - self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| { + self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { let tok = tok.as_ref(); match *val { simd_json::OwnedValue::Object(ref obj) => obj.get(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), @@ -24,13 +24,13 @@ impl, C: AsRef<[S]>> JsonPointerValueGetter }, _ => Err(IndexError::NotIndexable), } - })) + }) } /// Attempts to get a mutable reference to a value from the given JSON /// value, returning an error if it can't be found. fn get_mut<'json>(&self, val: &'json mut simd_json::OwnedValue) -> Result<&'json mut simd_json::OwnedValue, IndexError> { - self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| { + self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { let tok = tok.as_ref(); match *val { simd_json::OwnedValue::Object(ref mut obj) => obj.get_mut(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), @@ -46,13 +46,13 @@ impl, C: AsRef<[S]>> JsonPointerValueGetter }, _ => Err(IndexError::NotIndexable), } - })) + }) } /// Attempts to get an owned value from the given JSON value, returning an /// error if it can't be found. fn get_owned(&self, val: simd_json::OwnedValue) -> Result { - self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| { + self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { let tok = tok.as_ref(); match val { simd_json::OwnedValue::Object(mut obj) => obj.remove(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), @@ -72,7 +72,7 @@ impl, C: AsRef<[S]>> JsonPointerValueGetter }, _ => Err(IndexError::NotIndexable), } - })) + }) } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 30cbec0..07d68fe 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -6,7 +6,7 @@ use crate::JsonPointer; /// A parser for JSON pointers. If the string starts with a `#`, it is parsed /// as a URI fragment. Otherwise, it is parsed in the string representation. pub fn parse(s: &str) -> Result>, ParseError> { - if s.chars().next() == Some('#') { + if s.starts_with('#') { let s = uri_fragment::UnescapeIter::new(s.chars().skip(1)).collect::>()?; string_repr::parse(s.chars()) } else { diff --git a/src/ptr.rs b/src/ptr.rs index d9d84a7..bd8e3d9 100644 --- a/src/ptr.rs +++ b/src/ptr.rs @@ -30,10 +30,7 @@ impl, C: AsRef<[S]>> JsonPointer { /// Representation, including the leading `#`. pub fn uri_fragment(&self) -> String { fn legal_fragment_byte(b: u8) -> bool { - match b { - 0x21 | 0x24 | 0x26..=0x3b | 0x3d | 0x3f..=0x5a | 0x5f | 0x61..=0x7a => true, - _ => false, - } + matches!(b, 0x21 | 0x24 | 0x26..=0x3b | 0x3d | 0x3f..=0x5a | 0x5f | 0x61..=0x7a) } let mut s = "#".to_string(); From 5d45ab3ff43ac18d76810d07c61a336f91346315 Mon Sep 17 00:00:00 2001 From: Martin Bartlett Date: Thu, 21 Dec 2023 18:16:21 +0100 Subject: [PATCH 03/11] Tests work --- tests/rfc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/rfc.rs b/tests/rfc.rs index 6f7dde2..fa3ac44 100644 --- a/tests/rfc.rs +++ b/tests/rfc.rs @@ -27,7 +27,7 @@ macro_rules! rfc_tests { fn rfc_tests() { $({ let ptr = $ptr.parse::>().unwrap(); - assert_eq!(ptr.get(Lazy::get(&JSON).unwrap()).unwrap(), &json!($json)); + assert_eq!(ptr.get(Lazy::force(&JSON)).unwrap(), &json!($json)); })* } } From e3a6a2927c2a46d5ae5b17d34c67469589978a0b Mon Sep 17 00:00:00 2001 From: Martin Bartlett Date: Thu, 21 Dec 2023 18:23:05 +0100 Subject: [PATCH 04/11] doc tweaks --- .travis.yml | 17 ----------------- Cargo.toml | 4 ++-- README.md | 13 ++++++++----- src/lib.rs | 2 +- 4 files changed, 11 insertions(+), 25 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8fecf25..0000000 --- a/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -language: rust -rust: - - stable - - beta - - nightly -os: - - linux - - osx -script: - - cargo build --verbose - - cargo test --verbose - - cargo run --example create_from_str_array - - cargo doc -env: - - QUICKCHECK_TESTS=10000 QUICKCHECK_MAX_TESTS=1000000 -matrix: - fast_finish: true diff --git a/Cargo.toml b/Cargo.toml index 8e768df..2db47c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,11 +2,11 @@ authors = ["Nathaniel Ringo ", "Martin Bartlett "] description = "A crate for parsing and using JSON pointers with simd_json, as specified in RFC 6901." documentation = "https://docs.rs/json-pointer-simd" -homepage = "https://github.com/remexre/json-pointer-simd" +homepage = "https://github.com/bassmanitram/json-pointer-simd" license = "MIT" name = "json-pointer-simd" readme = "README.md" -repository = "https://github.com/remexre/json-pointer-simd" +repository = "https://github.com/bassmanitram/json-pointer-simd" version = "0.1.0" edition = "2021" diff --git a/README.md b/README.md index c451c29..12e3aad 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,20 @@ # json-pointer -This crate is a straight conversion of the [json-pointer]() crate, but for use -with `simd_json` instead of `serde_json`. While simde_json and serde_json expose +## Preamble +This crate is a straight conversion of the [json-pointer](https://github.com/remexre/json-pointer) crate, but for use +with `simd_json` instead of `serde_json`. While `simd_json` and `serde_json` expose similar APIs, neither attempts to implement the traits of the other, making an across-the-board generic implementation quite difficult to achieve. So, instead, I -opted to fork the original project and adapt it to simd_json Value types. The fact -is that if you persuaded by the benefits of simd_json, you can pretty much drop it -in to standard ser/deser workloads in place of serde_json. +opted to fork the original project and adapt it to `simd_json` Value types. The fact +is that if you are persuaded by the benefits of `simd_json`, you can pretty much drop it +into standard ser/deser workloads in place of `serde_json`. You can then us this +to replace [json-pointer](https://github.com/remexre/json-pointer) for pointer access. I also made some updates to the code to use the 2021 semantics of Rust. Otherwise, all the code, examples, and tests are those of the original author. +## Read me A crate for parsing and using JSON pointers, as specified in [RFC 6901](https://tools.ietf.org/html/rfc6901). Unlike the `pointer` method built into `serde_json`, this handles both validating JSON Pointers before diff --git a/src/lib.rs b/src/lib.rs index 9e71d30..3983297 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -//! A crate for parsing and using JSON pointers with simd_json values, as specified in [RFC +//! A crate for parsing and using JSON pointers with [simd_json] values, as specified in [RFC //! 6901](https://tools.ietf.org/html/rfc6901). Unlike the `pointer` method //! built into `serde_json`, this handles both validating JSON Pointers before //! use and the URI Fragment Identifier Representation. From 80ff5c597b4a5c084e593a38cac8a5bde1b134d7 Mon Sep 17 00:00:00 2001 From: Martin Bartlett Date: Fri, 22 Dec 2023 11:42:11 +0100 Subject: [PATCH 05/11] Reinclude serde_json DUH! Once the get methods were abstracted to a trait, serde_json could easily be supported! So this commit generalizes the mods and allows them to be a PR to the original repo - although there is a lot to do before actually merging. --- Cargo.toml | 1 + README.md | 24 ++++---- examples/create_from_str_array.rs | 2 +- src/borrowed.rs | 33 +++++------ src/lib.rs | 4 +- src/owned.rs | 33 +++++------ src/value.rs | 91 +++++++++++++++++++++++++++++++ tests/rfc.rs | 2 +- 8 files changed, 144 insertions(+), 46 deletions(-) create mode 100644 src/value.rs diff --git a/Cargo.toml b/Cargo.toml index 2db47c9..f4ef292 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ version = "0.1.0" edition = "2021" [dependencies] +serde_json = "1.0" simd-json = "0.13.4" [dev-dependencies] diff --git a/README.md b/README.md index 12e3aad..35239e3 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,20 @@ # json-pointer ## Preamble -This crate is a straight conversion of the [json-pointer](https://github.com/remexre/json-pointer) crate, but for use -with `simd_json` instead of `serde_json`. While `simd_json` and `serde_json` expose -similar APIs, neither attempts to implement the traits of the other, making an -across-the-board generic implementation quite difficult to achieve. So, instead, I -opted to fork the original project and adapt it to `simd_json` Value types. The fact -is that if you are persuaded by the benefits of `simd_json`, you can pretty much drop it -into standard ser/deser workloads in place of `serde_json`. You can then us this -to replace [json-pointer](https://github.com/remexre/json-pointer) for pointer access. +This crate is a generalization of the [json-pointer](https://github.com/remexre/json-pointer) crate. -I also made some updates to the code to use the 2021 semantics of Rust. +It opens up the target of the JSON pointer to anything that can be adapted using the `JsonPointerTarget` +trait. The odd name of the crate (_.simd_) comes from the first use case and first attempt at implementation - +- using JSON Pointers with [simd-json](https://docs.rs/simd-json/latest/simd_json) Values. + +But one learns in these efforts and the back-implementation of the `JsonPointerTarget` trait to re-include +[serde_json] values became pretty obvious pretty quickly! + +HOPEfully, then, this crate is a stop-gap to getting all this merged back into `json-pointer` at some point in +the future. Before then there is a lot to do -features, tests, docs, better semantics ... + +Apart from the `JsonPointerTarget`-related refactoring, I have also made some updates to the code to use the 2021 +semantics of Rust. Otherwise, all the code, examples, and tests are those of the original author. @@ -30,9 +34,9 @@ let from_strs = JsonPointer::new([ "bar", ]); let parsed = "/foo/bar".parse::>().unwrap(); +let from_dotted_notation = JsonPointer::new("foo.bar".split('.').collect::>()); assert_eq!(from_strs.to_string(), parsed.to_string()); -} ``` ## Using a JSON Pointer diff --git a/examples/create_from_str_array.rs b/examples/create_from_str_array.rs index 69c0dc0..d371a18 100644 --- a/examples/create_from_str_array.rs +++ b/examples/create_from_str_array.rs @@ -1,6 +1,6 @@ use json_pointer_simd::JsonPointer; use simd_json::json; -use json_pointer_simd::JsonPointerValueGetter; +use json_pointer_simd::JsonPointerTarget; fn main() { let ptr = JsonPointer::new([ diff --git a/src/borrowed.rs b/src/borrowed.rs index be71e94..ee1802a 100644 --- a/src/borrowed.rs +++ b/src/borrowed.rs @@ -1,18 +1,19 @@ use std::ops::{Index, IndexMut}; -use crate::{JsonPointer, JsonPointerValueGetter, IndexError}; +use crate::{JsonPointer, JsonPointerTarget, IndexError}; +use simd_json::value::borrowed::Value; /// Implement getting for SIMD JSON Borrowed values /// -impl<'value,S: AsRef, C: AsRef<[S]>> JsonPointerValueGetter> for JsonPointer { +impl<'value,S: AsRef, C: AsRef<[S]>> JsonPointerTarget> for JsonPointer { /// Attempts to get a reference to a value from the given JSON value, /// returning an error if it can't be found. - fn get<'json>(&self, val: &'json simd_json::BorrowedValue<'value>) -> Result<&'json simd_json::BorrowedValue<'value>, IndexError> { + fn get<'json>(&self, val: &'json Value<'value>) -> Result<&'json Value<'value>, IndexError> { self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { let tok = tok.as_ref(); match *val { - simd_json::BorrowedValue::Object(ref obj) => obj.get(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), - simd_json::BorrowedValue::Array(ref arr) => { + Value::Object(ref obj) => obj.get(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), + Value::Array(ref arr) => { let idx = if tok == "-" { arr.len() } else if let Ok(idx) = tok.parse() { @@ -29,12 +30,12 @@ impl<'value,S: AsRef, C: AsRef<[S]>> JsonPointerValueGetter(&self, val: &'json mut simd_json::BorrowedValue<'value>) -> Result<&'json mut simd_json::BorrowedValue<'value>, IndexError> { + fn get_mut<'json>(&self, val: &'json mut Value<'value>) -> Result<&'json mut Value<'value>, IndexError> { self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { let tok = tok.as_ref(); match *val { - simd_json::BorrowedValue::Object(ref mut obj) => obj.get_mut(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), - simd_json::BorrowedValue::Array(ref mut arr) => { + Value::Object(ref mut obj) => obj.get_mut(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), + Value::Array(ref mut arr) => { let idx = if tok == "-" { arr.len() } else if let Ok(idx) = tok.parse() { @@ -51,12 +52,12 @@ impl<'value,S: AsRef, C: AsRef<[S]>> JsonPointerValueGetter) -> Result, IndexError> { + fn get_owned(&self, val: Value<'value>) -> Result, IndexError> { self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { let tok = tok.as_ref(); match val { - simd_json::BorrowedValue::Object(mut obj) => obj.remove(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), - simd_json::BorrowedValue::Array(mut arr) => { + Value::Object(mut obj) => obj.remove(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), + Value::Array(mut arr) => { let idx = if tok == "-" { arr.len() } else if let Ok(idx) = tok.parse() { @@ -76,15 +77,15 @@ impl<'value,S: AsRef, C: AsRef<[S]>> JsonPointerValueGetter, C: AsRef<[S]>> Index<&'a JsonPointer> for simd_json::BorrowedValue<'a> { - type Output = simd_json::BorrowedValue<'a>; - fn index(&self, ptr: &'a JsonPointer) -> &simd_json::BorrowedValue<'a> { +impl<'a, S: AsRef, C: AsRef<[S]>> Index<&'a JsonPointer> for Value<'a> { + type Output = Value<'a>; + fn index(&self, ptr: &'a JsonPointer) -> &Value<'a> { ptr.get(self).unwrap() } } -impl<'a, S: AsRef, C: AsRef<[S]>> IndexMut<&'a JsonPointer> for simd_json::BorrowedValue<'a> { - fn index_mut(&mut self, ptr: &'a JsonPointer) -> &mut simd_json::BorrowedValue<'a> { +impl<'a, S: AsRef, C: AsRef<[S]>> IndexMut<&'a JsonPointer> for Value<'a> { + fn index_mut(&mut self, ptr: &'a JsonPointer) -> &mut Value<'a> { ptr.get_mut(self).unwrap() } } diff --git a/src/lib.rs b/src/lib.rs index 3983297..fd91412 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,6 +64,7 @@ mod parser; mod owned; mod borrowed; +mod value; mod ptr; pub use parser::ParseError; @@ -74,8 +75,7 @@ pub use ptr::JsonPointer; /// The trait that provides access to the data referenced by the JsonPointer. /// This trait is implemented for both [OwnedValue] and [BorrowedValue]. /// -pub trait JsonPointerValueGetter - where V: simd_json::base::TypedValue { +pub trait JsonPointerTarget { /// Attempts to get a reference to a value from the given JSON value, /// returning an error if it can't be found. diff --git a/src/owned.rs b/src/owned.rs index 5ae0a84..a0949f4 100644 --- a/src/owned.rs +++ b/src/owned.rs @@ -1,18 +1,19 @@ use std::ops::{Index, IndexMut}; -use crate::{JsonPointer, JsonPointerValueGetter, IndexError}; +use crate::{JsonPointer, JsonPointerTarget, IndexError}; +use simd_json::value::owned::Value; /// Implement getting for SIMD JSON Owned values /// -impl, C: AsRef<[S]>> JsonPointerValueGetter for JsonPointer { +impl, C: AsRef<[S]>> JsonPointerTarget for JsonPointer { /// Attempts to get a reference to a value from the given JSON value, /// returning an error if it can't be found. - fn get<'json>(&self, val: &'json simd_json::OwnedValue) -> Result<&'json simd_json::OwnedValue, IndexError> { + fn get<'json>(&self, val: &'json Value) -> Result<&'json Value, IndexError> { self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { let tok = tok.as_ref(); match *val { - simd_json::OwnedValue::Object(ref obj) => obj.get(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), - simd_json::OwnedValue::Array(ref arr) => { + Value::Object(ref obj) => obj.get(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), + Value::Array(ref arr) => { let idx = if tok == "-" { arr.len() } else if let Ok(idx) = tok.parse() { @@ -29,12 +30,12 @@ impl, C: AsRef<[S]>> JsonPointerValueGetter /// Attempts to get a mutable reference to a value from the given JSON /// value, returning an error if it can't be found. - fn get_mut<'json>(&self, val: &'json mut simd_json::OwnedValue) -> Result<&'json mut simd_json::OwnedValue, IndexError> { + fn get_mut<'json>(&self, val: &'json mut Value) -> Result<&'json mut Value, IndexError> { self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { let tok = tok.as_ref(); match *val { - simd_json::OwnedValue::Object(ref mut obj) => obj.get_mut(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), - simd_json::OwnedValue::Array(ref mut arr) => { + Value::Object(ref mut obj) => obj.get_mut(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), + Value::Array(ref mut arr) => { let idx = if tok == "-" { arr.len() } else if let Ok(idx) = tok.parse() { @@ -51,12 +52,12 @@ impl, C: AsRef<[S]>> JsonPointerValueGetter /// Attempts to get an owned value from the given JSON value, returning an /// error if it can't be found. - fn get_owned(&self, val: simd_json::OwnedValue) -> Result { + fn get_owned(&self, val: Value) -> Result { self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { let tok = tok.as_ref(); match val { - simd_json::OwnedValue::Object(mut obj) => obj.remove(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), - simd_json::OwnedValue::Array(mut arr) => { + Value::Object(mut obj) => obj.remove(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), + Value::Array(mut arr) => { let idx = if tok == "-" { arr.len() } else if let Ok(idx) = tok.parse() { @@ -76,15 +77,15 @@ impl, C: AsRef<[S]>> JsonPointerValueGetter } } -impl<'a, S: AsRef, C: AsRef<[S]>> Index<&'a JsonPointer> for simd_json::OwnedValue { - type Output = simd_json::OwnedValue; - fn index(&self, ptr: &'a JsonPointer) -> &simd_json::OwnedValue { +impl<'a, S: AsRef, C: AsRef<[S]>> Index<&'a JsonPointer> for Value { + type Output = Value; + fn index(&self, ptr: &'a JsonPointer) -> &Value { ptr.get(self).unwrap() } } -impl<'a, S: AsRef, C: AsRef<[S]>> IndexMut<&'a JsonPointer> for simd_json::OwnedValue { - fn index_mut(&mut self, ptr: &'a JsonPointer) -> &mut simd_json::OwnedValue { +impl<'a, S: AsRef, C: AsRef<[S]>> IndexMut<&'a JsonPointer> for Value { + fn index_mut(&mut self, ptr: &'a JsonPointer) -> &mut Value { ptr.get_mut(self).unwrap() } } diff --git a/src/value.rs b/src/value.rs new file mode 100644 index 0000000..fc55106 --- /dev/null +++ b/src/value.rs @@ -0,0 +1,91 @@ +use std::ops::{Index, IndexMut}; +use crate::{JsonPointer, JsonPointerTarget, IndexError}; +use serde_json::Value; + +/// Implement getting for SIMD JSON Owned values +/// +impl, C: AsRef<[S]>> JsonPointerTarget for JsonPointer { + + /// Attempts to get a reference to a value from the given JSON value, + /// returning an error if it can't be found. + fn get<'json>(&self, val: &'json Value) -> Result<&'json Value, IndexError> { + self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { + let tok = tok.as_ref(); + match *val { + Value::Object(ref obj) => obj.get(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), + Value::Array(ref arr) => { + let idx = if tok == "-" { + arr.len() + } else if let Ok(idx) = tok.parse() { + idx + } else { + return Err(IndexError::NoSuchKey(tok.to_owned())); + }; + arr.get(idx).ok_or(IndexError::OutOfBounds(idx)) + }, + _ => Err(IndexError::NotIndexable), + } + }) + } + + /// Attempts to get a mutable reference to a value from the given JSON + /// value, returning an error if it can't be found. + fn get_mut<'json>(&self, val: &'json mut Value) -> Result<&'json mut Value, IndexError> { + self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { + let tok = tok.as_ref(); + match *val { + Value::Object(ref mut obj) => obj.get_mut(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), + Value::Array(ref mut arr) => { + let idx = if tok == "-" { + arr.len() + } else if let Ok(idx) = tok.parse() { + idx + } else { + return Err(IndexError::NoSuchKey(tok.to_owned())); + }; + arr.get_mut(idx).ok_or(IndexError::OutOfBounds(idx)) + }, + _ => Err(IndexError::NotIndexable), + } + }) + } + + /// Attempts to get an owned value from the given JSON value, returning an + /// error if it can't be found. + fn get_owned(&self, val: Value) -> Result { + self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { + let tok = tok.as_ref(); + match val { + Value::Object(mut obj) => obj.remove(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), + Value::Array(mut arr) => { + let idx = if tok == "-" { + arr.len() + } else if let Ok(idx) = tok.parse() { + idx + } else { + return Err(IndexError::NoSuchKey(tok.to_owned())); + }; + if idx >= arr.len() { + Err(IndexError::OutOfBounds(idx)) + } else { + Ok(arr.swap_remove(idx)) + } + }, + _ => Err(IndexError::NotIndexable), + } + }) + } +} + +impl<'a, S: AsRef, C: AsRef<[S]>> Index<&'a JsonPointer> for Value { + type Output = Value; + fn index(&self, ptr: &'a JsonPointer) -> &Value { + ptr.get(self).unwrap() + } +} + +impl<'a, S: AsRef, C: AsRef<[S]>> IndexMut<&'a JsonPointer> for Value { + fn index_mut(&mut self, ptr: &'a JsonPointer) -> &mut Value { + ptr.get_mut(self).unwrap() + } +} diff --git a/tests/rfc.rs b/tests/rfc.rs index fa3ac44..b1b82a4 100644 --- a/tests/rfc.rs +++ b/tests/rfc.rs @@ -1,5 +1,5 @@ use json_pointer_simd::JsonPointer; -use json_pointer_simd::JsonPointerValueGetter; +use json_pointer_simd::JsonPointerTarget; use once_cell::sync::Lazy; use simd_json::OwnedValue; use simd_json::json; From e0aaef6f153df9ef16393a0206b23479faaa1ff4 Mon Sep 17 00:00:00 2001 From: Martin Bartlett Date: Fri, 22 Dec 2023 11:52:12 +0100 Subject: [PATCH 06/11] Update version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f4ef292..8b4d855 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT" name = "json-pointer-simd" readme = "README.md" repository = "https://github.com/bassmanitram/json-pointer-simd" -version = "0.1.0" +version = "0.2.0" edition = "2021" [dependencies] From 1ff94dd77cc53c55cd3c6d356a9a66eb9fb4af3a Mon Sep 17 00:00:00 2001 From: Martin Bartlett Date: Fri, 22 Dec 2023 15:17:01 +0100 Subject: [PATCH 07/11] Big cleanup * Reverse the Trait - it gets implemented on the target now, not on the pointer. * Update the doc * Update the tests to include simd * Lift to version 0.3.0 (breaks 0.2.0) --- Cargo.toml | 2 +- README.md | 2 +- examples/create_from_str_array.rs | 7 ++- src/borrowed.rs | 27 ++++------ src/lib.rs | 74 +++++++++++++++++++-------- src/owned.rs | 19 +++---- src/value.rs | 18 +++---- tests/rfc.rs | 11 ++-- tests/rfc_simd.rs | 85 +++++++++++++++++++++++++++++++ 9 files changed, 178 insertions(+), 67 deletions(-) create mode 100644 tests/rfc_simd.rs diff --git a/Cargo.toml b/Cargo.toml index 8b4d855..2eab935 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT" name = "json-pointer-simd" readme = "README.md" repository = "https://github.com/bassmanitram/json-pointer-simd" -version = "0.2.0" +version = "0.3.0" edition = "2021" [dependencies] diff --git a/README.md b/README.md index 35239e3..e6fd5e6 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ let document = json!({ "quux": "xyzzy" }); -let indexed = ptr.get(&document).unwrap(); +let indexed = document.get(&ptr).unwrap(); assert_eq!(indexed, &json!(0)); ``` diff --git a/examples/create_from_str_array.rs b/examples/create_from_str_array.rs index d371a18..dd09c7f 100644 --- a/examples/create_from_str_array.rs +++ b/examples/create_from_str_array.rs @@ -1,6 +1,5 @@ -use json_pointer_simd::JsonPointer; -use simd_json::json; -use json_pointer_simd::JsonPointerTarget; +use json_pointer_simd::{JsonPointer,JsonPointerTarget}; +use simd_json::json; // or serde_json::json fn main() { let ptr = JsonPointer::new([ @@ -18,7 +17,7 @@ fn main() { "quux": "xyzzy" }); - let indexed = ptr.get(&document).unwrap(); + let indexed = document.get(&ptr).unwrap(); assert_eq!(indexed, &json!(0)); } diff --git a/src/borrowed.rs b/src/borrowed.rs index ee1802a..f38da97 100644 --- a/src/borrowed.rs +++ b/src/borrowed.rs @@ -4,12 +4,10 @@ use simd_json::value::borrowed::Value; /// Implement getting for SIMD JSON Borrowed values /// -impl<'value,S: AsRef, C: AsRef<[S]>> JsonPointerTarget> for JsonPointer { - - /// Attempts to get a reference to a value from the given JSON value, - /// returning an error if it can't be found. - fn get<'json>(&self, val: &'json Value<'value>) -> Result<&'json Value<'value>, IndexError> { - self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { +impl<'a> JsonPointerTarget for Value<'a> + where Self: Sized { + fn get<'json, S: AsRef, C: AsRef<[S]>>(&'json self, ptr: &JsonPointer) -> Result<&'json Self, IndexError> { + ptr.ref_toks.as_ref().iter().try_fold(self, |val, tok| { let tok = tok.as_ref(); match *val { Value::Object(ref obj) => obj.get(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), @@ -28,10 +26,8 @@ impl<'value,S: AsRef, C: AsRef<[S]>> JsonPointerTarget> for J }) } - /// Attempts to get a mutable reference to a value from the given JSON - /// value, returning an error if it can't be found. - fn get_mut<'json>(&self, val: &'json mut Value<'value>) -> Result<&'json mut Value<'value>, IndexError> { - self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { + fn get_mut<'json, S: AsRef, C: AsRef<[S]>>(&'json mut self, ptr: &JsonPointer) -> Result<&'json mut Self, IndexError> { + ptr.ref_toks.as_ref().iter().try_fold(self, |val, tok| { let tok = tok.as_ref(); match *val { Value::Object(ref mut obj) => obj.get_mut(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), @@ -50,10 +46,8 @@ impl<'value,S: AsRef, C: AsRef<[S]>> JsonPointerTarget> for J }) } - /// Attempts to get an owned value from the given JSON value, returning an - /// error if it can't be found. - fn get_owned(&self, val: Value<'value>) -> Result, IndexError> { - self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { + fn get_owned<'json, S: AsRef, C: AsRef<[S]>>(self, ptr: &JsonPointer) -> Result { + ptr.ref_toks.as_ref().iter().try_fold(self, |val, tok| { let tok = tok.as_ref(); match val { Value::Object(mut obj) => obj.remove(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), @@ -76,16 +70,15 @@ impl<'value,S: AsRef, C: AsRef<[S]>> JsonPointerTarget> for J }) } } - impl<'a, S: AsRef, C: AsRef<[S]>> Index<&'a JsonPointer> for Value<'a> { type Output = Value<'a>; fn index(&self, ptr: &'a JsonPointer) -> &Value<'a> { - ptr.get(self).unwrap() + self.get(ptr).unwrap() } } impl<'a, S: AsRef, C: AsRef<[S]>> IndexMut<&'a JsonPointer> for Value<'a> { fn index_mut(&mut self, ptr: &'a JsonPointer) -> &mut Value<'a> { - ptr.get_mut(self).unwrap() + self.get_mut(ptr).unwrap() } } diff --git a/src/lib.rs b/src/lib.rs index fd91412..eed939e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,32 +1,46 @@ -//! A crate for parsing and using JSON pointers with [simd_json] values, as specified in [RFC -//! 6901](https://tools.ietf.org/html/rfc6901). Unlike the `pointer` method -//! built into `serde_json`, this handles both validating JSON Pointers before -//! use and the URI Fragment Identifier Representation. +//! A crate for parsing and using JSON pointers with [simd_json] and [serde_json] values. +//! +//! The functionality is specified in [RFC 6901](https://tools.ietf.org/html/rfc6901). +//! +//! In the case of [serde_json], unlike nlike the `pointer` method, this handles both +//! validating JSON Pointers before use and the URI Fragment Identifier Representation. +//! +//! In the case of [simd_json], this crate provides that missing functionality. //! //! ## Creating a JSON Pointer //! -//! JSON pointers can be created with a literal `[&str]`, or parsed from a `String`. +//! JSON pointers can be parsed from any thing that can interpreted a s string slice +//! expressed in standard JSON Pointer syntax, or created from anything that can be +//! loosely represented as a vector or array of `&str`. //! //! ```rust -//! use json_pointer_simd::{JsonPointer,JsonPointerValueGetter}; +//! use json_pointer_simd::{JsonPointer,JsonPointerTarget}; //! //! let from_strs = JsonPointer::new([ //! "foo", //! "bar", //! ]); //! let parsed = "/foo/bar".parse::>().unwrap(); +//! let from_dotted_notation = JsonPointer::new("foo.bar".split('.').collect::>()); //! //! assert_eq!(from_strs.to_string(), parsed.to_string()); +//! assert_eq!(from_strs.to_string(), from_dotted_notation.to_string()); //! ``` //! //! ## Using a JSON Pointer //! -//! The `JsonPointer` type provides `.get()` and `.get_mut()`, to get references +//! The `JsonPointerTarget` trait provides `.get()` and `.get_mut()`, to get references //! and mutable references to the appropriate value, respectively. //! +//! As delivered, this is implemented on [serde_json] values and [simd_json] values, though +//! the former is a little more verbose to use than the latter due to the pre-existence of +//! these methods on [serde_json] values +//! +//! For [simd_json]: +//! //! ```rust //! use simd_json::json; -//! use json_pointer_simd::{JsonPointer,JsonPointerValueGetter}; +//! use json_pointer_simd::{JsonPointer,JsonPointerTarget}; //! //! let ptr = "/foo/bar".parse::>().unwrap(); //! @@ -37,7 +51,27 @@ //! }, //! "quux": "xyzzy" //! }); -//! let indexed = ptr.get(&document).unwrap(); +//! let indexed = document.get(&ptr).unwrap(); +//! +//! assert_eq!(indexed, &json!(0)); +//! ``` +//! +//! For [serde_json]: +//! +//! ```rust +//! use serde_json::{json, Value}; +//! use json_pointer_simd::{JsonPointer,JsonPointerTarget}; +//! +//! let ptr = "/foo/bar".parse::>().unwrap(); +//! +//! let document = json!({ +//! "foo": { +//! "bar": 0, +//! "baz": 1, +//! }, +//! "quux": "xyzzy" +//! }); +//! let indexed = ::get(&document,&ptr).unwrap(); //! //! assert_eq!(indexed, &json!(0)); //! ``` @@ -51,7 +85,7 @@ //! crate does not support parsing full URIs. //! //! ```rust -//! use json_pointer_simd::{JsonPointer,JsonPointerValueGetter}; +//! use json_pointer_simd::{JsonPointer,JsonPointerTarget}; //! //! let str_ptr = "/f%o".parse::>().unwrap(); //! let uri_ptr = "#/f%25o".parse::>().unwrap(); @@ -73,17 +107,17 @@ pub use ptr::JsonPointer; /// /// The trait that provides access to the data referenced by the JsonPointer. -/// This trait is implemented for both [OwnedValue] and [BorrowedValue]. -/// -pub trait JsonPointerTarget { +/// +pub trait JsonPointerTarget + where Self: Sized{ - /// Attempts to get a reference to a value from the given JSON value, + /// Attempts to get a reference to a value from self, + /// returning an error if it can't be found. + fn get<'json,S: AsRef, C: AsRef<[S]>>(&'json self, ptr: &JsonPointer) -> Result<&'json Self, IndexError>; + /// Attempts to get a mutable reference to a value from self /// returning an error if it can't be found. - fn get<'json>(&self, val: &'json V) -> Result<&'json V, IndexError>; - /// Attempts to get a mutable reference to a value from the given JSON - /// value, returning an error if it can't be found. - fn get_mut<'json>(&self, val: &'json mut V) -> Result<&'json mut V, IndexError>; - /// Attempts to get an owned value from the given JSON value, returning an + fn get_mut<'json,S: AsRef, C: AsRef<[S]>>(&'json mut self, ptr: &JsonPointer) -> Result<&'json mut Self, IndexError>; + /// Attempts to get an owned value from self, returning an /// error if it can't be found. - fn get_owned(&self, val: V) -> Result; + fn get_owned, C: AsRef<[S]>>(self, ptr: &JsonPointer) -> Result; } diff --git a/src/owned.rs b/src/owned.rs index a0949f4..d85b789 100644 --- a/src/owned.rs +++ b/src/owned.rs @@ -2,14 +2,15 @@ use std::ops::{Index, IndexMut}; use crate::{JsonPointer, JsonPointerTarget, IndexError}; use simd_json::value::owned::Value; +/// /// Implement getting for SIMD JSON Owned values /// -impl, C: AsRef<[S]>> JsonPointerTarget for JsonPointer { +impl JsonPointerTarget for Value { /// Attempts to get a reference to a value from the given JSON value, /// returning an error if it can't be found. - fn get<'json>(&self, val: &'json Value) -> Result<&'json Value, IndexError> { - self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { + fn get<'value, S: AsRef, C: AsRef<[S]>>(&'value self, ptr: &JsonPointer) -> Result<&'value Self, IndexError> { + ptr.ref_toks.as_ref().iter().try_fold(self, |val, tok| { let tok = tok.as_ref(); match *val { Value::Object(ref obj) => obj.get(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), @@ -30,8 +31,8 @@ impl, C: AsRef<[S]>> JsonPointerTarget for JsonPointer(&self, val: &'json mut Value) -> Result<&'json mut Value, IndexError> { - self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { + fn get_mut<'value, S: AsRef, C: AsRef<[S]>>(&'value mut self, ptr: &JsonPointer) -> Result<&'value mut Self, IndexError> { + ptr.ref_toks.as_ref().iter().try_fold(self, |val, tok| { let tok = tok.as_ref(); match *val { Value::Object(ref mut obj) => obj.get_mut(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), @@ -52,8 +53,8 @@ impl, C: AsRef<[S]>> JsonPointerTarget for JsonPointer Result { - self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { + fn get_owned<'value, S: AsRef, C: AsRef<[S]>>(self, ptr: &JsonPointer) -> Result { + ptr.ref_toks.as_ref().iter().try_fold(self, |val, tok| { let tok = tok.as_ref(); match val { Value::Object(mut obj) => obj.remove(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), @@ -80,12 +81,12 @@ impl, C: AsRef<[S]>> JsonPointerTarget for JsonPointer, C: AsRef<[S]>> Index<&'a JsonPointer> for Value { type Output = Value; fn index(&self, ptr: &'a JsonPointer) -> &Value { - ptr.get(self).unwrap() + self.get(ptr).unwrap() } } impl<'a, S: AsRef, C: AsRef<[S]>> IndexMut<&'a JsonPointer> for Value { fn index_mut(&mut self, ptr: &'a JsonPointer) -> &mut Value { - ptr.get_mut(self).unwrap() + self.get_mut(ptr).unwrap() } } diff --git a/src/value.rs b/src/value.rs index fc55106..06726dd 100644 --- a/src/value.rs +++ b/src/value.rs @@ -4,12 +4,12 @@ use serde_json::Value; /// Implement getting for SIMD JSON Owned values /// -impl, C: AsRef<[S]>> JsonPointerTarget for JsonPointer { +impl JsonPointerTarget for Value { /// Attempts to get a reference to a value from the given JSON value, /// returning an error if it can't be found. - fn get<'json>(&self, val: &'json Value) -> Result<&'json Value, IndexError> { - self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { + fn get<'value, S: AsRef, C: AsRef<[S]>>(&'value self, ptr: &JsonPointer) -> Result<&'value Self, IndexError> { + ptr.ref_toks.as_ref().iter().try_fold(self, |val, tok| { let tok = tok.as_ref(); match *val { Value::Object(ref obj) => obj.get(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), @@ -30,8 +30,8 @@ impl, C: AsRef<[S]>> JsonPointerTarget for JsonPointer(&self, val: &'json mut Value) -> Result<&'json mut Value, IndexError> { - self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { + fn get_mut<'value, S: AsRef, C: AsRef<[S]>>(&'value mut self, ptr: &JsonPointer) -> Result<&'value mut Self, IndexError> { + ptr.ref_toks.as_ref().iter().try_fold(self, |val, tok| { let tok = tok.as_ref(); match *val { Value::Object(ref mut obj) => obj.get_mut(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), @@ -52,8 +52,8 @@ impl, C: AsRef<[S]>> JsonPointerTarget for JsonPointer Result { - self.ref_toks.as_ref().iter().try_fold(val, |val, tok| { + fn get_owned, C: AsRef<[S]>>(self, ptr: &JsonPointer) -> Result { + ptr.ref_toks.as_ref().iter().try_fold(self, |val, tok| { let tok = tok.as_ref(); match val { Value::Object(mut obj) => obj.remove(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())), @@ -80,12 +80,12 @@ impl, C: AsRef<[S]>> JsonPointerTarget for JsonPointer, C: AsRef<[S]>> Index<&'a JsonPointer> for Value { type Output = Value; fn index(&self, ptr: &'a JsonPointer) -> &Value { - ptr.get(self).unwrap() + ::get(self,ptr).unwrap() } } impl<'a, S: AsRef, C: AsRef<[S]>> IndexMut<&'a JsonPointer> for Value { fn index_mut(&mut self, ptr: &'a JsonPointer) -> &mut Value { - ptr.get_mut(self).unwrap() + ::get_mut(self, ptr).unwrap() } } diff --git a/tests/rfc.rs b/tests/rfc.rs index b1b82a4..25540be 100644 --- a/tests/rfc.rs +++ b/tests/rfc.rs @@ -1,10 +1,8 @@ -use json_pointer_simd::JsonPointer; -use json_pointer_simd::JsonPointerTarget; +use json_pointer_simd::{JsonPointer,JsonPointerTarget}; use once_cell::sync::Lazy; -use simd_json::OwnedValue; -use simd_json::json; +use serde_json::{Value,json}; -static JSON: Lazy = Lazy::new(|| +static JSON: Lazy = Lazy::new(|| json!({ "foo": ["bar", "baz"], "": 0, @@ -27,7 +25,8 @@ macro_rules! rfc_tests { fn rfc_tests() { $({ let ptr = $ptr.parse::>().unwrap(); - assert_eq!(ptr.get(Lazy::force(&JSON)).unwrap(), &json!($json)); + let value = ::get(&JSON,&ptr); + assert_eq!(value.unwrap(), &json!($json)); })* } } diff --git a/tests/rfc_simd.rs b/tests/rfc_simd.rs new file mode 100644 index 0000000..562620c --- /dev/null +++ b/tests/rfc_simd.rs @@ -0,0 +1,85 @@ +use json_pointer_simd::{JsonPointer,JsonPointerTarget}; +use once_cell::sync::Lazy; +use simd_json::{OwnedValue,json}; + +static JSON: Lazy = Lazy::new(|| + json!({ + "foo": ["bar", "baz"], + "": 0, + "a/b": 1, + "c%d": 2, + "e^f": 3, + "g|h": 4, + "i\\j": 5, + "k\"l": 6, + " ": 7, + "m~n": 8, + }) +); + +macro_rules! rfc_tests { + ($($ptr:expr => $json:tt;)*) => { + /// The tests in Sections [5](https://tools.ietf.org/html/rfc6901#section-5) + /// and [6](https://tools.ietf.org/html/rfc6901#section-6) of RFC 6901. + #[test] + fn rfc_tests() { + $({ + let ptr = $ptr.parse::>().unwrap(); + let value = JSON.get(&ptr); + assert_eq!(value.unwrap(), &json!($json)); + })* + } + } +} + +rfc_tests! { + // Section 5 + "" => { + "foo": ["bar", "baz"], + "": 0, + "a/b": 1, + "c%d": 2, + "e^f": 3, + "g|h": 4, + "i\\j": 5, + "k\"l": 6, + " ": 7, + "m~n": 8, + }; + "/foo" => ["bar", "baz"]; + "/foo/0" => "bar"; + "/" => 0; + "/a~1b" => 1; + "/c%d" => 2; + "/e^f" => 3; + "/g|h" => 4; + "/i\\j" => 5; + "/k\"l" => 6; + "/ " => 7; + "/m~0n" => 8; + + // Section 6 + "#" => { + "foo": ["bar", "baz"], + "": 0, + "a/b": 1, + "c%d": 2, + "e^f": 3, + "g|h": 4, + "i\\j": 5, + "k\"l": 6, + " ": 7, + "m~n": 8, + }; + "#/foo" => ["bar", "baz"]; + "#/foo/0" => "bar"; + "#/" => 0; + "#/a~1b" => 1; + "#/c%25d" => 2; + "#/e%5Ef" => 3; + "#/g%7Ch" => 4; + "#/i%5Cj" => 5; + "#/k%22l" => 6; + "#/%20" => 7; + "#/m~0n" => 8; +} From 2eda3a27b46ab36e6a1d3813e8d9e061065e8c68 Mon Sep 17 00:00:00 2001 From: Martin Bartlett Date: Fri, 22 Dec 2023 15:42:19 +0100 Subject: [PATCH 08/11] Version upgrades after cargo audit findings --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2eab935..47f100f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,6 @@ simd-json = "0.13.4" [dev-dependencies] lazy_static = "^0.2.8" -quickcheck = "^0.4.1" -regex = "^0.2.2" +regex = "1.10.2" +quickcheck = "1.0.3" once_cell = "1.19.0" From 52b9e40a55cf99c6eb3102ea0e8557ed35b2cc53 Mon Sep 17 00:00:00 2001 From: Martin Bartlett Date: Fri, 22 Dec 2023 15:43:23 +0100 Subject: [PATCH 09/11] Version upgrades after cargo audit findings --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 47f100f..1639c37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT" name = "json-pointer-simd" readme = "README.md" repository = "https://github.com/bassmanitram/json-pointer-simd" -version = "0.3.0" +version = "0.3.1" edition = "2021" [dependencies] From 6f8d0d7a2a283c8551a7b75af6337340a796c46f Mon Sep 17 00:00:00 2001 From: Martin Bartlett Date: Mon, 23 Sep 2024 11:31:06 +0200 Subject: [PATCH 10/11] Update version --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1639c37..f8f620b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,12 +7,12 @@ license = "MIT" name = "json-pointer-simd" readme = "README.md" repository = "https://github.com/bassmanitram/json-pointer-simd" -version = "0.3.1" +version = "0.3.2" edition = "2021" [dependencies] serde_json = "1.0" -simd-json = "0.13.4" +simd-json = "0.14" [dev-dependencies] lazy_static = "^0.2.8" From 42b1f8238e2642dc994788a2ec113c7d5be0b396 Mon Sep 17 00:00:00 2001 From: Martin Bartlett Date: Fri, 25 Oct 2024 14:41:05 +0200 Subject: [PATCH 11/11] Update dependencies --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f8f620b..620e4ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,12 +7,12 @@ license = "MIT" name = "json-pointer-simd" readme = "README.md" repository = "https://github.com/bassmanitram/json-pointer-simd" -version = "0.3.2" +version = "0.3.3" edition = "2021" [dependencies] serde_json = "1.0" -simd-json = "0.14" +simd-json = "0" [dev-dependencies] lazy_static = "^0.2.8"