Skip to content

Commit

Permalink
make json_path_instance work without PathInstance, which is a Box<d…
Browse files Browse the repository at this point in the history
…yn> type and thus needs an additinal vtable for each search
  • Loading branch information
xMAC94x committed Jul 1, 2024
1 parent 8e7511f commit 7ff57ae
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 37 deletions.
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ impl FromStr for JsonPathInst {

impl JsonPathInst {
pub fn find_slice<'a>(&'a self, value: &'a Value) -> Vec<JsonPtr<'a, Value>> {
use crate::path::Path;
json_path_instance(&self.inner, value)
.find(JsonPathValue::from_root(value))
.into_iter()
Expand Down Expand Up @@ -420,6 +421,7 @@ impl<'a, Data> JsonPathValue<'a, Data> {
/// );
/// ```
pub fn find_slice<'a>(path: &'a JsonPathInst, json: &'a Value) -> Vec<JsonPathValue<'a, Value>> {
use crate::path::Path;
let instance = json_path_instance(&path.inner, json);
let res = instance.find(JsonPathValue::from_root(json));
let has_v: Vec<JsonPathValue<'_, Value>> = res.into_iter().filter(|v| v.has_value()).collect();
Expand Down
22 changes: 13 additions & 9 deletions src/path/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use crate::JsonPathValue::{NoValue, Slice};
use serde_json::value::Value::Array;
use serde_json::Value;

use super::TopPaths;

/// process the slice like [start:end:step]
#[derive(Debug)]
pub(crate) struct ArraySlice {
Expand Down Expand Up @@ -127,7 +129,7 @@ impl<'a> Current<'a> {
pub(crate) fn from(jp: &'a JsonPath, root: &'a Value) -> Self {
match jp {
JsonPath::Empty => Current::none(),
tail => Current::new(json_path_instance(tail, root)),
tail => Current::new(Box::new(json_path_instance(tail, root))),
}
}
pub(crate) fn new(tail: PathInstance<'a>) -> Self {
Expand All @@ -151,30 +153,32 @@ impl<'a> Path<'a> for Current<'a> {

/// the list of indexes like [1,2,3]
pub(crate) struct UnionIndex<'a> {
indexes: Vec<PathInstance<'a>>,
indexes: Vec<TopPaths<'a>>,
}

impl<'a> UnionIndex<'a> {
pub fn from_indexes(elems: &'a [Value]) -> Self {
let mut indexes: Vec<PathInstance<'a>> = vec![];
let mut indexes: Vec<TopPaths<'a>> = vec![];

for idx in elems.iter() {
indexes.push(Box::new(ArrayIndex::new(idx.as_u64().unwrap() as usize)))
indexes.push(TopPaths::ArrayIndex(ArrayIndex::new(
idx.as_u64().unwrap() as usize
)))
}

UnionIndex::new(indexes)
}
pub fn from_keys(elems: &'a [String]) -> Self {
let mut indexes: Vec<PathInstance<'a>> = vec![];
let mut indexes: Vec<TopPaths<'a>> = vec![];

for key in elems.iter() {
indexes.push(Box::new(ObjectField::new(key)))
indexes.push(TopPaths::ObjectField(ObjectField::new(key)))
}

UnionIndex::new(indexes)
}

pub fn new(indexes: Vec<PathInstance<'a>>) -> Self {
pub fn new(indexes: Vec<TopPaths<'a>>) -> Self {
UnionIndex { indexes }
}
}
Expand Down Expand Up @@ -582,8 +586,8 @@ mod tests {
let chain = chain!(path!($), path!("key"), index);
let path_inst = json_path_instance(&chain, &json);
let expected_res = jp_v![
&exp4;"$.['key'][0]",
&exp3;"$.['key'][2]",
&exp4;"$.['key'][0]",
&exp3;"$.['key'][2]",
&exp4;"$.['key'][4]"];
assert_eq!(
path_inst.find(JsonPathValue::from_root(&json)),
Expand Down
132 changes: 107 additions & 25 deletions src/path/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,40 +36,122 @@ pub trait Path<'a> {
}
}

/// The basic type for instances.
pub type PathInstance<'a> = Box<dyn Path<'a, Data = Value> + 'a>;
/// all known Paths, mostly to avoid a dynamic Box and vtable for internal function
pub(crate) enum TopPaths<'a> {
RootPointer(RootPointer<'a, Value>),
ObjectField(ObjectField<'a>),
Chain(Chain<'a>),
Wildcard(Wildcard),
DescentObject(DescentObject<'a>),
DescentWildcard(DescentWildcard),
Current(Current<'a>),
ArrayIndex(ArrayIndex),
ArraySlice(ArraySlice),
UnionIndex(UnionIndex<'a>),
FilterPath(FilterPath<'a>),
IdentityPath(IdentityPath),
FnPath(FnPath),
}

/// The major method to process the top part of json part
pub fn json_path_instance<'a>(json_path: &'a JsonPath, root: &'a Value) -> PathInstance<'a> {
match json_path {
JsonPath::Root => Box::new(RootPointer::new(root)),
JsonPath::Field(key) => Box::new(ObjectField::new(key)),
JsonPath::Chain(chain) => Box::new(Chain::from(chain, root)),
JsonPath::Wildcard => Box::new(Wildcard {}),
JsonPath::Descent(key) => Box::new(DescentObject::new(key)),
JsonPath::DescentW => Box::new(DescentWildcard),
JsonPath::Current(value) => Box::new(Current::from(value, root)),
JsonPath::Index(index) => process_index(index, root),
JsonPath::Empty => Box::new(IdentityPath {}),
JsonPath::Fn(Function::Length) => Box::new(FnPath::Size),
impl<'a> Path<'a> for TopPaths<'a> {
type Data = Value;

fn find(&self, input: JsonPathValue<'a, Self::Data>) -> Vec<JsonPathValue<'a, Self::Data>> {
match self {
TopPaths::RootPointer(inner) => inner.find(input),
TopPaths::ObjectField(inner) => inner.find(input),
TopPaths::Chain(inner) => inner.find(input),
TopPaths::Wildcard(inner) => inner.find(input),
TopPaths::DescentObject(inner) => inner.find(input),
TopPaths::DescentWildcard(inner) => inner.find(input),
TopPaths::Current(inner) => inner.find(input),
TopPaths::ArrayIndex(inner) => inner.find(input),
TopPaths::ArraySlice(inner) => inner.find(input),
TopPaths::UnionIndex(inner) => inner.find(input),
TopPaths::FilterPath(inner) => inner.find(input),
TopPaths::IdentityPath(inner) => inner.find(input),
TopPaths::FnPath(inner) => inner.find(input),
}
}

fn flat_find(
&self,
input: Vec<JsonPathValue<'a, Self::Data>>,
_is_search_length: bool,
) -> Vec<JsonPathValue<'a, Self::Data>> {
match self {
TopPaths::RootPointer(inner) => inner.flat_find(input, _is_search_length),
TopPaths::ObjectField(inner) => inner.flat_find(input, _is_search_length),
TopPaths::Chain(inner) => inner.flat_find(input, _is_search_length),
TopPaths::Wildcard(inner) => inner.flat_find(input, _is_search_length),
TopPaths::DescentObject(inner) => inner.flat_find(input, _is_search_length),
TopPaths::DescentWildcard(inner) => inner.flat_find(input, _is_search_length),
TopPaths::Current(inner) => inner.flat_find(input, _is_search_length),
TopPaths::ArrayIndex(inner) => inner.flat_find(input, _is_search_length),
TopPaths::ArraySlice(inner) => inner.flat_find(input, _is_search_length),
TopPaths::UnionIndex(inner) => inner.flat_find(input, _is_search_length),
TopPaths::FilterPath(inner) => inner.flat_find(input, _is_search_length),
TopPaths::IdentityPath(inner) => inner.flat_find(input, _is_search_length),
TopPaths::FnPath(inner) => inner.flat_find(input, _is_search_length),
}
}

fn needs_all(&self) -> bool {
match self {
TopPaths::RootPointer(inner) => inner.needs_all(),
TopPaths::ObjectField(inner) => inner.needs_all(),
TopPaths::Chain(inner) => inner.needs_all(),
TopPaths::Wildcard(inner) => inner.needs_all(),
TopPaths::DescentObject(inner) => inner.needs_all(),
TopPaths::DescentWildcard(inner) => inner.needs_all(),
TopPaths::Current(inner) => inner.needs_all(),
TopPaths::ArrayIndex(inner) => inner.needs_all(),
TopPaths::ArraySlice(inner) => inner.needs_all(),
TopPaths::UnionIndex(inner) => inner.needs_all(),
TopPaths::FilterPath(inner) => inner.needs_all(),
TopPaths::IdentityPath(inner) => inner.needs_all(),
TopPaths::FnPath(inner) => inner.needs_all(),
}
}
}

/// The method processes the indexes(all expressions indie [])
fn process_index<'a>(json_path_index: &'a JsonPathIndex, root: &'a Value) -> PathInstance<'a> {
match json_path_index {
JsonPathIndex::Single(index) => Box::new(ArrayIndex::new(index.as_u64().unwrap() as usize)),
JsonPathIndex::Slice(s, e, step) => Box::new(ArraySlice::new(*s, *e, *step)),
JsonPathIndex::UnionKeys(elems) => Box::new(UnionIndex::from_keys(elems)),
JsonPathIndex::UnionIndex(elems) => Box::new(UnionIndex::from_indexes(elems)),
JsonPathIndex::Filter(fe) => Box::new(FilterPath::new(fe, root)),
/// The basic type for instances.
pub(crate) type PathInstance<'a> = Box<dyn Path<'a, Data = Value> + 'a>;

/// The major method to process the top part of json part
pub(crate) fn json_path_instance<'a>(json_path: &'a JsonPath, root: &'a Value) -> TopPaths<'a> {
match json_path {
JsonPath::Root => TopPaths::RootPointer(RootPointer::new(root)),
JsonPath::Field(key) => TopPaths::ObjectField(ObjectField::new(key)),
JsonPath::Chain(chain) => TopPaths::Chain(Chain::from(chain, root)),
JsonPath::Wildcard => TopPaths::Wildcard(Wildcard {}),
JsonPath::Descent(key) => TopPaths::DescentObject(DescentObject::new(key)),
JsonPath::DescentW => TopPaths::DescentWildcard(DescentWildcard),
JsonPath::Current(value) => TopPaths::Current(Current::from(value, root)),
JsonPath::Index(JsonPathIndex::Single(index)) => {
TopPaths::ArrayIndex(ArrayIndex::new(index.as_u64().unwrap() as usize))
}
JsonPath::Index(JsonPathIndex::Slice(s, e, step)) => {
TopPaths::ArraySlice(ArraySlice::new(*s, *e, *step))
}
JsonPath::Index(JsonPathIndex::UnionKeys(elems)) => {
TopPaths::UnionIndex(UnionIndex::from_keys(elems))
}
JsonPath::Index(JsonPathIndex::UnionIndex(elems)) => {
TopPaths::UnionIndex(UnionIndex::from_indexes(elems))
}
JsonPath::Index(JsonPathIndex::Filter(fe)) => {
TopPaths::FilterPath(FilterPath::new(fe, root))
}
JsonPath::Empty => TopPaths::IdentityPath(IdentityPath {}),
JsonPath::Fn(Function::Length) => TopPaths::FnPath(FnPath::Size),
}
}

/// The method processes the operand inside the filter expressions
fn process_operand<'a>(op: &'a Operand, root: &'a Value) -> PathInstance<'a> {
match op {
Box::new(match op {
Operand::Static(v) => json_path_instance(&JsonPath::Root, v),
Operand::Dynamic(jp) => json_path_instance(jp, root),
}
})
}
8 changes: 5 additions & 3 deletions src/path/top.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use crate::parser::model::*;
use crate::path::{json_path_instance, JsonPathValue, Path, PathInstance};
use crate::path::{json_path_instance, JsonPathValue, Path};
use crate::JsonPathValue::{NewValue, NoValue, Slice};
use crate::{jsp_idx, jsp_obj, JsPathStr};
use serde_json::value::Value::{Array, Object};
use serde_json::{json, Value};

use super::TopPaths;

/// to process the element [*]
pub(crate) struct Wildcard {}

Expand Down Expand Up @@ -248,12 +250,12 @@ impl<'a> DescentObject<'a> {

/// the top method of the processing representing the chain of other operators
pub(crate) struct Chain<'a> {
chain: Vec<PathInstance<'a>>,
chain: Vec<TopPaths<'a>>,
is_search_length: bool,
}

impl<'a> Chain<'a> {
pub fn new(chain: Vec<PathInstance<'a>>, is_search_length: bool) -> Self {
pub fn new(chain: Vec<TopPaths<'a>>, is_search_length: bool) -> Self {
Chain {
chain,
is_search_length,
Expand Down

0 comments on commit 7ff57ae

Please sign in to comment.