Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions .travis.yml

This file was deleted.

29 changes: 13 additions & 16 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
[package]
authors = ["Nathaniel Ringo <remexre@gmail.com>"]
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 <remexre@gmail.com>", "Martin Bartlett <martin.j.bartlett@gmail.com>"]
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/bassmanitram/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/bassmanitram/json-pointer-simd"
version = "0.3.3"
edition = "2021"

[dependencies]
serde_json = "^1.0.2"
serde_json = "1.0"
simd-json = "0"

[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"
27 changes: 21 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
# json-pointer

## Preamble
This crate is a generalization of the [json-pointer](https://github.com/remexre/json-pointer) crate.

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.

## 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
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`.
Expand All @@ -19,9 +34,9 @@ let from_strs = JsonPointer::new([
"bar",
]);
let parsed = "/foo/bar".parse::<JsonPointer<_, _>>().unwrap();
let from_dotted_notation = JsonPointer::new("foo.bar".split('.').collect::<Vec<&str>>());

assert_eq!(from_strs.to_string(), parsed.to_string());
}
```

## Using a JSON Pointer
Expand All @@ -40,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));
```
Expand Down
9 changes: 3 additions & 6 deletions examples/create_from_str_array.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
extern crate json_pointer;
#[macro_use]
extern crate serde_json;

use json_pointer::JsonPointer;
use json_pointer_simd::{JsonPointer,JsonPointerTarget};
use simd_json::json; // or serde_json::json

fn main() {
let ptr = JsonPointer::new([
Expand All @@ -20,7 +17,7 @@ fn main() {
"quux": "xyzzy"
});

let indexed = ptr.get(&document).unwrap();
let indexed = document.get(&ptr).unwrap();

assert_eq!(indexed, &json!(0));
}
84 changes: 84 additions & 0 deletions src/borrowed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use std::ops::{Index, IndexMut};
use crate::{JsonPointer, JsonPointerTarget, IndexError};
use simd_json::value::borrowed::Value;

/// Implement getting for SIMD JSON Borrowed values
///
impl<'a> JsonPointerTarget for Value<'a>
where Self: Sized {
fn get<'json, S: AsRef<str>, C: AsRef<[S]>>(&'json self, ptr: &JsonPointer<S,C>) -> 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())),
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),
}
})
}

fn get_mut<'json, S: AsRef<str>, C: AsRef<[S]>>(&'json mut self, ptr: &JsonPointer<S,C>) -> 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())),
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),
}
})
}

fn get_owned<'json, S: AsRef<str>, C: AsRef<[S]>>(self, ptr: &JsonPointer<S,C>) -> Result<Self, IndexError> {
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())),
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<str>, C: AsRef<[S]>> Index<&'a JsonPointer<S, C>> for Value<'a> {
type Output = Value<'a>;
fn index(&self, ptr: &'a JsonPointer<S, C>) -> &Value<'a> {
self.get(ptr).unwrap()
}
}

impl<'a, S: AsRef<str>, C: AsRef<[S]>> IndexMut<&'a JsonPointer<S, C>> for Value<'a> {
fn index_mut(&mut self, ptr: &'a JsonPointer<S, C>) -> &mut Value<'a> {
self.get_mut(ptr).unwrap()
}
}
132 changes: 83 additions & 49 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,59 +1,79 @@
//! 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)
//! 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
//! extern crate json_pointer;
//!
//! use json_pointer::JsonPointer;
//! use json_pointer_simd::{JsonPointer,JsonPointerTarget};
//!
//! fn main() {
//! let from_strs = JsonPointer::new([
//! "foo",
//! "bar",
//! ]);
//! let parsed = "/foo/bar".parse::<JsonPointer<_, _>>().unwrap();
//!
//! assert_eq!(from_strs.to_string(), parsed.to_string());
//! }
//! let from_strs = JsonPointer::new([
//! "foo",
//! "bar",
//! ]);
//! let parsed = "/foo/bar".parse::<JsonPointer<_, _>>().unwrap();
//! let from_dotted_notation = JsonPointer::new("foo.bar".split('.').collect::<Vec<&str>>());
//!
//! 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
//! extern crate json_pointer;
//! #[macro_use]
//! extern crate serde_json;
//! use simd_json::json;
//! use json_pointer_simd::{JsonPointer,JsonPointerTarget};
//!
//! use json_pointer::JsonPointer;
//!
//! fn main() {
//! let ptr = "/foo/bar".parse::<JsonPointer<_, _>>().unwrap();
//! let ptr = "/foo/bar".parse::<JsonPointer<_, _>>().unwrap();
//!
//! let document = json!({
//! "foo": {
//! "bar": 0,
//! "baz": 1,
//! },
//! "quux": "xyzzy"
//! });
//! let document = json!({
//! "foo": {
//! "bar": 0,
//! "baz": 1,
//! },
//! "quux": "xyzzy"
//! });
//! let indexed = document.get(&ptr).unwrap();
//!
//! let indexed = ptr.get(&document).unwrap();
//! assert_eq!(indexed, &json!(0));
//! ```
//!
//! 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::<JsonPointer<_, _>>().unwrap();
//!
//! let document = json!({
//! "foo": {
//! "bar": 0,
//! "baz": 1,
//! },
//! "quux": "xyzzy"
//! });
//! let indexed = <Value as JsonPointerTarget>::get(&document,&ptr).unwrap();
//!
//! assert_eq!(indexed, &json!(0));
//! ```
//!
//! ## URI Fragment Identifier Representation
Expand All @@ -65,25 +85,39 @@
//! crate does not support parsing full URIs.
//!
//! ```rust
//! extern crate json_pointer;
//! use json_pointer_simd::{JsonPointer,JsonPointerTarget};
//!
//! use json_pointer::JsonPointer;
//!
//! fn main() {
//! let str_ptr = "/f%o".parse::<JsonPointer<_, _>>().unwrap();
//! let uri_ptr = "#/f%25o".parse::<JsonPointer<_, _>>().unwrap();
//! let str_ptr = "/f%o".parse::<JsonPointer<_, _>>().unwrap();
//! let uri_ptr = "#/f%25o".parse::<JsonPointer<_, _>>().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 value;
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.
///
pub trait JsonPointerTarget
where Self: Sized{

/// Attempts to get a reference to a value from self,
/// returning an error if it can't be found.
fn get<'json,S: AsRef<str>, C: AsRef<[S]>>(&'json self, ptr: &JsonPointer<S,C>) -> 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_mut<'json,S: AsRef<str>, C: AsRef<[S]>>(&'json mut self, ptr: &JsonPointer<S,C>) -> 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<S: AsRef<str>, C: AsRef<[S]>>(self, ptr: &JsonPointer<S,C>) -> Result<Self, IndexError>;
}
Loading