diff --git a/Cargo.toml b/Cargo.toml index 3905cfb0..60cce38a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "jsonpath_lib" version = "0.3.0" +edition = "2021" authors = ["Changseok Han "] description = "It is JsonPath engine written in Rust. it provide a similar API interface in Webassembly and Javascript too. - Webassembly Demo: https://freestrings.github.io/jsonpath" diff --git a/lua/.gitignore b/lua/.gitignore deleted file mode 100644 index 7a7d6214..00000000 --- a/lua/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -.idea/* -.vscode -/target/ -Cargo.lock -docker_example/ab_results/** \ No newline at end of file diff --git a/lua/Cargo.toml b/lua/Cargo.toml deleted file mode 100644 index fe05a109..00000000 --- a/lua/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "jsonpath_lua" -version = "0.1.0" -authors = ["Changseok Han "] -license = "MIT" -[dependencies] -serde = { version = "1.0", features = ["derive"] } -serde_json = { version = "1.0", features = ["preserve_order"] } -jsonpath_lib = { path = "../" } - -[[bin]] -name = "bench" -path = "bench_lua_vs_rust/example.rs" - diff --git a/lua/bench_lua_vs_rust/example.lua b/lua/bench_lua_vs_rust/example.lua deleted file mode 100644 index 0c59a37d..00000000 --- a/lua/bench_lua_vs_rust/example.lua +++ /dev/null @@ -1,22 +0,0 @@ -local jsonpath = require("jsonpath") - -local iter; -if arg[1] == nil or arg[1] == '' then - iter = 5000; -else - iter = tonumber(arg[1]); -end - -print(string.format("%s - %u", "lua iter", iter)); - -local file = io.open("../../benchmark/example.json", "r"); -io.input(file) -local data = io.read("*a"); -io.close(file); - -jsonpath.init('../target/release/deps/libjsonpath_lib.so') -local template = jsonpath.compile("$..book[?(@.price<30 && @.category==\"fiction\")]"); -for i = 0, iter do - local r = template(data); --- print(r); -end diff --git a/lua/bench_lua_vs_rust/example.rs b/lua/bench_lua_vs_rust/example.rs deleted file mode 100644 index 68f63b2d..00000000 --- a/lua/bench_lua_vs_rust/example.rs +++ /dev/null @@ -1,46 +0,0 @@ -extern crate jsonpath_lib as jsonpath; -extern crate serde; -extern crate serde_json; - -use std::io::Read; - -use serde_json::Value; - -fn read_json(path: &str) -> String { - let mut f = std::fs::File::open(path).unwrap(); - let mut contents = String::new(); - f.read_to_string(&mut contents).unwrap(); - contents -} - -fn get_string() -> String { - read_json("../../benchmark/example.json") -} - -fn get_json() -> Value { - let string = get_string(); - serde_json::from_str(string.as_str()).unwrap() -} - -fn get_path() -> &'static str { - r#"$..book[?(@.price<30 && @.category=="fiction")]"# -} - -fn main() { - let args: Vec = std::env::args().collect(); - let iter = if args.len() < 2 { 5000_usize } else { args[1].as_str().parse::().unwrap() }; - - println!("rust iter - {}", iter); - - let json = get_json(); - for _ in 0..iter { - let mut selector = jsonpath::Selector::default(); - let _ = selector.str_path(get_path()); - selector.value(&json); - let r = selector.select(); - if r.is_err() { - panic!(); - } -// println!("{:?}", serde_json::to_string(&r.expect("")).unwrap()); - } -} \ No newline at end of file diff --git a/lua/bench_lua_vs_rust/run.sh b/lua/bench_lua_vs_rust/run.sh deleted file mode 100755 index e9e0863a..00000000 --- a/lua/bench_lua_vs_rust/run.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -# cd lua/bench_lua_vs_rust && ./run.sh - -set -e - -# http://luajit.org/index.html - -# cargo clean && \ -cargo build --release - -export JSONPATH_LIB_PATH="${PWD}/../target/release/deps" -export LUA_PATH="${PWD}/../?.lua;" - -echo -time cargo run --release --bin bench -- 1000 -echo -time luajit example.lua 1000 -echo -time cargo run --release --bin bench -- 5000 -echo -time luajit example.lua 5000 -echo -time cargo run --release --bin bench -- 10000 -echo -time luajit example.lua 10000 - diff --git a/lua/docker_example/default.conf b/lua/docker_example/default.conf deleted file mode 100644 index 4b04b076..00000000 --- a/lua/docker_example/default.conf +++ /dev/null @@ -1,107 +0,0 @@ -lua_package_path '/etc/jsonpath/?.lua;;'; - -access_log /var/log/access.log; -error_log /var/log/error.log info; - -lua_shared_dict jsonpaths 1m; - -init_by_lua_block { - local pathStrings = { - "$.store.book[*].author", - "$..author", - "$.store.*", - "$.store..price", - "$..book[2]", - "$..book[-2]", - "$..book[0,1]", - "$..book[:2]", - "$..book[1:2]", - "$..book[-2:]", - "$..book[2:]", - "$..book[?(@.isbn)]", - "$.store.book[?(@.price == 10)]", - "$..*", - "$..book[ ?( (@.price < 13 || $.store.bicycle.price < @.price) && @.price <=10 ) ]", - "$.store.book[?( (@.price < 10 || @.price > 10) && @.price > 10 )]", - "$..[?(@.originPrice > 1)]", - "$.pickBanner[?(@.originPrice > 1)]" - } - - local jp = require("jsonpath") - jp.init("/etc/jsonpath/libjsonpath_lib.so") - local jsonpaths = ngx.shared.jsonpaths - - for i, path in ipairs(pathStrings) do - jsonpaths:set(i, path) - jp.compile(path) - end - -} - -server { - listen 80; - server_name localhost; - - gzip on; - gzip_types text/plain application/json; - #gzip_comp_level 6; - #gzip_vary on; - - location / { - add_header 'Cache-Control' 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; - expires off; - - default_type 'text/plain'; - root /etc/jsonpath/example; - } - - location /filter { - # https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Accept-Encoding - proxy_set_header Accept-Encoding "*"; - - default_type 'text/plain'; - - rewrite /filter/(.*) /$1 break; - proxy_pass http://localhost; - - header_filter_by_lua_block { - ngx.header["content-length"] = nil - - local args = ngx.req.get_uri_args() - local jsonpaths = ngx.shared.jsonpaths - local path = jsonpaths:get(args['path']) - - if path == nil then - ngx.exit(ngx.HTTP_BAD_REQUEST) - end - } - - body_filter_by_lua_block { - local chunk, eof = ngx.arg[1], ngx.arg[2] - local buf = ngx.ctx.buf - - if eof then - if buf then - local args = ngx.req.get_uri_args() - local path = ngx.shared.jsonpaths:get(args['path']) - local jsonpath = require("jsonpath") - local template = jsonpath.exec(path) - local json = buf .. chunk - local result = template(json) - ngx.arg[1] = result - return - end - - return - end - - if buf then - ngx.ctx.buf = buf .. chunk - else - ngx.ctx.buf = chunk - end - - ngx.arg[1] = nil - } - } -} \ No newline at end of file diff --git a/lua/docker_example/init.lua b/lua/docker_example/init.lua deleted file mode 100644 index 38ac53fd..00000000 --- a/lua/docker_example/init.lua +++ /dev/null @@ -1,3 +0,0 @@ -local jsonpath = require("jsonpath") -jsonpath.init("/etc/jsonpath/libjsonpath_lib.so") -ngx.log(ngx.INFO, "loaded libjsonpath_lib.so") \ No newline at end of file diff --git a/lua/docker_example/run.sh b/lua/docker_example/run.sh deleted file mode 100755 index f55bd9d8..00000000 --- a/lua/docker_example/run.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -# cd lua && cargo build --release && cd docker_example && ./run.sh - -set -v - -[ "$(docker ps -a | grep jsonpath)" ] && docker kill jsonpath - -docker run -d --rm --name jsonpath \ - -v "${PWD}/../../benchmark/example.json":/etc/jsonpath/example/example.json:ro \ - -v "${PWD}/../../benchmark/big_example.json":/etc/jsonpath/example/big_example.json:ro \ - -v "${PWD}/../jsonpath.lua":/etc/jsonpath/jsonpath.lua:ro \ - -v "${PWD}/init.lua":/etc/jsonpath/init.lua:ro \ - -v "${PWD}/../target/release/deps/libjsonpath_lib.so":/etc/jsonpath/libjsonpath_lib.so:ro \ - -v "${PWD}/default.conf":/etc/nginx/conf.d/default.conf \ - -p 8080:80 \ - openresty/openresty:bionic - -#for i in {1..16}; do -# curl http://localhost:8080/filter/example.json?path=${i} -# echo -#done - -#ab -n 1000 -c 10 http://localhost:8080/filter/big_example.json?path=17 -#ab -n 1000 -c 10 http://localhost:8080/filter/big_example.json?path=18 \ No newline at end of file diff --git a/lua/jsonpath.lua b/lua/jsonpath.lua deleted file mode 100644 index ba5fc289..00000000 --- a/lua/jsonpath.lua +++ /dev/null @@ -1,60 +0,0 @@ -local ffi = require('ffi') - -ffi.cdef [[ -const char* ffi_select(const char *json_str, const char *path); -void *ffi_path_compile(const char *path); -const char* ffi_select_with_compiled_path(void *ptr, const char *json_str); -]] - -local jsonpath -local cache = {} -local module = {} - -local function existsVaiable(var) - for k, _ in pairs(_G) do - if k == var then - return true - end - end -end - -local _ngx -if existsVaiable('ngx') then - _ngx = ngx -else - _ngx = {} - _ngx.log = function(level, msg) - print('['..level..'] ' .. msg) - end -end - -function module.compile(path) - assert(jsonpath, '"libjsonpath_lib" is not loaded') - - if(cache[path] == nil) then - cache[path] = jsonpath.ffi_path_compile(path) - _ngx.log(_ngx.INFO, 'compile : [' .. path .. ']') - end -end - -function module.exec(path) - local compiledPath = cache[path] - - if(cache[path] == nil) then - assert(jsonpath, path .. ": is not compiled") - end - - return function(jsonStr) - local result = jsonpath.ffi_select_with_compiled_path(compiledPath, jsonStr) - return ffi.string(result); - end -end - -function module.init(path) - if jsonpath == nil then - jsonpath = ffi.load(path) - _ngx.log(_ngx.INFO, '"' .. path .. '" initialized') - end -end - -return module \ No newline at end of file diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs deleted file mode 100644 index 813486cd..00000000 --- a/src/ffi/mod.rs +++ /dev/null @@ -1,62 +0,0 @@ -use std::ffi::{CStr, CString}; -use std::os::raw::{c_char, c_void}; - -use {parser, select, select_as_str}; - -const INVALID_PATH: &str = "invalid path"; -const INVALID_JSON: &str = "invalud json"; - -fn to_str(v: *const c_char, err_msg: &str) -> &str { - unsafe { CStr::from_ptr(v) }.to_str().expect(err_msg) -} - -fn to_char_ptr(v: &str) -> *const c_char { - let s = CString::new(v).unwrap_or_else(|_| panic!("invalid string: {}", v)); - let ptr = s.as_ptr(); - std::mem::forget(s); - ptr -} - -#[no_mangle] -pub extern "C" fn ffi_select(json_str: *const c_char, path: *const c_char) -> *const c_char { - let json_str = to_str(json_str, INVALID_JSON); - let path = to_str(path, INVALID_PATH); - match select_as_str(json_str, path) { - Ok(v) => to_char_ptr(v.as_str()), - Err(e) => { - panic!("{:?}", e); - } - } -} - -#[no_mangle] -#[allow(clippy::forget_copy)] -pub extern "C" fn ffi_path_compile(path: *const c_char) -> *mut c_void { - let path = to_str(path, INVALID_PATH); - #[allow(deprecated)] - let ref_node = Box::into_raw(Box::new(parser::Parser::compile(path).unwrap())); - let ptr = ref_node as *mut c_void; - std::mem::forget(ref_node); - ptr -} - -#[no_mangle] -pub extern "C" fn ffi_select_with_compiled_path( - path_ptr: *mut c_void, - json_ptr: *const c_char, -) -> *const c_char { - #[allow(deprecated)] - let node = unsafe { Box::from_raw(path_ptr as *mut parser::Node) }; - let json_str = to_str(json_ptr, INVALID_JSON); - let json = serde_json::from_str(json_str) - .unwrap_or_else(|_| panic!("invalid json string: {}", json_str)); - - #[allow(deprecated)] - let mut selector = select::Selector::default(); - let found = selector.compiled_path(&node).value(&json).select().unwrap(); - std::mem::forget(node); - - let result = serde_json::to_string(&found) - .unwrap_or_else(|_| panic!("json serialize error: {:?}", found)); - to_char_ptr(result.as_str()) -} diff --git a/src/lib.rs b/src/lib.rs index 664e69a0..d2856a34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -131,28 +131,19 @@ extern crate serde_json; use serde_json::Value; #[allow(deprecated)] -use parser::Node; +use crate::parser::Node; #[allow(deprecated)] -pub use parser::Parser; +pub use crate::parser::Parser; #[allow(deprecated)] -pub use select::{Selector, SelectorMut}; +pub use crate::select::{Selector, SelectorMut}; -#[deprecated( -since = "0.4.0", -note = "It will be move to common module. since 0.5" -)] -pub use select::JsonPathError; +#[deprecated(since = "0.4.0", note = "It will be move to common module. since 0.5")] +pub use crate::select::JsonPathError; -pub use selector::{JsonSelector, JsonSelectorMut}; -pub use paths::PathParser; +pub use crate::paths::PathParser; +pub use crate::selector::{JsonSelector, JsonSelectorMut}; use std::rc::Rc; -#[doc(hidden)] -#[deprecated( -since = "0.4.0", -note = "'ffi' is moved to another location like 'wasm' from version 0.5.x" -)] -mod ffi; #[doc(hidden)] mod parser; #[doc(hidden)] @@ -165,7 +156,9 @@ impl From<&paths::TokenError> for JsonPathError { fn from(e: &paths::TokenError) -> Self { match e { paths::TokenError::Eof => JsonPathError::Path("Eof".to_string()), - paths::TokenError::Position(pos) => JsonPathError::Path(["Position:", &pos.to_string()].concat()) + paths::TokenError::Position(pos) => { + JsonPathError::Path(["Position:", &pos.to_string()].concat()) + } } } } @@ -198,8 +191,8 @@ impl From<&paths::TokenError> for JsonPathError { /// ]); /// ``` #[deprecated( -since = "0.2.5", -note = "Please use the PathCompiled::compile function instead. It will be removed from 0.4.1" + since = "0.2.5", + note = "Please use the PathCompiled::compile function instead. It will be removed from 0.4.1" )] pub fn compile(path: &str) -> impl FnMut(&Value) -> Result, JsonPathError> { #[allow(deprecated)] @@ -249,11 +242,17 @@ pub fn compile(path: &str) -> impl FnMut(&Value) -> Result, JsonPath /// ]); /// ``` #[allow(clippy::needless_lifetimes)] -pub fn selector<'a>(json: &'a Value) -> impl FnMut(&'a str) -> Result, JsonPathError> { +pub fn selector<'a>( + json: &'a Value, +) -> impl FnMut(&'a str) -> Result, JsonPathError> { let mut selector = JsonSelector::default(); move |path| { let parser = PathParser::compile(path).map_err(|e| JsonPathError::from(&e))?; - selector.reset_parser(parser).value(json).reset_value().select() + selector + .reset_parser(parser) + .value(json) + .reset_value() + .select() } } @@ -303,9 +302,9 @@ pub fn selector<'a>(json: &'a Value) -> impl FnMut(&'a str) -> Result(json: &'a Value) - -> impl FnMut(&'a str) -> Result, JsonPathError> + '_ -{ +pub fn selector_as<'a, T: serde::de::DeserializeOwned>( + json: &'a Value, +) -> impl FnMut(&'a str) -> Result, JsonPathError> + '_ { let mut selector = JsonSelector::default(); let _ = selector.value(json); move |path: &str| { @@ -555,11 +554,14 @@ where /// ]})); /// ``` pub fn replace_with_tokens(value: Value, path: &str, fun: &mut F) -> Result - where - F: FnMut(Value, &[String]) -> Result, JsonPathError>, +where + F: FnMut(Value, &[String]) -> Result, JsonPathError>, { let mut selector = SelectorMut::default(); - let value = selector.str_path(path)?.value(value).replace_with_tokens(fun)?; + let value = selector + .str_path(path)? + .value(value) + .replace_with_tokens(fun)?; Ok(value.take().unwrap_or(Value::Null)) } @@ -606,10 +608,7 @@ pub fn replace_with_tokens(value: Value, path: &str, fun: &mut F) -> Result Result { let node = parser::Parser::compile(path)?; - Ok(Self { - node - }) + Ok(Self { node }) } /// Execute the select operation on the pre-compiled path. @@ -688,7 +685,7 @@ impl<'a> PathCompiled<'a> { pub fn compile(path: &str) -> Result { let parser = PathParser::compile(path).map_err(|e| JsonPathError::from(&e))?; Ok(PathCompiled { - parser: Rc::new(parser) + parser: Rc::new(parser), }) } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index affb887a..6d1ccd49 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -13,8 +13,8 @@ mod utils { use std::str::FromStr; pub fn string_to_num(string: &str, msg_handler: F) -> Result - where - F: Fn() -> String, + where + F: Fn() -> String, { match string.parse() { Ok(n) => Ok(n), @@ -481,14 +481,15 @@ impl Parser { let node = Self::term(tokenizer)?; Self::eat_whitespace(tokenizer); - if matches!(tokenizer.peek_token(), + if matches!( + tokenizer.peek_token(), Ok(Token::Equal(_)) - | Ok(Token::NotEqual(_)) - | Ok(Token::Little(_)) - | Ok(Token::LittleOrEqual(_)) - | Ok(Token::Greater(_)) - | Ok(Token::GreaterOrEqual(_))) - { + | Ok(Token::NotEqual(_)) + | Ok(Token::Little(_)) + | Ok(Token::LittleOrEqual(_)) + | Ok(Token::Greater(_)) + | Ok(Token::GreaterOrEqual(_)) + ) { Self::op(node, tokenizer) } else if has_prop_candidate { Ok(node) @@ -543,21 +544,15 @@ impl Parser { _ => Self::paths(node, tokenizer), } } - Ok(Token::Absolute(_)) => { - Self::json_path(tokenizer) - } + Ok(Token::Absolute(_)) => Self::json_path(tokenizer), Ok(Token::DoubleQuoted(_, _)) | Ok(Token::SingleQuoted(_, _)) => { Self::array_quote_value(tokenizer) } - Ok(Token::Key(_, key)) => { - match key.as_bytes()[0] { - b'-' | b'0'..=b'9' => Self::term_num(tokenizer), - _ => Self::boolean(tokenizer), - } - } - _ => { - Err(tokenizer.err_msg()) - } + Ok(Token::Key(_, key)) => match key.as_bytes()[0] { + b'-' | b'0'..=b'9' => Self::term_num(tokenizer), + _ => Self::boolean(tokenizer), + }, + _ => Err(tokenizer.err_msg()), } } @@ -628,48 +623,48 @@ pub trait NodeVisitor { } ParseToken::In | ParseToken::Leaves => { if let Some(n) = &node.left { - self.visit(&*n); + self.visit(n); } self.visit_token(&node.token); if let Some(n) = &node.right { - self.visit(&*n); + self.visit(n); } } ParseToken::Array => { if let Some(n) = &node.left { - self.visit(&*n); + self.visit(n); } self.visit_token(&node.token); if let Some(n) = &node.right { - self.visit(&*n); + self.visit(n); } self.visit_token(&ParseToken::ArrayEof); } ParseToken::Filter(FilterToken::And) | ParseToken::Filter(FilterToken::Or) => { if let Some(n) = &node.left { - self.visit(&*n); + self.visit(n); } if let Some(n) = &node.right { - self.visit(&*n); + self.visit(n); } self.visit_token(&node.token); } ParseToken::Filter(_) => { if let Some(n) = &node.left { - self.visit(&*n); + self.visit(n); } self.end_term(); if let Some(n) = &node.right { - self.visit(&*n); + self.visit(n); } self.end_term(); diff --git a/src/parser/tokenizer.rs b/src/parser/tokenizer.rs index 3e079b9d..67d7d1e8 100644 --- a/src/parser/tokenizer.rs +++ b/src/parser/tokenizer.rs @@ -105,23 +105,9 @@ impl<'a> Tokenizer<'a> { fn dolla(&mut self, pos: usize, ch: char) -> Result { let fun = |c: &char| match c { - &CH_DOT - | &CH_ASTERISK - | &CH_LARRAY - | &CH_RARRAY - | &CH_LPAREN - | &CH_RPAREN - | &CH_AT - | &CH_QUESTION - | &CH_COMMA - | &CH_SEMICOLON - | &CH_LITTLE - | &CH_GREATER - | &CH_EQUAL - | &CH_AMPERSAND - | &CH_PIPE - | &CH_EXCLAMATION - => false, + &CH_DOT | &CH_ASTERISK | &CH_LARRAY | &CH_RARRAY | &CH_LPAREN | &CH_RPAREN | &CH_AT + | &CH_QUESTION | &CH_COMMA | &CH_SEMICOLON | &CH_LITTLE | &CH_GREATER | &CH_EQUAL + | &CH_AMPERSAND | &CH_PIPE | &CH_EXCLAMATION => false, _ => !c.is_whitespace(), }; let (_, mut vec) = self.input.take_while(fun).map_err(to_token_error)?; @@ -243,24 +229,9 @@ impl<'a> Tokenizer<'a> { fn other(&mut self, pos: usize, ch: char) -> Result { let fun = |c: &char| match c { - &CH_DOLLA - | &CH_DOT - | &CH_ASTERISK - | &CH_LARRAY - | &CH_RARRAY - | &CH_LPAREN - | &CH_RPAREN - | &CH_AT - | &CH_QUESTION - | &CH_COMMA - | &CH_SEMICOLON - | &CH_LITTLE - | &CH_GREATER - | &CH_EQUAL - | &CH_AMPERSAND - | &CH_PIPE - | &CH_EXCLAMATION - => false, + &CH_DOLLA | &CH_DOT | &CH_ASTERISK | &CH_LARRAY | &CH_RARRAY | &CH_LPAREN + | &CH_RPAREN | &CH_AT | &CH_QUESTION | &CH_COMMA | &CH_SEMICOLON | &CH_LITTLE + | &CH_GREATER | &CH_EQUAL | &CH_AMPERSAND | &CH_PIPE | &CH_EXCLAMATION => false, _ => !c.is_whitespace(), }; let (_, mut vec) = self.input.take_while(fun).map_err(to_token_error)?; diff --git a/src/paths/mod.rs b/src/paths/mod.rs index 59474c47..186008c5 100644 --- a/src/paths/mod.rs +++ b/src/paths/mod.rs @@ -4,9 +4,9 @@ pub use self::path_parser::PathParser; pub use self::str_reader::StrRange; pub use self::tokenizer::TokenError; +mod parser_node_visitor; +mod parser_token_handler; +mod path_parser; mod str_reader; mod tokenizer; pub mod tokens; -mod parser_token_handler; -mod parser_node_visitor; -mod path_parser; diff --git a/src/paths/parser_node_visitor.rs b/src/paths/parser_node_visitor.rs index ab35c1e3..e84cb2e2 100644 --- a/src/paths/parser_node_visitor.rs +++ b/src/paths/parser_node_visitor.rs @@ -1,12 +1,12 @@ -use paths::{ParserTokenHandler, StrRange}; -use paths::path_parser::ParserNode; -use paths::tokens::{FilterToken, ParseToken}; +use crate::paths::path_parser::ParserNode; +use crate::paths::tokens::{FilterToken, ParseToken}; +use crate::paths::{ParserTokenHandler, StrRange}; pub trait ParserNodeVisitor<'a> { fn visit(&self, parse_node: &ParserNode, token_handler: &mut F, parse_value_reader: &F1) - where - F: ParserTokenHandler<'a>, - F1: Fn(&StrRange) -> &'a str + where + F: ParserTokenHandler<'a>, + F1: Fn(&StrRange) -> &'a str, { trace!("visit {:?}", parse_node); match &parse_node.token { @@ -23,46 +23,46 @@ pub trait ParserNodeVisitor<'a> { } ParseToken::In | ParseToken::Leaves => { if let Some(n) = &parse_node.left { - self.visit(&*n, token_handler, parse_value_reader); + self.visit(n, token_handler, parse_value_reader); } token_handler.handle(&parse_node.token, parse_value_reader); if let Some(n) = &parse_node.right { - self.visit(&*n, token_handler, parse_value_reader); + self.visit(n, token_handler, parse_value_reader); } } ParseToken::Array => { if let Some(n) = &parse_node.left { - self.visit(&*n, token_handler, parse_value_reader); + self.visit(n, token_handler, parse_value_reader); } token_handler.handle(&parse_node.token, parse_value_reader); if let Some(n) = &parse_node.right { - self.visit(&*n, token_handler, parse_value_reader); + self.visit(n, token_handler, parse_value_reader); } token_handler.handle(&ParseToken::ArrayEof, parse_value_reader); } ParseToken::Filter(FilterToken::And) | ParseToken::Filter(FilterToken::Or) => { if let Some(n) = &parse_node.left { - self.visit(&*n, token_handler, parse_value_reader); + self.visit(n, token_handler, parse_value_reader); } if let Some(n) = &parse_node.right { - self.visit(&*n, token_handler, parse_value_reader); + self.visit(n, token_handler, parse_value_reader); } token_handler.handle(&parse_node.token, parse_value_reader); } ParseToken::Filter(_) => { if let Some(n) = &parse_node.left { - self.visit(&*n, token_handler, parse_value_reader); + self.visit(n, token_handler, parse_value_reader); } if let Some(n) = &parse_node.right { - self.visit(&*n, token_handler, parse_value_reader); + self.visit(n, token_handler, parse_value_reader); } token_handler.handle(&parse_node.token, parse_value_reader); @@ -70,4 +70,4 @@ pub trait ParserNodeVisitor<'a> { _ => {} } } -} \ No newline at end of file +} diff --git a/src/paths/parser_token_handler.rs b/src/paths/parser_token_handler.rs index ec06d410..65fcd24f 100644 --- a/src/paths/parser_token_handler.rs +++ b/src/paths/parser_token_handler.rs @@ -3,6 +3,6 @@ use super::tokens::ParseToken; pub trait ParserTokenHandler<'a> { fn handle(&mut self, token: &ParseToken, parse_value_reader: &F) - where - F: Fn(&StrRange) -> &'a str; -} \ No newline at end of file + where + F: Fn(&StrRange) -> &'a str; +} diff --git a/src/paths/path_parser.rs b/src/paths/path_parser.rs index 178e105d..816b1ec6 100644 --- a/src/paths/path_parser.rs +++ b/src/paths/path_parser.rs @@ -1,7 +1,7 @@ use std::str::FromStr; -use super::parser_token_handler::ParserTokenHandler; use super::parser_node_visitor::ParserNodeVisitor; +use super::parser_token_handler::ParserTokenHandler; use super::str_reader::StrRange; use super::tokenizer::{TokenError, TokenReader}; use super::tokens::{FilterToken, ParseToken, Token}; @@ -19,8 +19,8 @@ impl<'a> PathParser<'a> { } pub(crate) fn parse(&self, parse_token_handler: &mut F) -> Result<(), String> - where - F: ParserTokenHandler<'a>, + where + F: ParserTokenHandler<'a>, { if self.parser.parse_node.is_none() { unreachable!() @@ -54,8 +54,8 @@ impl<'a> ParserImpl<'a> { } fn string_to_num(string: &str, msg_handler: F) -> Result - where - F: Fn() -> TokenError, + where + F: Fn() -> TokenError, { match string.parse() { Ok(n) => Ok(n), @@ -293,9 +293,7 @@ impl<'a> ParserImpl<'a> { self.eat_token(); self.range_to() } - Ok(Token::DoubleQuoted(_)) | Ok(Token::SingleQuoted(_)) => { - self.array_quote_value() - } + Ok(Token::DoubleQuoted(_)) | Ok(Token::SingleQuoted(_)) => self.array_quote_value(), Err(TokenError::Eof) => Ok(self.create_node(ParseToken::Eof)), _ => { self.eat_token(); @@ -472,14 +470,15 @@ impl<'a> ParserImpl<'a> { let node = self.term()?; self.eat_whitespace(); - if matches!(self.token_reader.peek_token(), + if matches!( + self.token_reader.peek_token(), Ok(Token::Equal(_)) - | Ok(Token::NotEqual(_)) - | Ok(Token::Little(_)) - | Ok(Token::LittleOrEqual(_)) - | Ok(Token::Greater(_)) - | Ok(Token::GreaterOrEqual(_))) - { + | Ok(Token::NotEqual(_)) + | Ok(Token::Little(_)) + | Ok(Token::LittleOrEqual(_)) + | Ok(Token::Greater(_)) + | Ok(Token::GreaterOrEqual(_)) + ) { self.op(node) } else if has_prop_candidate { Ok(node) @@ -511,7 +510,9 @@ impl<'a> ParserImpl<'a> { match self.token_reader.next_token() { Ok(Token::Key(s)) => { let frac = self.token_reader.read_value(&s); - let number = Self::string_to_num(&[num, ".", frac].concat(), || self.token_reader.to_error())?; + let number = Self::string_to_num(&[num, ".", frac].concat(), || { + self.token_reader.to_error() + })?; Ok(self.create_node(ParseToken::Number(number))) } _ => Err(self.token_reader.to_error()), @@ -552,15 +553,9 @@ impl<'a> ParserImpl<'a> { _ => self.paths(node), } } - Ok(Token::Absolute(_)) => { - self.json_path() - } - Ok(Token::DoubleQuoted(_)) | Ok(Token::SingleQuoted(_)) => { - self.array_quote_value() - } - _ => { - Err(self.token_reader.to_error()) - } + Ok(Token::Absolute(_)) => self.json_path(), + Ok(Token::DoubleQuoted(_)) | Ok(Token::SingleQuoted(_)) => self.array_quote_value(), + _ => Err(self.token_reader.to_error()), } } @@ -623,10 +618,10 @@ pub struct ParserNode { #[cfg(test)] mod path_parser_tests { - use paths::ParserTokenHandler; - use paths::path_parser::PathParser; - use paths::str_reader::StrRange; - use paths::tokens::{FilterToken, ParseToken}; + use crate::paths::path_parser::PathParser; + use crate::paths::str_reader::StrRange; + use crate::paths::tokens::{FilterToken, ParseToken}; + use crate::paths::ParserTokenHandler; struct NodeVisitorTestImpl<'a> { input: &'a str, @@ -650,8 +645,8 @@ mod path_parser_tests { impl<'a> ParserTokenHandler<'a> for NodeVisitorTestImpl<'a> { fn handle(&mut self, token: &ParseToken, _: &F) - where - F: Fn(&StrRange) -> &'a str + where + F: Fn(&StrRange) -> &'a str, { trace!("handle {:?}", token); self.stack.push(token.clone()); @@ -964,7 +959,10 @@ mod path_parser_tests { Ok(vec![ ParseToken::Absolute, ParseToken::Array, - ParseToken::Keys(vec![StrRange::new(2, "\"a\"".len()), StrRange::new(7, "'b'".len())]), + ParseToken::Keys(vec![ + StrRange::new(2, "\"a\"".len()), + StrRange::new(7, "'b'".len()) + ]), ParseToken::ArrayEof ]) ); @@ -1127,11 +1125,11 @@ mod path_parser_tests { ); assert_eq!( - run(r#"$['single\'quote']"#), + run(r"$['single\'quote']"), Ok(vec![ ParseToken::Absolute, ParseToken::Array, - ParseToken::Key(StrRange::new(2, r#"'single\'quote'"#.len())), + ParseToken::Key(StrRange::new(2, r"'single\'quote'".len())), ParseToken::ArrayEof ]) ); diff --git a/src/paths/str_reader.rs b/src/paths/str_reader.rs index 11b74a70..1e5aca29 100644 --- a/src/paths/str_reader.rs +++ b/src/paths/str_reader.rs @@ -28,7 +28,12 @@ pub(crate) struct StrReader<'a> { impl<'a> StrReader<'a> { pub fn new(input: &'a str) -> Self { - StrReader { input, pos: 0, chars: input.chars(), peeked: None } + StrReader { + input, + pos: 0, + chars: input.chars(), + peeked: None, + } } pub fn peek_char(&mut self) -> Result { @@ -37,8 +42,8 @@ impl<'a> StrReader<'a> { } pub fn take_while(&mut self, fun: F) -> Result - where - F: Fn(&char) -> bool, + where + F: Fn(&char) -> bool, { let mut char_len: usize = 0; while let Some(c) = self.peek() { @@ -47,7 +52,7 @@ impl<'a> StrReader<'a> { } match self.next() { Some(ch) => char_len += ch.len_utf8(), - _ => return Err(ReaderError::Eof) + _ => return Err(ReaderError::Eof), } } diff --git a/src/paths/tokenizer.rs b/src/paths/tokenizer.rs index fd61c7e5..764118e5 100644 --- a/src/paths/tokenizer.rs +++ b/src/paths/tokenizer.rs @@ -50,23 +50,9 @@ impl<'a> Tokenizer<'a> { fn dolla(&mut self) -> Result { let fun = |c: &char| match c { - &CH_DOT - | &CH_ASTERISK - | &CH_LARRAY - | &CH_RARRAY - | &CH_LPAREN - | &CH_RPAREN - | &CH_AT - | &CH_QUESTION - | &CH_COMMA - | &CH_SEMICOLON - | &CH_LITTLE - | &CH_GREATER - | &CH_EQUAL - | &CH_AMPERSAND - | &CH_PIPE - | &CH_EXCLAMATION - => false, + &CH_DOT | &CH_ASTERISK | &CH_LARRAY | &CH_RARRAY | &CH_LPAREN | &CH_RPAREN | &CH_AT + | &CH_QUESTION | &CH_COMMA | &CH_SEMICOLON | &CH_LITTLE | &CH_GREATER | &CH_EQUAL + | &CH_AMPERSAND | &CH_PIPE | &CH_EXCLAMATION => false, _ => !c.is_whitespace(), }; let read = self.input.take_while(fun).map_err(to_token_error)?; @@ -78,11 +64,17 @@ impl<'a> Tokenizer<'a> { } fn quote(&mut self, ch: char) -> Result { - let span = self.input.take_while(|c| *c != ch).map_err(to_token_error)?; + let span = self + .input + .take_while(|c| *c != ch) + .map_err(to_token_error)?; let val = self.input.read(&span); if let Some('\\') = val.chars().last() { self.input.next_char().map_err(to_token_error)?; - let remain_span = self.input.take_while(|c| *c != ch).map_err(to_token_error)?; + let remain_span = self + .input + .take_while(|c| *c != ch) + .map_err(to_token_error)?; self.input.next_char().map_err(to_token_error)?; Ok(StrRange::new(span.pos, remain_span.offset)) } else { @@ -175,24 +167,9 @@ impl<'a> Tokenizer<'a> { fn other(&mut self) -> Result { let fun = |c: &char| match c { - &CH_DOLLA - | &CH_DOT - | &CH_ASTERISK - | &CH_LARRAY - | &CH_RARRAY - | &CH_LPAREN - | &CH_RPAREN - | &CH_AT - | &CH_QUESTION - | &CH_COMMA - | &CH_SEMICOLON - | &CH_LITTLE - | &CH_GREATER - | &CH_EQUAL - | &CH_AMPERSAND - | &CH_PIPE - | &CH_EXCLAMATION - => false, + &CH_DOLLA | &CH_DOT | &CH_ASTERISK | &CH_LARRAY | &CH_RARRAY | &CH_LPAREN + | &CH_RPAREN | &CH_AT | &CH_QUESTION | &CH_COMMA | &CH_SEMICOLON | &CH_LITTLE + | &CH_GREATER | &CH_EQUAL | &CH_AMPERSAND | &CH_PIPE | &CH_EXCLAMATION => false, _ => !c.is_whitespace(), }; let span = self.input.take_while(fun).map_err(to_token_error)?; @@ -270,7 +247,8 @@ impl<'a> TokenReader<'a> { let peeked = self.peeked.get_or_insert_with(|| { let mut token = tokenizer.next_token(); if let Ok(token) = &mut token { - let token = token.reset_span(StrRange::new(prev_pos, tokenizer.current_pos() - prev_pos)); + let token = + token.reset_span(StrRange::new(prev_pos, tokenizer.current_pos() - prev_pos)); return Ok(token); } token @@ -310,9 +288,9 @@ impl<'a> TokenReader<'a> { #[cfg(test)] mod tokenizer_tests { - use paths::str_reader::StrRange; - use paths::tokenizer::{TokenError, TokenReader}; - use paths::tokens::Token; + use crate::paths::str_reader::StrRange; + use crate::paths::tokenizer::{TokenError, TokenReader}; + use crate::paths::tokens::Token; fn setup() { let _ = env_logger::try_init(); @@ -393,7 +371,11 @@ mod tokenizer_tests { run( "$..", ( - vec![Token::Absolute(StrRange::new(0, 1)), Token::Dot(StrRange::new(1, 1)), Token::Dot(StrRange::new(2, 1))], + vec![ + Token::Absolute(StrRange::new(0, 1)), + Token::Dot(StrRange::new(1, 1)), + Token::Dot(StrRange::new(2, 1)), + ], Some(TokenError::Eof), ), ); @@ -541,12 +523,12 @@ mod tokenizer_tests { ); run( - r#"$['single\'quote']"#, + r"$['single\'quote']", ( vec![ Token::Absolute(StrRange::new(0, 1)), Token::OpenArray(StrRange::new(1, 1)), - Token::SingleQuoted(StrRange::new(2, r#"'single\'quote'"#.len())), + Token::SingleQuoted(StrRange::new(2, r"'single\'quote'".len())), Token::CloseArray(StrRange::new(17, 1)), ], Some(TokenError::Eof), @@ -554,14 +536,14 @@ mod tokenizer_tests { ); run( - r#"$['single\'1','single\'2']"#, + r"$['single\'1','single\'2']", ( vec![ Token::Absolute(StrRange::new(0, 1)), Token::OpenArray(StrRange::new(1, 1)), - Token::SingleQuoted(StrRange::new(2, r#"'single\'1'"#.len())), + Token::SingleQuoted(StrRange::new(2, r"'single\'1'".len())), Token::Comma(StrRange::new(13, 1)), - Token::SingleQuoted(StrRange::new(14, r#"'single\'2'"#.len())), + Token::SingleQuoted(StrRange::new(14, r"'single\'2'".len())), Token::CloseArray(StrRange::new(25, 1)), ], Some(TokenError::Eof), @@ -581,4 +563,4 @@ mod tokenizer_tests { ), ); } -} \ No newline at end of file +} diff --git a/src/paths/tokens.rs b/src/paths/tokens.rs index 0d4cc919..f7cf272f 100644 --- a/src/paths/tokens.rs +++ b/src/paths/tokens.rs @@ -128,4 +128,4 @@ pub enum FilterToken { GreaterOrEqual, And, Or, -} \ No newline at end of file +} diff --git a/src/select/cmp.rs b/src/select/cmp.rs index 74834d34..37b23147 100644 --- a/src/select/cmp.rs +++ b/src/select/cmp.rs @@ -193,7 +193,7 @@ impl Cmp for CmpOr { let mut ret = [v1, v2].concat(); for x in (0..ret.len()).rev() { - for y in (x+1..ret.len()).rev() { + for y in (x + 1..ret.len()).rev() { if ret[x] == ret[y] { ret.remove(y); } @@ -204,7 +204,6 @@ impl Cmp for CmpOr { } } - // #[cfg(test)] // mod cmp_inner_tests { // use serde_json::Value; diff --git a/src/select/expr_term.rs b/src/select/expr_term.rs index f128a7cc..fbc41418 100644 --- a/src/select/expr_term.rs +++ b/src/select/expr_term.rs @@ -1,6 +1,6 @@ +use crate::select::cmp::*; +use crate::select::{to_f64, FilterKey}; use serde_json::{Number, Value}; -use select::cmp::*; -use select::{FilterKey, to_f64}; #[derive(Debug, PartialEq, Clone)] pub(super) enum ExprTerm<'a> { diff --git a/src/select/mod.rs b/src/select/mod.rs index 3c13a90d..3e597c96 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -1,10 +1,10 @@ use std::collections::HashSet; use std::fmt; -use serde_json::{Number, Value}; use serde_json::map::Entry; +use serde_json::{Number, Value}; -use parser::*; +use crate::parser::*; use self::expr_term::*; use self::value_walker::ValueWalker; @@ -42,7 +42,7 @@ pub enum JsonPathError { EmptyValue, Path(String), Serde(String), - Replacement(String) + Replacement(String), } impl std::error::Error for JsonPathError {} @@ -60,7 +60,10 @@ impl fmt::Display for JsonPathError { JsonPathError::EmptyValue => f.write_str("json value not set"), JsonPathError::Path(msg) => f.write_str(&format!("path error: \n{}\n", msg)), JsonPathError::Serde(msg) => f.write_str(&format!("serde error: \n{}\n", msg)), - JsonPathError::Replacement(msg) => f.write_str(&format!("error occurred during jsonpath replacement: \n{}\n", msg)) + JsonPathError::Replacement(msg) => f.write_str(&format!( + "error occurred during jsonpath replacement: \n{}\n", + msg + )), } } } @@ -87,7 +90,9 @@ impl<'a> FilterTerms<'a> { self.0.pop() } - fn filter_json_term, &mut Vec<&'a Value>, &mut HashSet) -> FilterKey>( + fn filter_json_term< + F: Fn(&Vec<&'a Value>, &mut Vec<&'a Value>, &mut HashSet) -> FilterKey, + >( &mut self, e: ExprTerm<'a>, fun: F, @@ -98,33 +103,40 @@ impl<'a> FilterTerms<'a> { let mut tmp = Vec::new(); let mut not_matched = HashSet::new(); let filter_key = if let Some(FilterKey::String(key)) = fk { - let key_contained = &vec.iter().map(|v| match v { - Value::Object(map) if map.contains_key(&key) => map.get(&key).unwrap(), - _ => v, - }).collect(); + let key_contained = &vec + .iter() + .map(|v| match v { + Value::Object(map) if map.contains_key(&key) => map.get(&key).unwrap(), + _ => v, + }) + .collect(); fun(key_contained, &mut tmp, &mut not_matched) } else { fun(&vec, &mut tmp, &mut not_matched) }; if rel.is_some() { - self.0.push(Some(ExprTerm::Json(rel, Some(filter_key), tmp))); + self.0 + .push(Some(ExprTerm::Json(rel, Some(filter_key), tmp))); } else { - let filtered: Vec<&Value> = vec.iter().enumerate() - .filter( - |(idx, _)| !not_matched.contains(idx) - ) + let filtered: Vec<&Value> = vec + .iter() + .enumerate() + .filter(|(idx, _)| !not_matched.contains(idx)) .map(|(_, v)| *v) .collect(); - self.0.push(Some(ExprTerm::Json(Some(filtered), Some(filter_key), tmp))); + self.0 + .push(Some(ExprTerm::Json(Some(filtered), Some(filter_key), tmp))); } } else { unreachable!("unexpected: ExprTerm: {:?}", e); } } - fn push_json_term, &mut Vec<&'a Value>, &mut HashSet) -> FilterKey>( + fn push_json_term< + F: Fn(&Vec<&'a Value>, &mut Vec<&'a Value>, &mut HashSet) -> FilterKey, + >( &mut self, current: &Option>, fun: F, @@ -135,7 +147,8 @@ impl<'a> FilterTerms<'a> { let mut tmp = Vec::new(); let mut not_matched = HashSet::new(); let filter_key = fun(current, &mut tmp, &mut not_matched); - self.0.push(Some(ExprTerm::Json(None, Some(filter_key), tmp))); + self.0 + .push(Some(ExprTerm::Json(None, Some(filter_key), tmp))); } } @@ -196,7 +209,11 @@ impl<'a> FilterTerms<'a> { debug!("filter_next_with_str : {}, {:?}", key, self.0); } - fn collect_next_with_num(&mut self, current: &Option>, index: f64) -> Option> { + fn collect_next_with_num( + &mut self, + current: &Option>, + index: f64, + ) -> Option> { fn _collect<'a>(tmp: &mut Vec<&'a Value>, vec: &'a [Value], index: f64) { let index = abs_index(index as isize, vec.len()); if let Some(v) = vec.get(index) { @@ -230,10 +247,7 @@ impl<'a> FilterTerms<'a> { } } - debug!( - "collect_next_with_num : {:?}, {:?}", - &index, ¤t - ); + debug!("collect_next_with_num : {:?}, {:?}", &index, ¤t); None } @@ -264,7 +278,11 @@ impl<'a> FilterTerms<'a> { None } - fn collect_next_with_str(&mut self, current: &Option>, keys: &[String]) -> Option> { + fn collect_next_with_str( + &mut self, + current: &Option>, + keys: &[String], + ) -> Option> { if let Some(current) = current { let mut tmp = Vec::new(); for c in current { @@ -285,10 +303,7 @@ impl<'a> FilterTerms<'a> { } } - debug!( - "collect_next_with_str : {:?}, {:?}", - keys, ¤t - ); + debug!("collect_next_with_str : {:?}, {:?}", keys, ¤t); None } @@ -304,7 +319,11 @@ impl<'a> FilterTerms<'a> { None } - fn collect_all_with_str(&mut self, current: &Option>, key: &str) -> Option> { + fn collect_all_with_str( + &mut self, + current: &Option>, + key: &str, + ) -> Option> { if let Some(current) = current { let mut tmp = Vec::new(); ValueWalker::all_with_str(current, &mut tmp, key, false); @@ -316,7 +335,11 @@ impl<'a> FilterTerms<'a> { None } - fn collect_all_with_num(&mut self, current: &Option>, index: f64) -> Option> { + fn collect_all_with_num( + &mut self, + current: &Option>, + index: f64, + ) -> Option> { if let Some(current) = current { let mut tmp = Vec::new(); ValueWalker::all_with_num(current, &mut tmp, index); @@ -506,7 +529,8 @@ impl<'a, 'b> Selector<'a, 'b> { if self.is_last_before_token_match(ParseToken::Array) { if let Some(Some(e)) = self.selector_filter.pop_term() { if let ExprTerm::String(key) = e { - self.selector_filter.filter_next_with_str(&self.current, &key); + self.selector_filter + .filter_next_with_str(&self.current, &key); self.tokens.pop(); return; } @@ -521,12 +545,16 @@ impl<'a, 'b> Selector<'a, 'b> { if let Some(Some(e)) = self.selector_filter.pop_term() { let selector_filter_consumed = match &e { ExprTerm::Number(n) => { - self.current = self.selector_filter.collect_all_with_num(&self.current, to_f64(n)); + self.current = self + .selector_filter + .collect_all_with_num(&self.current, to_f64(n)); self.selector_filter.pop_term(); true } ExprTerm::String(key) => { - self.current = self.selector_filter.collect_all_with_str(&self.current, key); + self.current = self + .selector_filter + .collect_all_with_str(&self.current, key); self.selector_filter.pop_term(); true } @@ -545,10 +573,14 @@ impl<'a, 'b> Selector<'a, 'b> { if let Some(Some(e)) = self.selector_filter.pop_term() { match e { ExprTerm::Number(n) => { - self.current = self.selector_filter.collect_next_with_num(&self.current, to_f64(&n)); + self.current = self + .selector_filter + .collect_next_with_num(&self.current, to_f64(&n)); } ExprTerm::String(key) => { - self.current = self.selector_filter.collect_next_with_str(&self.current, &[key]); + self.current = self + .selector_filter + .collect_next_with_str(&self.current, &[key]); } ExprTerm::Json(rel, _, v) => { if v.is_empty() { @@ -599,7 +631,8 @@ impl<'a, 'b> Selector<'a, 'b> { fn visit_key(&mut self, key: &str) { if let Some(ParseToken::Array) = self.tokens.last() { - self.selector_filter.push_term(Some(ExprTerm::String(key.to_string()))); + self.selector_filter + .push_term(Some(ExprTerm::String(key.to_string()))); return; } @@ -607,10 +640,14 @@ impl<'a, 'b> Selector<'a, 'b> { if self.selector_filter.is_term_empty() { match t { ParseToken::Leaves => { - self.current = self.selector_filter.collect_all_with_str(&self.current, key) + self.current = self + .selector_filter + .collect_all_with_str(&self.current, key) } ParseToken::In => { - self.current = self.selector_filter.collect_next_with_str(&self.current, &[key.to_string()]) + self.current = self + .selector_filter + .collect_next_with_str(&self.current, &[key.to_string()]) } _ => {} } @@ -620,7 +657,8 @@ impl<'a, 'b> Selector<'a, 'b> { self.selector_filter.filter_all_with_str(&self.current, key); } ParseToken::In => { - self.selector_filter.filter_next_with_str(&self.current, key); + self.selector_filter + .filter_next_with_str(&self.current, key); } _ => {} } @@ -634,7 +672,9 @@ impl<'a, 'b> Selector<'a, 'b> { } if let Some(ParseToken::Array) = self.tokens.pop() { - self.current = self.selector_filter.collect_next_with_str(&self.current, keys); + self.current = self + .selector_filter + .collect_next_with_str(&self.current, keys); } else { unreachable!(); } @@ -772,7 +812,8 @@ impl<'a, 'b> NodeVisitor for Selector<'a, 'b> { ParseToken::Key(key) => self.visit_key(key), ParseToken::Keys(keys) => self.visit_keys(keys), ParseToken::Number(v) => { - self.selector_filter.push_term(Some(ExprTerm::Number(Number::from_f64(*v).unwrap()))); + self.selector_filter + .push_term(Some(ExprTerm::Number(Number::from_f64(*v).unwrap()))); } ParseToken::Filter(ref ft) => self.visit_filter(ft), ParseToken::Range(from, to, step) => self.visit_range(from, to, step), @@ -808,7 +849,7 @@ fn replace_value_with_tokens Result, if is_last { if let Entry::Occupied(mut e) = map.entry(token) { let v = e.insert(Value::Null); - if let Some(res) = fun(v,&tokens_clone)? { + if let Some(res) = fun(v, &tokens_clone)? { e.insert(res); } else { e.remove(); @@ -822,7 +863,7 @@ fn replace_value_with_tokens Result, if let Ok(x) = token.parse::() { if is_last { let v = std::mem::replace(&mut vec[x], Value::Null); - if let Some(res) = fun(v,&tokens_clone)? { + if let Some(res) = fun(v, &tokens_clone)? { vec[x] = res; } else { vec.remove(x); @@ -1030,9 +1071,11 @@ impl SelectorMut { Ok(self) } - pub fn replace_with_tokens Result, JsonPathError>>( + pub fn replace_with_tokens< + F: FnMut(Value, &[String]) -> Result, JsonPathError>, + >( &mut self, - fun: &mut F + fun: &mut F, ) -> Result<&mut Self, JsonPathError> { let paths = { let result = self.select()?; @@ -1049,7 +1092,6 @@ impl SelectorMut { } } - #[cfg(test)] mod select_inner_tests { use serde_json::Value; @@ -1059,7 +1101,7 @@ mod select_inner_tests { let number = 0_i64; let v: Value = serde_json::from_str(&format!("{}", number)).unwrap(); if let Value::Number(n) = v { - assert_eq!((super::to_f64(&n) - number as f64).abs() == 0_f64, true); + assert!((super::to_f64(&n) - number as f64).abs() == 0_f64); } else { panic!(); } @@ -1070,7 +1112,7 @@ mod select_inner_tests { let number = 0.1_f64; let v: Value = serde_json::from_str(&format!("{}", number)).unwrap(); if let Value::Number(n) = v { - assert_eq!((super::to_f64(&n) - number).abs() == 0_f64, true); + assert!((super::to_f64(&n) - number).abs() == 0_f64); } else { panic!(); } @@ -1081,7 +1123,7 @@ mod select_inner_tests { let number = u64::max_value(); let v: Value = serde_json::from_str(&format!("{}", number)).unwrap(); if let Value::Number(n) = v { - assert_eq!((super::to_f64(&n) - number as f64).abs() == 0_f64, true); + assert!((super::to_f64(&n) - number as f64).abs() == 0_f64); } else { panic!(); } diff --git a/src/select/value_walker.rs b/src/select/value_walker.rs index 63be27df..a56aed8a 100644 --- a/src/select/value_walker.rs +++ b/src/select/value_walker.rs @@ -5,10 +5,12 @@ pub(super) struct ValueWalker; impl<'a> ValueWalker { pub fn all_with_num(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, index: f64) { - Self::walk(vec, tmp, &|v| if v.is_array() { - v.get(index as usize).map(|item| vec![item]) - } else { - None + Self::walk(vec, tmp, &|v| { + if v.is_array() { + v.get(index as usize).map(|item| vec![item]) + } else { + None + } }); } @@ -40,13 +42,19 @@ impl<'a> ValueWalker { }); } - fn walk(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, fun: &F) where F: Fn(&Value) -> Option> { + fn walk(vec: &[&'a Value], tmp: &mut Vec<&'a Value>, fun: &F) + where + F: Fn(&Value) -> Option>, + { for v in vec { Self::_walk(v, tmp, fun); } } - fn _walk(v: &'a Value, tmp: &mut Vec<&'a Value>, fun: &F) where F: Fn(&Value) -> Option> { + fn _walk(v: &'a Value, tmp: &mut Vec<&'a Value>, fun: &F) + where + F: Fn(&Value) -> Option>, + { if let Some(mut ret) = fun(v) { tmp.append(&mut ret); } @@ -66,10 +74,12 @@ impl<'a> ValueWalker { } } - pub fn walk_dedup(v: &'a Value, - tmp: &mut Vec<&'a Value>, - key: &str, - visited: &mut HashSet<*const Value>, ) { + pub fn walk_dedup( + v: &'a Value, + tmp: &mut Vec<&'a Value>, + key: &str, + visited: &mut HashSet<*const Value>, + ) { match v { Value::Object(map) => { if map.contains_key(key) { @@ -89,4 +99,3 @@ impl<'a> ValueWalker { } } } - diff --git a/src/selector/cmp.rs b/src/selector/cmp.rs index 951cfae2..e1c6417d 100644 --- a/src/selector/cmp.rs +++ b/src/selector/cmp.rs @@ -60,7 +60,7 @@ impl Cmp for CmpNe { let mut ret = v1.to_vec(); for v in v2 { for i in 0..ret.len() { - if std::ptr::eq(*v, &*ret[i]) { + if std::ptr::eq(*v, ret[i]) { ret.remove(i); break; } @@ -209,12 +209,11 @@ impl Cmp for CmpOr { } } - #[cfg(test)] mod cmp_inner_tests { use serde_json::Value; - use selector::cmp::*; + use crate::selector::cmp::*; #[test] fn cmp_eq() { diff --git a/src/selector/mod.rs b/src/selector/mod.rs index a188668c..30aae43e 100644 --- a/src/selector/mod.rs +++ b/src/selector/mod.rs @@ -1,7 +1,7 @@ pub use self::selector_impl::{JsonSelector, JsonSelectorMut}; mod cmp; -mod terms; mod selector_impl; +mod terms; +mod utils; mod value_walker; -mod utils; \ No newline at end of file diff --git a/src/selector/selector_impl.rs b/src/selector/selector_impl.rs index 2a22c454..e31e5ee9 100644 --- a/src/selector/selector_impl.rs +++ b/src/selector/selector_impl.rs @@ -1,12 +1,12 @@ use std::collections::HashSet; use std::rc::Rc; -use serde_json::{Number, Value}; use serde_json::map::Entry; +use serde_json::{Number, Value}; -use JsonPathError; -use paths::{ParserTokenHandler, PathParser, StrRange, tokens::*}; use super::utils; +use crate::paths::{tokens::*, ParserTokenHandler, PathParser, StrRange}; +use crate::JsonPathError; use super::terms::*; @@ -111,9 +111,13 @@ impl<'a> JsonSelector<'a> { } } - fn compute_absolute_path_filter(&mut self, token: &ParseToken, parse_value_reader: &F) -> bool - where - F: Fn(&StrRange) -> &'a str + fn compute_absolute_path_filter( + &mut self, + token: &ParseToken, + parse_value_reader: &F, + ) -> bool + where + F: Fn(&StrRange) -> &'a str, { if !self.selectors.is_empty() { match token { @@ -140,7 +144,10 @@ impl<'a> JsonSelector<'a> { return false; } - self.selectors.last_mut().unwrap().handle(token, parse_value_reader); + self.selectors + .last_mut() + .unwrap() + .handle(token, parse_value_reader); true } } @@ -183,7 +190,9 @@ impl<'a> JsonSelector<'a> { if self.is_last_before_token_match(ParseToken::Array) { if let Some(Some(e)) = self.selector_filter.pop_term() { if let ExprTerm::String(key) = e { - self.current = self.selector_filter.filter_next_with_str(self.current.take(), key); + self.current = self + .selector_filter + .filter_next_with_str(self.current.take(), key); self.tokens.pop(); return; } @@ -198,12 +207,16 @@ impl<'a> JsonSelector<'a> { if let Some(Some(e)) = self.selector_filter.pop_term() { let selector_filter_consumed = match e { ExprTerm::Number(n) => { - self.current = self.selector_filter.collect_all_with_num(self.current.take(), utils::to_f64(&n)); + self.current = self + .selector_filter + .collect_all_with_num(self.current.take(), utils::to_f64(&n)); self.selector_filter.pop_term(); true } ExprTerm::String(key) => { - self.current = self.selector_filter.collect_all_with_str(self.current.take(), key); + self.current = self + .selector_filter + .collect_all_with_str(self.current.take(), key); self.selector_filter.pop_term(); true } @@ -222,10 +235,14 @@ impl<'a> JsonSelector<'a> { if let Some(Some(e)) = self.selector_filter.pop_term() { match e { ExprTerm::Number(n) => { - self.current = self.selector_filter.collect_next_with_num(self.current.take(), utils::to_f64(&n)); + self.current = self + .selector_filter + .collect_next_with_num(self.current.take(), utils::to_f64(&n)); } ExprTerm::String(key) => { - self.current = self.selector_filter.collect_next_with_str(self.current.take(), &[key]); + self.current = self + .selector_filter + .collect_next_with_str(self.current.take(), &[key]); } ExprTerm::Json(rel, _, v) => { if v.is_empty() { @@ -284,20 +301,28 @@ impl<'a> JsonSelector<'a> { if self.selector_filter.is_term_empty() { match t { ParseToken::Leaves => { - self.current = self.selector_filter.collect_all_with_str(self.current.take(), key) + self.current = self + .selector_filter + .collect_all_with_str(self.current.take(), key) } ParseToken::In => { - self.current = self.selector_filter.collect_next_with_str(self.current.take(), &[key]) + self.current = self + .selector_filter + .collect_next_with_str(self.current.take(), &[key]) } _ => {} } } else { match t { ParseToken::Leaves => { - self.current = self.selector_filter.filter_all_with_str(self.current.take(), key); + self.current = self + .selector_filter + .filter_all_with_str(self.current.take(), key); } ParseToken::In => { - self.current = self.selector_filter.filter_next_with_str(self.current.take(), key); + self.current = self + .selector_filter + .filter_next_with_str(self.current.take(), key); } _ => {} } @@ -311,7 +336,9 @@ impl<'a> JsonSelector<'a> { } if let Some(ParseToken::Array) = self.tokens.pop() { - self.current = self.selector_filter.collect_next_with_str(self.current.take(), keys); + self.current = self + .selector_filter + .collect_next_with_str(self.current.take(), keys); } else { unreachable!(); } @@ -425,8 +452,8 @@ impl<'a> JsonSelector<'a> { impl<'a> ParserTokenHandler<'a> for JsonSelector<'a> { fn handle(&mut self, token: &ParseToken, parse_value_reader: &F) - where - F: Fn(&StrRange) -> &'a str + where + F: Fn(&StrRange) -> &'a str, { debug!("token: {:?}, stack: {:?}", token, self.tokens); @@ -450,11 +477,12 @@ impl<'a> ParserTokenHandler<'a> for JsonSelector<'a> { self.visit_key(key); } ParseToken::Keys(keys) => { - let keys: Vec<&str> = keys.iter().map(|s| { parse_value_reader(s) }).collect(); + let keys: Vec<&str> = keys.iter().map(parse_value_reader).collect(); self.visit_keys(&keys) } ParseToken::Number(v) => { - self.selector_filter.push_term(Some(ExprTerm::Number(Number::from_f64(*v).unwrap()))); + self.selector_filter + .push_term(Some(ExprTerm::Number(Number::from_f64(*v).unwrap()))); } ParseToken::Filter(ref ft) => self.visit_filter(ft), ParseToken::Range(from, to, step) => self.visit_range(from, to, step), @@ -466,7 +494,7 @@ impl<'a> ParserTokenHandler<'a> for JsonSelector<'a> { } } -#[derive(Default,Clone)] +#[derive(Default, Clone)] pub struct JsonSelectorMut<'a> { value: Option, parser: Option>>, @@ -530,8 +558,8 @@ impl<'a> JsonSelectorMut<'a> { } pub fn replace_with(&mut self, fun: &mut F) -> Result<&mut Self, JsonPathError> - where - F: FnMut(Value) -> Result, JsonPathError>, + where + F: FnMut(Value) -> Result, JsonPathError>, { let result = self.select()?; let paths = self.compute_paths(result); @@ -545,9 +573,13 @@ impl<'a> JsonSelectorMut<'a> { Ok(self) } - fn replace_value(mut tokens: Vec, value: &mut Value, fun: &mut F) -> Result<(), JsonPathError> - where - F: FnMut(Value) -> Result, JsonPathError> + fn replace_value( + mut tokens: Vec, + value: &mut Value, + fun: &mut F, + ) -> Result<(), JsonPathError> + where + F: FnMut(Value) -> Result, JsonPathError>, { let mut target = value; diff --git a/src/selector/terms.rs b/src/selector/terms.rs index 6f562b3c..49e57452 100644 --- a/src/selector/terms.rs +++ b/src/selector/terms.rs @@ -11,13 +11,17 @@ pub enum ExprTerm<'a> { String(&'a str), Number(Number), Bool(bool), - Json(Option>, Option>, Vec<&'a Value>), + Json( + Option>, + Option>, + Vec<&'a Value>, + ), } impl<'a> ExprTerm<'a> { fn cmp_string(s1: &str, other: &mut ExprTerm<'a>, cmp_fn: &C) -> ExprTerm<'a> - where - C: Cmp, + where + C: Cmp, { match other { ExprTerm::String(s2) => { @@ -31,19 +35,21 @@ impl<'a> ExprTerm<'a> { } fn cmp_number(n1: &Number, other: &mut ExprTerm<'a>, cmp_fn: &C) -> ExprTerm<'a> - where - C: Cmp, + where + C: Cmp, { match other { - ExprTerm::Number(n2) => ExprTerm::Bool(cmp_fn.cmp_f64(utils::to_f64(n1), utils::to_f64(n2))), + ExprTerm::Number(n2) => { + ExprTerm::Bool(cmp_fn.cmp_f64(utils::to_f64(n1), utils::to_f64(n2))) + } ExprTerm::Json(_, _, _) => unreachable!(), _ => ExprTerm::Bool(cmp_fn.default()), } } fn cmp_bool(b1: &bool, other: &mut ExprTerm<'a>, cmp_fn: &C) -> ExprTerm<'a> - where - C: Cmp, + where + C: Cmp, { match other { ExprTerm::Bool(b2) => ExprTerm::Bool(cmp_fn.cmp_bool(*b1, *b2)), @@ -52,80 +58,95 @@ impl<'a> ExprTerm<'a> { } } - fn cmp_json_string(s2: &str, - fk1: &Option, - vec1: &[&'a Value], - cmp_fn: &C) -> Vec<&'a Value> - where - C: Cmp + fn cmp_json_string( + s2: &str, + fk1: &Option, + vec1: &[&'a Value], + cmp_fn: &C, + ) -> Vec<&'a Value> + where + C: Cmp, { let path_str = utils::to_path_str(s2); - vec1.iter().filter(|v1| match v1 { - Value::String(s1) => { - cmp_fn.cmp_string(s1, path_str.get_key()) - } - Value::Object(map1) => { - if let Some(FilterKey::String(k)) = fk1 { - if let Some(Value::String(s1)) = map1.get(*k) { - return cmp_fn.cmp_string(s1, path_str.get_key()); + vec1.iter() + .filter(|v1| match v1 { + Value::String(s1) => cmp_fn.cmp_string(s1, path_str.get_key()), + Value::Object(map1) => { + if let Some(FilterKey::String(k)) = fk1 { + if let Some(Value::String(s1)) = map1.get(*k) { + return cmp_fn.cmp_string(s1, path_str.get_key()); + } } + cmp_fn.default() } - cmp_fn.default() - } - _ => cmp_fn.default(), - }).copied().collect() - } - - fn cmp_json_number(n2: &Number, - fk1: &Option, - vec1: &[&'a Value], - cmp_fn: &C) -> Vec<&'a Value> - where - C: Cmp + _ => cmp_fn.default(), + }) + .copied() + .collect() + } + + fn cmp_json_number( + n2: &Number, + fk1: &Option, + vec1: &[&'a Value], + cmp_fn: &C, + ) -> Vec<&'a Value> + where + C: Cmp, { let n2 = utils::to_f64(n2); - vec1.iter().filter(|v1| match v1 { - Value::Number(n1) => cmp_fn.cmp_f64(utils::to_f64(n1), n2), - Value::Object(map1) => { - if let Some(FilterKey::String(k)) = fk1 { - if let Some(Value::Number(n1)) = map1.get(*k) { - return cmp_fn.cmp_f64(utils::to_f64(n1), n2); + vec1.iter() + .filter(|v1| match v1 { + Value::Number(n1) => cmp_fn.cmp_f64(utils::to_f64(n1), n2), + Value::Object(map1) => { + if let Some(FilterKey::String(k)) = fk1 { + if let Some(Value::Number(n1)) = map1.get(*k) { + return cmp_fn.cmp_f64(utils::to_f64(n1), n2); + } } + cmp_fn.default() } - cmp_fn.default() - } - _ => cmp_fn.default(), - }).copied().collect() - } - - fn cmp_json_bool(b2: &bool, - fk1: &Option, - vec1: &[&'a Value], - cmp_fn: &C1) -> Vec<&'a Value> - where - C1: Cmp + _ => cmp_fn.default(), + }) + .copied() + .collect() + } + + fn cmp_json_bool( + b2: &bool, + fk1: &Option, + vec1: &[&'a Value], + cmp_fn: &C1, + ) -> Vec<&'a Value> + where + C1: Cmp, { - vec1.iter().filter(|v1| match v1 { - Value::Bool(b1) => cmp_fn.cmp_bool(*b1, *b2), - Value::Object(map1) => { - if let Some(FilterKey::String(k)) = fk1 { - if let Some(Value::Bool(b1)) = map1.get(*k) { - return cmp_fn.cmp_bool(*b1, *b2); + vec1.iter() + .filter(|v1| match v1 { + Value::Bool(b1) => cmp_fn.cmp_bool(*b1, *b2), + Value::Object(map1) => { + if let Some(FilterKey::String(k)) = fk1 { + if let Some(Value::Bool(b1)) = map1.get(*k) { + return cmp_fn.cmp_bool(*b1, *b2); + } } + cmp_fn.default() } - cmp_fn.default() - } - _ => cmp_fn.default(), - }).copied().collect() - } - - fn cmp_json_json(rel: &Option>, - parent: &Option>, - vec1: &[&'a Value], - vec2: &[&'a Value], - cmp_fn: &C1) -> Vec<&'a Value> - where - C1: Cmp + _ => cmp_fn.default(), + }) + .copied() + .collect() + } + + fn cmp_json_json( + rel: &Option>, + parent: &Option>, + vec1: &[&'a Value], + vec2: &[&'a Value], + cmp_fn: &C1, + ) -> Vec<&'a Value> + where + C1: Cmp, { if let Some(vec1) = rel { if let Some(vec2) = parent { @@ -140,13 +161,15 @@ impl<'a> ExprTerm<'a> { } } - fn cmp_json(rel: Option>, - fk1: Option>, - vec1: &mut Vec<&'a Value>, - other: &mut ExprTerm<'a>, - cmp_fn: &C1) -> ExprTerm<'a> - where - C1: Cmp + fn cmp_json( + rel: Option>, + fk1: Option>, + vec1: &mut Vec<&'a Value>, + other: &mut ExprTerm<'a>, + cmp_fn: &C1, + ) -> ExprTerm<'a> + where + C1: Cmp, { let ret: Vec<&Value> = match other { ExprTerm::String(s2) => Self::cmp_json_string(s2, &fk1, vec1, cmp_fn), @@ -186,12 +209,11 @@ impl<'a> ExprTerm<'a> { return ExprTerm::Json(Some(Vec::new()), None, ret); } - let ret_set: HashSet<*const Value> = ret.iter() - .fold(HashSet::new(), |mut acc, v| { - let ptr = *v as *const Value; - acc.insert(ptr); - acc - }); + let ret_set: HashSet<*const Value> = ret.iter().fold(HashSet::new(), |mut acc, v| { + let ptr = *v as *const Value; + acc.insert(ptr); + acc + }); let mut tmp = Vec::new(); for rv in rel { @@ -209,9 +231,9 @@ impl<'a> ExprTerm<'a> { } fn cmp(&mut self, other: &mut Self, cmp_fn: &C1, rev_cmp_fn: &C2) -> ExprTerm<'a> - where - C1: Cmp, - C2: Cmp + where + C1: Cmp, + C2: Cmp, { if let ExprTerm::Json(_, _, _) = other { if let ExprTerm::Json(_, _, _) = &self { @@ -225,8 +247,9 @@ impl<'a> ExprTerm<'a> { ExprTerm::String(s1) => Self::cmp_string(s1, other, cmp_fn), ExprTerm::Number(n1) => Self::cmp_number(n1, other, cmp_fn), ExprTerm::Bool(b1) => Self::cmp_bool(b1, other, cmp_fn), - ExprTerm::Json(rel, fk1, vec1) => + ExprTerm::Json(rel, fk1, vec1) => { Self::cmp_json(rel.take(), fk1.take(), vec1, other, cmp_fn) + } } } @@ -310,7 +333,7 @@ pub enum FilterKey<'a> { struct FilterResult<'a> { key: FilterKey<'a>, - collected: Vec<&'a Value> + collected: Vec<&'a Value>, } #[derive(Debug, Default, Clone)] @@ -336,8 +359,8 @@ impl<'a> FilterTerms<'a> { } fn filter_json_term(&mut self, e: ExprTerm<'a>, fun: F) - where - F: Fn(&Vec<&'a Value>, &mut Option>) -> FilterResult<'a>, + where + F: Fn(&Vec<&'a Value>, &mut Option>) -> FilterResult<'a>, { debug!("filter_json_term: {:?}", e); @@ -353,25 +376,34 @@ impl<'a> FilterTerms<'a> { self.push_term(Some(ExprTerm::Json( rel, Some(filter_result.key), - filter_result.collected))); + filter_result.collected, + ))); } else { let not_matched = not_matched.unwrap(); - let filtered = vec.iter().enumerate() + let filtered = vec + .iter() + .enumerate() .filter(|(idx, _)| !not_matched.contains(idx)) - .map(|(_, v)| *v).collect(); + .map(|(_, v)| *v) + .collect(); self.push_term(Some(ExprTerm::Json( Some(filtered), Some(filter_result.key), - filter_result.collected))); + filter_result.collected, + ))); } } else { unreachable!("unexpected: ExprTerm: {:?}", e); } } - fn push_json_term(&mut self, current: Option>, fun: F) -> Option> - where - F: Fn(&Vec<&'a Value>, &mut Option>) -> FilterResult<'a>, + fn push_json_term( + &mut self, + current: Option>, + fun: F, + ) -> Option> + where + F: Fn(&Vec<&'a Value>, &mut Option>) -> FilterResult<'a>, { debug!("push_json_term: {:?}", ¤t); @@ -380,15 +412,16 @@ impl<'a> FilterTerms<'a> { self.push_term(Some(ExprTerm::Json( None, Some(filter_result.key), - filter_result.collected))); + filter_result.collected, + ))); } current } fn filter(&mut self, current: Option>, fun: F) -> Option> - where - F: Fn(&Vec<&'a Value>, &mut Option>) -> FilterResult<'a>, + where + F: Fn(&Vec<&'a Value>, &mut Option>) -> FilterResult<'a>, { let peek = self.pop_term(); @@ -403,42 +436,49 @@ impl<'a> FilterTerms<'a> { current } - pub fn filter_all_with_str(&mut self, current: Option>, key: &'a str) -> Option> { - let current = self.filter(current, |vec, _| { - FilterResult { - key: FilterKey::All, - collected: ValueWalker::all_with_str(vec, key) - } + pub fn filter_all_with_str( + &mut self, + current: Option>, + key: &'a str, + ) -> Option> { + let current = self.filter(current, |vec, _| FilterResult { + key: FilterKey::All, + collected: ValueWalker::all_with_str(vec, key), }); debug!("filter_all_with_str : {}, {:?}", key, self.0); current } - pub fn filter_next_with_str(&mut self, current: Option>, key: &'a str) -> Option> { + pub fn filter_next_with_str( + &mut self, + current: Option>, + key: &'a str, + ) -> Option> { let current = self.filter(current, |vec, not_matched| { let mut visited = HashSet::new(); let mut acc = Vec::new(); let path_key = &utils::to_path_str(key); - ValueWalker::walk_dedup_all(vec, - path_key.get_key(), - &mut visited, - &mut |v| { - acc.push(v); - }, - &mut |idx| { - if let Some(set) = not_matched { - set.insert(idx); - } - }, - 0 + ValueWalker::walk_dedup_all( + vec, + path_key.get_key(), + &mut visited, + &mut |v| { + acc.push(v); + }, + &mut |idx| { + if let Some(set) = not_matched { + set.insert(idx); + } + }, + 0, ); FilterResult { key: FilterKey::String(path_key.get_origin_key()), - collected: acc + collected: acc, } }); @@ -446,7 +486,11 @@ impl<'a> FilterTerms<'a> { current } - pub fn collect_next_with_num(&mut self, current: Option>, index: f64) -> Option> { + pub fn collect_next_with_num( + &mut self, + current: Option>, + index: f64, + ) -> Option> { if current.is_none() { debug!("collect_next_with_num : {:?}, {:?}", &index, ¤t); return current; @@ -482,12 +526,13 @@ impl<'a> FilterTerms<'a> { Some(acc) } - pub fn collect_next_with_str(&mut self, current: Option>, keys: &[&'a str]) -> Option> { + pub fn collect_next_with_str( + &mut self, + current: Option>, + keys: &[&'a str], + ) -> Option> { if current.is_none() { - debug!( - "collect_next_with_str : {:?}, {:?}", - keys, ¤t - ); + debug!("collect_next_with_str : {:?}, {:?}", keys, ¤t); return current; } @@ -518,7 +563,11 @@ impl<'a> FilterTerms<'a> { Some(ValueWalker::all(current.as_ref().unwrap())) } - pub fn collect_all_with_str(&mut self, current: Option>, key: &'a str) -> Option> { + pub fn collect_all_with_str( + &mut self, + current: Option>, + key: &'a str, + ) -> Option> { if current.is_none() { debug!("collect_all_with_str: {}, {:?}", key, ¤t); return current; @@ -528,7 +577,11 @@ impl<'a> FilterTerms<'a> { Some(ret) } - pub fn collect_all_with_num(&mut self, mut current: Option>, index: f64) -> Option> { + pub fn collect_all_with_num( + &mut self, + mut current: Option>, + index: f64, + ) -> Option> { if let Some(current) = current.take() { let ret = ValueWalker::all_with_num(¤t, index); if !ret.is_empty() { @@ -545,7 +598,7 @@ impl<'a> FilterTerms<'a> { mod expr_term_inner_tests { use serde_json::{Number, Value}; - use selector::terms::ExprTerm; + use crate::selector::terms::ExprTerm; #[test] fn value_vec_into() { diff --git a/src/selector/utils.rs b/src/selector/utils.rs index ec250625..9c224027 100644 --- a/src/selector/utils.rs +++ b/src/selector/utils.rs @@ -20,7 +20,7 @@ pub fn abs_index(n: isize, len: usize) -> usize { pub struct PathKey<'a> { key: &'a str, - special_key: Option + special_key: Option, } impl<'a: 'b, 'b> PathKey<'a> { @@ -40,7 +40,7 @@ impl<'a: 'b, 'b> PathKey<'a> { pub fn to_path_str(key: &str) -> PathKey { let mut path_key = PathKey { key, - special_key: None + special_key: None, }; if key.starts_with('\'') || key.starts_with('"') { @@ -51,4 +51,4 @@ pub fn to_path_str(key: &str) -> PathKey { } } path_key -} \ No newline at end of file +} diff --git a/src/selector/value_walker.rs b/src/selector/value_walker.rs index 2c7c1039..a78409dd 100644 --- a/src/selector/value_walker.rs +++ b/src/selector/value_walker.rs @@ -1,8 +1,8 @@ use std::collections::HashSet; -use serde_json::Value; use super::utils; -use selector::utils::PathKey; +use crate::selector::utils::PathKey; +use serde_json::Value; pub(super) struct ValueWalker; @@ -52,19 +52,23 @@ impl<'a> ValueWalker { pub fn all_with_str(vec: &[&'a Value], key: &'a str) -> Vec<&'a Value> { let path_key = utils::to_path_str(key); - Self::walk(vec, &|v, acc| if let Value::Object(map) = v { - if let Some(v) = map.get(path_key.get_key()) { - acc.push(v); + Self::walk(vec, &|v, acc| { + if let Value::Object(map) = v { + if let Some(v) = map.get(path_key.get_key()) { + acc.push(v); + } } }) } pub fn all_with_strs(vec: &[&'a Value], keys: &[&'a str]) -> Vec<&'a Value> { - let path_keys: &Vec = &keys.iter().map(|key| { utils::to_path_str(key) }).collect(); + let path_keys: &Vec = &keys.iter().map(|key| utils::to_path_str(key)).collect(); vec.iter().fold(Vec::new(), |mut acc, v| { if let Value::Object(map) = v { - path_keys.iter().for_each(|pk| if let Some(v) = map.get(pk.get_key()) { - acc.push(v) + path_keys.iter().for_each(|pk| { + if let Some(v) = map.get(pk.get_key()) { + acc.push(v) + } }); } acc @@ -72,20 +76,18 @@ impl<'a> ValueWalker { } pub fn all(vec: &[&'a Value]) -> Vec<&'a Value> { - Self::walk(vec, &|v, acc| { - match v { - Value::Array(ay) => acc.extend(ay), - Value::Object(map) => { - acc.extend(map.values()); - } - _ => {} + Self::walk(vec, &|v, acc| match v { + Value::Array(ay) => acc.extend(ay), + Value::Object(map) => { + acc.extend(map.values()); } + _ => {} }) } fn walk(vec: &[&'a Value], fun: &F) -> Vec<&'a Value> - where - F: Fn(&'a Value, &mut Vec<&'a Value>), + where + F: Fn(&'a Value, &mut Vec<&'a Value>), { vec.iter().fold(Vec::new(), |mut acc, v| { Self::_walk(v, &mut acc, fun); @@ -94,8 +96,8 @@ impl<'a> ValueWalker { } fn _walk(v: &'a Value, acc: &mut Vec<&'a Value>, fun: &F) - where - F: Fn(&'a Value, &mut Vec<&'a Value>), + where + F: Fn(&'a Value, &mut Vec<&'a Value>), { fun(v, acc); @@ -104,41 +106,39 @@ impl<'a> ValueWalker { vec.iter().for_each(|v| Self::_walk(v, acc, fun)); } Value::Object(map) => { - map.values().into_iter().for_each(|v| Self::_walk(v, acc, fun)); + map.values().for_each(|v| Self::_walk(v, acc, fun)); } _ => {} } } - pub fn walk_dedup_all(vec: &[&'a Value], - key: &str, - visited: &mut HashSet<*const Value>, - is_contain: &mut F1, - is_not_contain: &mut F2, - depth: usize) - where - F1: FnMut(&'a Value), - F2: FnMut(usize), + pub fn walk_dedup_all( + vec: &[&'a Value], + key: &str, + visited: &mut HashSet<*const Value>, + is_contain: &mut F1, + is_not_contain: &mut F2, + depth: usize, + ) where + F1: FnMut(&'a Value), + F2: FnMut(usize), { - vec.iter().enumerate().for_each(|(index, v)| Self::walk_dedup(v, - key, - visited, - index, - is_contain, - is_not_contain, - depth)); + vec.iter().enumerate().for_each(|(index, v)| { + Self::walk_dedup(v, key, visited, index, is_contain, is_not_contain, depth) + }); } - fn walk_dedup(v: &'a Value, - key: &str, - visited: &mut HashSet<*const Value>, - index: usize, - is_contain: &mut F1, - is_not_contain: &mut F2, - depth: usize) - where - F1: FnMut(&'a Value), - F2: FnMut(usize), + fn walk_dedup( + v: &'a Value, + key: &str, + visited: &mut HashSet<*const Value>, + index: usize, + is_contain: &mut F1, + is_not_contain: &mut F2, + depth: usize, + ) where + F1: FnMut(&'a Value), + F2: FnMut(usize), { let ptr = v as *const Value; if visited.contains(&ptr) { @@ -162,7 +162,15 @@ impl<'a> ValueWalker { is_not_contain(index); } vec.iter().for_each(|v| { - Self::walk_dedup(v, key, visited, index, is_contain, is_not_contain, depth + 1); + Self::walk_dedup( + v, + key, + visited, + index, + is_contain, + is_not_contain, + depth + 1, + ); }) } _ => { @@ -173,4 +181,3 @@ impl<'a> ValueWalker { } } } - diff --git a/tests/array_filter.rs b/tests/array_filter.rs index 7f1cf332..41ffa2c7 100644 --- a/tests/array_filter.rs +++ b/tests/array_filter.rs @@ -1,7 +1,7 @@ #[macro_use] extern crate serde_json; -use common::{read_json, select_and_then_compare, setup}; +use crate::common::{read_json, select_and_then_compare, setup}; mod common; @@ -256,9 +256,5 @@ fn bugs40_bracket_notation_after_recursive_descent() { fn bugs50() { setup(); - select_and_then_compare( - "$[0]", - json!({"f": [1,2,3]}), - json!([]) - ); -} \ No newline at end of file + select_and_then_compare("$[0]", json!({"f": [1,2,3]}), json!([])); +} diff --git a/tests/filter.rs b/tests/filter.rs index c847dab3..069d8113 100644 --- a/tests/filter.rs +++ b/tests/filter.rs @@ -1,7 +1,7 @@ #[macro_use] extern crate serde_json; -use common::{read_json, select_and_then_compare, setup}; +use crate::common::{read_json, select_and_then_compare, setup}; mod common; @@ -10,7 +10,7 @@ fn quote() { setup(); select_and_then_compare( - r#"$['single\'quote']"#, + r"$['single\'quote']", json!({"single'quote":"value"}), json!(["value"]), ); @@ -133,11 +133,11 @@ fn filter_parent_paths() { select_and_then_compare( "$[?(@.key.subKey == 'subKey2')]", json!([ - {"key": {"seq": 1, "subKey": "subKey1"}}, - {"key": {"seq": 2, "subKey": "subKey2"}}, - {"key": 42}, - {"some": "value"} - ]), + {"key": {"seq": 1, "subKey": "subKey1"}}, + {"key": {"seq": 2, "subKey": "subKey2"}}, + {"key": 42}, + {"some": "value"} + ]), json!([{"key": {"seq": 2, "subKey": "subKey2"}}]), ); } @@ -149,15 +149,15 @@ fn bugs33_exist_in_all() { select_and_then_compare( "$..[?(@.first.second)]", json!({ - "foo": { - "first": { "second": "value" } - }, - "foo2": { - "first": {} - }, - "foo3": { - } - }), + "foo": { + "first": { "second": "value" } + }, + "foo2": { + "first": {} + }, + "foo3": { + } + }), json!([ { "first": { @@ -175,15 +175,15 @@ fn bugs33_exist_left_in_all_with_and_condition() { select_and_then_compare( "$..[?(@.first && @.first.second)]", json!({ - "foo": { - "first": { "second": "value" } - }, - "foo2": { - "first": {} - }, - "foo3": { - } - }), + "foo": { + "first": { "second": "value" } + }, + "foo2": { + "first": {} + }, + "foo3": { + } + }), json!([ { "first": { @@ -232,49 +232,49 @@ fn bugs38_array_notation_in_filter() { select_and_then_compare( "$[?(@['key']==42)]", json!([ - {"key": 0}, - {"key": 42}, - {"key": -1}, - {"key": 41}, - {"key": 43}, - {"key": 42.0001}, - {"key": 41.9999}, - {"key": 100}, - {"some": "value"} - ]), + {"key": 0}, + {"key": 42}, + {"key": -1}, + {"key": 41}, + {"key": 43}, + {"key": 42.0001}, + {"key": 41.9999}, + {"key": 100}, + {"some": "value"} + ]), json!([{"key": 42}]), ); select_and_then_compare( "$[?(@['key'].subKey == 'subKey2')]", json!([ - {"key": {"seq": 1, "subKey": "subKey1"}}, - {"key": {"seq": 2, "subKey": "subKey2"}}, - {"key": 42}, - {"some": "value"} - ]), + {"key": {"seq": 1, "subKey": "subKey1"}}, + {"key": {"seq": 2, "subKey": "subKey2"}}, + {"key": 42}, + {"some": "value"} + ]), json!([{"key": {"seq": 2, "subKey": "subKey2"}}]), ); select_and_then_compare( "$[?(@['key']['subKey'] == 'subKey2')]", json!([ - {"key": {"seq": 1, "subKey": "subKey1"}}, - {"key": {"seq": 2, "subKey": "subKey2"}}, - {"key": 42}, - {"some": "value"} - ]), + {"key": {"seq": 1, "subKey": "subKey1"}}, + {"key": {"seq": 2, "subKey": "subKey2"}}, + {"key": 42}, + {"some": "value"} + ]), json!([{"key": {"seq": 2, "subKey": "subKey2"}}]), ); select_and_then_compare( "$..key[?(@['subKey'] == 'subKey2')]", json!([ - {"key": {"seq": 1, "subKey": "subKey1"}}, - {"key": {"seq": 2, "subKey": "subKey2"}}, - {"key": 42}, - {"some": "value"} - ]), + {"key": {"seq": 1, "subKey": "subKey1"}}, + {"key": {"seq": 2, "subKey": "subKey2"}}, + {"key": 42}, + {"some": "value"} + ]), json!([{"seq": 2, "subKey": "subKey2"}]), ); -} \ No newline at end of file +} diff --git a/tests/jsonpath_examples.rs b/tests/jsonpath_examples.rs index 35e84a3d..f17c027c 100644 --- a/tests/jsonpath_examples.rs +++ b/tests/jsonpath_examples.rs @@ -1,7 +1,7 @@ #[macro_use] extern crate serde_json; -use common::{read_json, select_and_then_compare, setup}; +use crate::common::{read_json, select_and_then_compare, setup}; mod common; diff --git a/tests/lib.rs b/tests/lib.rs index d2c48cb2..c0dc5418 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -6,8 +6,8 @@ extern crate serde_json; use serde::Deserialize; use serde_json::Value; -use common::{compare_result, read_contents, read_json, setup}; -use jsonpath::JsonPathError; +use crate::common::{compare_result, read_contents, read_json, setup}; +use crate::jsonpath::JsonPathError; mod common; diff --git a/tests/op.rs b/tests/op.rs index 35089d8d..d328a182 100644 --- a/tests/op.rs +++ b/tests/op.rs @@ -1,7 +1,7 @@ #[macro_use] extern crate serde_json; -use common::{read_json, select_and_then_compare, setup}; +use crate::common::{read_json, select_and_then_compare, setup}; mod common; @@ -174,14 +174,14 @@ fn op_ge_for_number() { select_and_then_compare("$.[?(@.a >= 0)]", json!({ "a": 1 }), json!([{ "a": 1 }])); } - - #[test] fn op_eq_for_string_value() { setup(); select_and_then_compare( - r#"$.[?(@.a == "b")]"#, json!({ "a": "b" }), json!([{ "a": "b" }]), + r#"$.[?(@.a == "b")]"#, + json!({ "a": "b" }), + json!([{ "a": "b" }]), ); } @@ -190,18 +190,17 @@ fn op_ne_for_string_value() { setup(); select_and_then_compare( - r#"$.[?(@.a != "c")]"#, json!({ "a": "b" }), json!([{ "a": "b" }]), + r#"$.[?(@.a != "c")]"#, + json!({ "a": "b" }), + json!([{ "a": "b" }]), ); - } #[test] fn op_lt_for_string_value() { setup(); - select_and_then_compare( - r#"$.[?(@.a < "b")]"#, json!({ "a": "b" }), json!([]), - ); + select_and_then_compare(r#"$.[?(@.a < "b")]"#, json!({ "a": "b" }), json!([])); } #[test] @@ -209,7 +208,9 @@ fn op_le_for_string_value() { setup(); select_and_then_compare( - r#"$.[?(@.a <= "b")]"#, json!({ "a": "b" }), json!([{ "a": "b" }]), + r#"$.[?(@.a <= "b")]"#, + json!({ "a": "b" }), + json!([{ "a": "b" }]), ); } @@ -217,9 +218,7 @@ fn op_le_for_string_value() { fn op_gt_for_string_value() { setup(); - select_and_then_compare( - r#"$.[?(@.a > "b")]"#, json!({ "a": "b" }), json!([]), - ); + select_and_then_compare(r#"$.[?(@.a > "b")]"#, json!({ "a": "b" }), json!([])); } #[test] @@ -227,7 +226,9 @@ fn op_ge_for_string_value() { setup(); select_and_then_compare( - r#"$.[?(@.a >= "b")]"#, json!({ "a": "b" }), json!([{ "a": "b" }]), + r#"$.[?(@.a >= "b")]"#, + json!({ "a": "b" }), + json!([{ "a": "b" }]), ); } @@ -314,21 +315,21 @@ fn cmp_json_rel() { } }), json!([ - { - "a" : { - "a" : [ - true, - "1" - ] - }, - "b" : { - "a" : [ - true, - "1" - ] - } - } - ]) + { + "a" : { + "a" : [ + true, + "1" + ] + }, + "b" : { + "a" : [ + true, + "1" + ] + } + } + ]), ) } @@ -380,11 +381,7 @@ fn op_ge_for_object_value() { fn op_eq_for_complex_value() { setup(); - select_and_then_compare( - r#"$.[?(1 == @.a)]"#, - json!({ "a": { "b": 1 } }), - json!([]), - ); + select_and_then_compare(r#"$.[?(1 == @.a)]"#, json!({ "a": { "b": 1 } }), json!([])); } #[test] @@ -403,7 +400,7 @@ fn op_ne_for_complex_value() { "b" : 1 } } - ]) + ]), ); } @@ -411,22 +408,14 @@ fn op_ne_for_complex_value() { fn op_le_for_complex_value() { setup(); - select_and_then_compare( - r#"$.[?(@.a <= 1)]"#, - json!({ "a": { "b": 1 } }), - json!([]), - ); + select_and_then_compare(r#"$.[?(@.a <= 1)]"#, json!({ "a": { "b": 1 } }), json!([])); } #[test] fn op_gt_for_complex_value() { setup(); - select_and_then_compare( - r#"$.[?(@.a > "1")]"#, - json!({ "a": { "b": 1 } }), - json!([]), - ); + select_and_then_compare(r#"$.[?(@.a > "1")]"#, json!({ "a": { "b": 1 } }), json!([])); } #[test] @@ -439,7 +428,7 @@ fn op_compare_different_types() { r#"$[?(true == 1)]"#, r#"$[?(@ == 1)]"#, ] - .iter() + .iter() { select_and_then_compare(path, json!({}), json!([])); } @@ -461,4 +450,4 @@ fn op_for_same_type() { {"a": 1} ]), ); -} \ No newline at end of file +} diff --git a/tests/paths.rs b/tests/paths.rs index 61da575c..7dbb51bf 100644 --- a/tests/paths.rs +++ b/tests/paths.rs @@ -1,7 +1,7 @@ #[macro_use] extern crate serde_json; -use common::{select_and_then_compare, setup}; +use crate::common::{select_and_then_compare, setup}; mod common; @@ -12,104 +12,104 @@ fn dolla_token_in_path() { select_and_then_compare( "$..$ref", json!({ - "Junk1": "This is a test to illustrate use of '$' in the attr for the expression $..['$ref'] ", - "$ref": "Match Root", - "Subset1":[ - {"Junk2": "Data...", - "$ref": "Match Subset1" - } - ], - "hierachy1":{ - "hierachy2.1":{ - "hierachy2.1.1":{ "$ref":"Match 2.1.1"}, - "hierachy2.1.2":{ "ref":"Match 2.1.2"}, - "hierachy2.1.3":{ "ref":"No Match 2.1.3"}, - "hierachy2.1.4":{ "$ref":"Match 2.1.4"}, - "hierachy2.1.5":{ "ref":"No Match 2.1.5"} - }, - "hierachy2.2":{ - "hierachy2.2.1":{ "ref":"No Match 2.2.1"}, - "hierachy2.2.2":{ "$ref":"Match 2.2.2"}, - "hierachy2.2.3":{ "ref":"No Match 2.2.3"}, - "hierachy2.2.4":{ "ref":"No Match 2.2.5"}, - "hierachy2.2.5":{ "$ref":"Match 2.2.5"} - }, - "hierachy2.3":{ - "hierachy2.3.1":{ "ref":"No Match 2.3.1"}, - "hierachy2.3.2":{ "ref":"No Match 2.3.2"}, - "hierachy2.3.3":{ "ref":"No Match 2.3.3"}, - "hierachy2.3.4":{ "ref":"No Match 2.3.4"}, - "hierachy2.3.5":{ "ref":"No Match 2.3.5"}, - "hierachy2.3.6":{ - "hierachy2.3.6.1":{ "$ref":"Match 2.3.6.1"}, - "hierachy2.3.6.2":{ "ref":"No Match 2.3.6.2"}, - "hierachy2.3.6.3":{ "ref":"No Match 2.3.6.3"}, - "hierachy2.3.6.4":{ "ref":"No Match 2.3.6.4"}, - "hierachy2.3.6.5":{ "ref":"No Match 2.3.6.5"} - } - } + "Junk1": "This is a test to illustrate use of '$' in the attr for the expression $..['$ref'] ", + "$ref": "Match Root", + "Subset1":[ + {"Junk2": "Data...", + "$ref": "Match Subset1" } - }), + ], + "hierachy1":{ + "hierachy2.1":{ + "hierachy2.1.1":{ "$ref":"Match 2.1.1"}, + "hierachy2.1.2":{ "ref":"Match 2.1.2"}, + "hierachy2.1.3":{ "ref":"No Match 2.1.3"}, + "hierachy2.1.4":{ "$ref":"Match 2.1.4"}, + "hierachy2.1.5":{ "ref":"No Match 2.1.5"} + }, + "hierachy2.2":{ + "hierachy2.2.1":{ "ref":"No Match 2.2.1"}, + "hierachy2.2.2":{ "$ref":"Match 2.2.2"}, + "hierachy2.2.3":{ "ref":"No Match 2.2.3"}, + "hierachy2.2.4":{ "ref":"No Match 2.2.5"}, + "hierachy2.2.5":{ "$ref":"Match 2.2.5"} + }, + "hierachy2.3":{ + "hierachy2.3.1":{ "ref":"No Match 2.3.1"}, + "hierachy2.3.2":{ "ref":"No Match 2.3.2"}, + "hierachy2.3.3":{ "ref":"No Match 2.3.3"}, + "hierachy2.3.4":{ "ref":"No Match 2.3.4"}, + "hierachy2.3.5":{ "ref":"No Match 2.3.5"}, + "hierachy2.3.6":{ + "hierachy2.3.6.1":{ "$ref":"Match 2.3.6.1"}, + "hierachy2.3.6.2":{ "ref":"No Match 2.3.6.2"}, + "hierachy2.3.6.3":{ "ref":"No Match 2.3.6.3"}, + "hierachy2.3.6.4":{ "ref":"No Match 2.3.6.4"}, + "hierachy2.3.6.5":{ "ref":"No Match 2.3.6.5"} + } + } + } + }), json!([ - "Match Root", - "Match Subset1", - "Match 2.1.1", - "Match 2.1.4", - "Match 2.2.2", - "Match 2.2.5", - "Match 2.3.6.1" + "Match Root", + "Match Subset1", + "Match 2.1.1", + "Match 2.1.4", + "Match 2.2.2", + "Match 2.2.5", + "Match 2.3.6.1" ]), ); select_and_then_compare( "$..['$ref']", json!({ - "Junk1": "This is a test to illustrate use of '$' in the attr for the expression $..['$ref'] ", - "$ref": "Match Root", - "Subset1":[ - {"Junk2": "Data...", - "$ref": "Match Subset1" - } - ], - "hierachy1":{ - "hierachy2.1":{ - "hierachy2.1.1":{ "$ref":"Match 2.1.1"}, - "hierachy2.1.2":{ "ref":"Match 2.1.2"}, - "hierachy2.1.3":{ "ref":"No Match 2.1.3"}, - "hierachy2.1.4":{ "$ref":"Match 2.1.4"}, - "hierachy2.1.5":{ "ref":"No Match 2.1.5"} - }, - "hierachy2.2":{ - "hierachy2.2.1":{ "ref":"No Match 2.2.1"}, - "hierachy2.2.2":{ "$ref":"Match 2.2.2"}, - "hierachy2.2.3":{ "ref":"No Match 2.2.3"}, - "hierachy2.2.4":{ "ref":"No Match 2.2.5"}, - "hierachy2.2.5":{ "$ref":"Match 2.2.5"} - }, - "hierachy2.3":{ - "hierachy2.3.1":{ "ref":"No Match 2.3.1"}, - "hierachy2.3.2":{ "ref":"No Match 2.3.2"}, - "hierachy2.3.3":{ "ref":"No Match 2.3.3"}, - "hierachy2.3.4":{ "ref":"No Match 2.3.4"}, - "hierachy2.3.5":{ "ref":"No Match 2.3.5"}, - "hierachy2.3.6":{ - "hierachy2.3.6.1":{ "$ref":"Match 2.3.6.1"}, - "hierachy2.3.6.2":{ "ref":"No Match 2.3.6.2"}, - "hierachy2.3.6.3":{ "ref":"No Match 2.3.6.3"}, - "hierachy2.3.6.4":{ "ref":"No Match 2.3.6.4"}, - "hierachy2.3.6.5":{ "ref":"No Match 2.3.6.5"} - } - } + "Junk1": "This is a test to illustrate use of '$' in the attr for the expression $..['$ref'] ", + "$ref": "Match Root", + "Subset1":[ + {"Junk2": "Data...", + "$ref": "Match Subset1" } - }), + ], + "hierachy1":{ + "hierachy2.1":{ + "hierachy2.1.1":{ "$ref":"Match 2.1.1"}, + "hierachy2.1.2":{ "ref":"Match 2.1.2"}, + "hierachy2.1.3":{ "ref":"No Match 2.1.3"}, + "hierachy2.1.4":{ "$ref":"Match 2.1.4"}, + "hierachy2.1.5":{ "ref":"No Match 2.1.5"} + }, + "hierachy2.2":{ + "hierachy2.2.1":{ "ref":"No Match 2.2.1"}, + "hierachy2.2.2":{ "$ref":"Match 2.2.2"}, + "hierachy2.2.3":{ "ref":"No Match 2.2.3"}, + "hierachy2.2.4":{ "ref":"No Match 2.2.5"}, + "hierachy2.2.5":{ "$ref":"Match 2.2.5"} + }, + "hierachy2.3":{ + "hierachy2.3.1":{ "ref":"No Match 2.3.1"}, + "hierachy2.3.2":{ "ref":"No Match 2.3.2"}, + "hierachy2.3.3":{ "ref":"No Match 2.3.3"}, + "hierachy2.3.4":{ "ref":"No Match 2.3.4"}, + "hierachy2.3.5":{ "ref":"No Match 2.3.5"}, + "hierachy2.3.6":{ + "hierachy2.3.6.1":{ "$ref":"Match 2.3.6.1"}, + "hierachy2.3.6.2":{ "ref":"No Match 2.3.6.2"}, + "hierachy2.3.6.3":{ "ref":"No Match 2.3.6.3"}, + "hierachy2.3.6.4":{ "ref":"No Match 2.3.6.4"}, + "hierachy2.3.6.5":{ "ref":"No Match 2.3.6.5"} + } + } + } + }), json!([ - "Match Root", - "Match Subset1", - "Match 2.1.1", - "Match 2.1.4", - "Match 2.2.2", - "Match 2.2.5", - "Match 2.3.6.1" + "Match Root", + "Match Subset1", + "Match 2.1.1", + "Match 2.1.4", + "Match 2.2.2", + "Match 2.2.5", + "Match 2.3.6.1" ]), ); -} \ No newline at end of file +} diff --git a/tests/precompile.rs b/tests/precompile.rs index 6793a12b..be4668b0 100644 --- a/tests/precompile.rs +++ b/tests/precompile.rs @@ -2,7 +2,7 @@ extern crate serde_json; extern crate jsonpath_lib; -use common::{setup}; +use crate::common::setup; use jsonpath_lib::PathCompiled; use serde_json::Value; @@ -27,8 +27,14 @@ fn precompile_test() { // re-use //let result = compiled(&json).unwrap(); - assert_eq!(compiled.select(&json).unwrap().clone(), vec![&Value::String("baz".into())]); - assert_eq!(compiled.select(&json).unwrap().clone(), vec![&Value::String("baz".into())]); + assert_eq!( + compiled.select(&json).unwrap().clone(), + vec![&Value::String("baz".into())] + ); + assert_eq!( + compiled.select(&json).unwrap().clone(), + vec![&Value::String("baz".into())] + ); } #[test] @@ -38,4 +44,4 @@ fn precompile_failure() { let compiled = PathCompiled::compile(""); assert!(compiled.is_err()); -} \ No newline at end of file +} diff --git a/tests/readme.rs b/tests/readme.rs index b8b6db8d..26798d2d 100644 --- a/tests/readme.rs +++ b/tests/readme.rs @@ -6,7 +6,7 @@ extern crate serde_json; use serde::Deserialize; use serde_json::Value; -use jsonpath::{JsonSelector, JsonSelectorMut, PathParser}; +use crate::jsonpath::{JsonSelector, JsonSelectorMut, PathParser}; mod common; @@ -176,9 +176,7 @@ fn readme_selector() { let parser = PathParser::compile("$..[?(@.age >= 30)]").unwrap(); let mut selector = JsonSelector::new(parser); - let result = selector.value(&json_obj) - .select() - .unwrap(); + let result = selector.value(&json_obj).select().unwrap(); assert_eq!(vec![&json!({"name": "친구3", "age": 30})], result); @@ -212,7 +210,8 @@ fn readme_selector_mut() { let parser = PathParser::compile("$..[?(@.age == 20)].age").unwrap(); let mut selector_mut = JsonSelectorMut::new(parser); - let result = selector_mut.value(json_obj) + let result = selector_mut + .value(json_obj) .replace_with(&mut |v| { let age = if let Value::Number(n) = v { n.as_u64().unwrap() * 2 @@ -286,7 +285,7 @@ fn readme_select_as_str() { "#, "$..friends[0]", ) - .unwrap(); + .unwrap(); assert_eq!( ret, @@ -317,7 +316,7 @@ fn readme_select_as() { }"#, "$.person", ) - .unwrap(); + .unwrap(); let person = Person { name: "Doe John".to_string(), @@ -520,7 +519,7 @@ fn readme_replace_with() { Ok(Some(json!(age))) }) - .unwrap(); + .unwrap(); assert_eq!( result, diff --git a/tests/return_type.rs b/tests/return_type.rs index 0139dda0..0fca344e 100644 --- a/tests/return_type.rs +++ b/tests/return_type.rs @@ -1,7 +1,7 @@ #[macro_use] extern crate serde_json; -use common::{read_json, select_and_then_compare, setup}; +use crate::common::{read_json, select_and_then_compare, setup}; mod common; @@ -100,9 +100,5 @@ fn return_type_for_array_filter_true() { fn return_type_empty() { setup(); - select_and_then_compare( - "$[?(@.key==43)]", - json!([{"key": 42}]), - json!([]), - ); -} \ No newline at end of file + select_and_then_compare("$[?(@.key==43)]", json!([{"key": 42}]), json!([])); +} diff --git a/tests/selector.rs b/tests/selector.rs index 770501be..091f9d62 100644 --- a/tests/selector.rs +++ b/tests/selector.rs @@ -2,10 +2,10 @@ extern crate jsonpath_lib as jsonpath; #[macro_use] extern crate serde_json; -use common::{read_json, setup}; -use jsonpath::{Parser, Selector, SelectorMut, JsonPathError}; +use crate::common::{read_json, setup}; +use crate::jsonpath::{JsonPathError, Parser, Selector, SelectorMut}; +use crate::jsonpath::{JsonSelector, JsonSelectorMut, PathParser}; use serde_json::Value; -use jsonpath::{PathParser, JsonSelector, JsonSelectorMut}; mod common; @@ -17,7 +17,8 @@ fn selector_mut() { let mut selector_mut = JsonSelectorMut::new(parser); let mut nums = Vec::new(); - let result = selector_mut.value(read_json("./benchmark/example.json")) + let result = selector_mut + .value(read_json("./benchmark/example.json")) .replace_with(&mut |v| { if let Value::Number(n) = v { nums.push(n.as_f64().unwrap()); @@ -35,9 +36,7 @@ fn selector_mut() { let parser = PathParser::compile("$.store..price").unwrap(); let mut selector = JsonSelector::new(parser); - let result = selector.value(&result) - .select() - .unwrap(); + let result = selector.value(&result).select().unwrap(); assert_eq!( vec![ @@ -60,14 +59,9 @@ fn selector_mut_err() { .str_path(r#"$.store..price"#) .unwrap() .value(read_json("./benchmark/example.json")) - .replace_with(&mut |_| { - Err(JsonPathError::EmptyValue) - }); + .replace_with(&mut |_| Err(JsonPathError::EmptyValue)); - assert_eq!( - result.is_err(), - true - ); + assert!(result.is_err()); } #[test] @@ -78,14 +72,9 @@ fn jsonselector_mut_err() { let mut selector_mut = JsonSelectorMut::new(parser); let result = selector_mut .value(read_json("./benchmark/example.json")) - .replace_with(&mut |_| { - Err(JsonPathError::EmptyValue) - }); + .replace_with(&mut |_| Err(JsonPathError::EmptyValue)); - assert_eq!( - result.is_err(), - true - ); + assert!(result.is_err()); } #[test] @@ -102,7 +91,8 @@ fn selector_delete_multi_elements_from_array() { let parser = PathParser::compile("$[0,2]").unwrap(); let mut selector_mut = JsonSelectorMut::new(parser); - let result = selector_mut.value(serde_json::from_str("[1,2,3]").unwrap()) + let result = selector_mut + .value(serde_json::from_str("[1,2,3]").unwrap()) .remove() .unwrap() .take() @@ -121,7 +111,8 @@ fn selector_delete() { let parser = PathParser::compile("$.store..price[?(@>13)]").unwrap(); let mut selector_mut = JsonSelectorMut::new(parser); - let result = selector_mut.value(read_json("./benchmark/example.json")) + let result = selector_mut + .value(read_json("./benchmark/example.json")) .delete() .unwrap() .take() @@ -129,9 +120,7 @@ fn selector_delete() { let parser = PathParser::compile("$.store..price").unwrap(); let mut selector = JsonSelector::new(parser); - let result = selector.value(&result) - .select() - .unwrap(); + let result = selector.value(&result).select().unwrap(); assert_eq!( result, @@ -151,7 +140,8 @@ fn selector_remove() { let parser = PathParser::compile("$.store..price[?(@>13)]").unwrap(); let mut selector_mut = JsonSelectorMut::new(parser); - let result = selector_mut.value(read_json("./benchmark/example.json")) + let result = selector_mut + .value(read_json("./benchmark/example.json")) .remove() .unwrap() .take() @@ -159,16 +149,7 @@ fn selector_remove() { let parser = PathParser::compile("$.store..price").unwrap(); let mut selector = JsonSelector::new(parser); - let result = selector.value(&result) - .select() - .unwrap(); + let result = selector.value(&result).select().unwrap(); - assert_eq!( - result, - vec![ - &json!(8.95), - &json!(12.99), - &json!(8.99) - ] - ); + assert_eq!(result, vec![&json!(8.95), &json!(12.99), &json!(8.99)]); }