serde_json::Value clone 제거

This commit is contained in:
freestrings 2019-03-11 17:35:15 +09:00
parent ba57ae0ea5
commit 1a3104c5db
30 changed files with 1333 additions and 672 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "jsonpath_lib" name = "jsonpath_lib"
version = "0.1.2" version = "0.1.3"
authors = ["Changseok Han <freestrings@gmail.com>"] authors = ["Changseok Han <freestrings@gmail.com>"]
description = "JsonPath in Rust and Webassembly - Webassembly Demo: https://freestrings.github.io/jsonpath" description = "JsonPath in Rust and Webassembly - Webassembly Demo: https://freestrings.github.io/jsonpath"
@ -27,4 +27,8 @@ bencher = "0.1.5"
[lib] [lib]
name = "jsonpath_lib" name = "jsonpath_lib"
path = "src/lib.rs" path = "src/lib.rs"
[profile.release]
debug = true
lto = false

183
README.md
View File

@ -1,7 +1,7 @@
# jsonpath-lib # jsonpath-lib
[![Build Status](https://travis-ci.org/freestrings/jsonpath.svg?branch=master)](https://travis-ci.org/freestrings/jsonpath) [![Build Status](https://travis-ci.org/freestrings/jsonpath.svg?branch=master)](https://travis-ci.org/freestrings/jsonpath)
[![version](https://img.shields.io/crates/v/:jsonpath.svg)](https://crates.io/crates/jsonpath_lib) ![crates.io](https://img.shields.io/crates/v/jsonpath_lib.svg)
`Rust` 버전 [JsonPath](https://goessner.net/articles/JsonPath/) 구현이다. Rust 구현과 동일한 기능을 `Webassembly` 로 제공하는 것도 목표. `Rust` 버전 [JsonPath](https://goessner.net/articles/JsonPath/) 구현이다. Rust 구현과 동일한 기능을 `Webassembly` 로 제공하는 것도 목표.
@ -16,17 +16,18 @@ To enjoy Rust!
[With Javascript (Webassembly)](#with-javascript-webassembly) [With Javascript (Webassembly)](#with-javascript-webassembly)
- [jsonpath-wasm library](#jsonpath-wasm-library) - [jsonpath-wasm library](#jsonpath-wasm-library)
- [javascript - jsonpath.read(json: string|object, jsonpath: string)](#javascript---jsonpathreadjson-stringobject-jsonpath-string) - [javascript - jsonpath.select(json: string|object, jsonpath: string)](#javascript---jsonpathselectjson-stringobject-jsonpath-string)
- [javascript - jsonpath.compile(jsonpath: string)](#javascript---jsonpathcompilejsonpath-string) - [javascript - jsonpath.compile(jsonpath: string)](#javascript---jsonpathcompilejsonpath-string)
- [javascript - jsonpath.reader(json: string|object)](#javascript---jsonpathreaderjson-stringobject) - [javascript - jsonpath.selector(json: string|object)](#javascript---jsonpathselectorjson-stringobject)
- [javascript - alloc_json, dealloc_json](#javascript---alloc_json-dealloc_json)
- [javascript - examples](#javascript---examples) - [javascript - examples](#javascript---examples)
[With Rust (as library)](#with-rust-as-library) [With Rust (as library)](#with-rust-as-library)
- [jsonpath_lib library](#jsonpath_lib-library) - [jsonpath_lib library](#jsonpath_lib-library)
- [rust - jsonpath::read(json: serde_json::value::Value, jsonpath: &str)](#rust---jsonpathreadjson-serde_jsonvaluevalue-jsonpath-str) - [rust - jsonpath::select(json: serde_json::value::Value, jsonpath: &str)](#rust---jsonpathselectjson-serde_jsonvaluevalue-jsonpath-str)
- [rust - jsonpath::compile(jsonpath: &str)](#rust---jsonpathcompilejsonpath-str) - [rust - jsonpath::compile(jsonpath: &str)](#rust---jsonpathcompilejsonpath-str)
- [rust - jsonpath::reader(json: serde_json::value::Value)](#rust---jsonpathreaderjson-serde_jsonvaluevalue) - [rust - jsonpath::selector(json: serde_json::value::Value)](#rust---jsonpathselectorjson-serde_jsonvaluevalue)
- [rust - examples](#rust---examples) - [rust - examples](#rust---examples)
[With AWS API Gateway](#with-aws-api-gateway) [With AWS API Gateway](#with-aws-api-gateway)
@ -45,7 +46,7 @@ import * as jsonpath from "jsonpath-wasm";
let jsonpath = require('jsonpath-wasm'); let jsonpath = require('jsonpath-wasm');
``` ```
### javascript - jsonpath.read(json: string|object, jsonpath: string) ### javascript - jsonpath.select(json: string|object, jsonpath: string)
```javascript ```javascript
let jsonObj = { let jsonObj = {
@ -56,8 +57,8 @@ let jsonObj = {
}; };
let ret = [{"id": 0}, {"id": 0}]; let ret = [{"id": 0}, {"id": 0}];
let a = jsonpath.read(JSON.stringify(jsonObj), "$..friends[0]"); let a = jsonpath.select(JSON.stringify(jsonObj), "$..friends[0]");
let b = jsonpath.read(jsonObj, "$..friends[0]"); let b = jsonpath.select(jsonObj, "$..friends[0]");
console.log( console.log(
JSON.stringify(ret) == JSON.stringify(a), JSON.stringify(ret) == JSON.stringify(a),
JSON.stringify(a) == JSON.stringify(b) JSON.stringify(a) == JSON.stringify(b)
@ -101,7 +102,7 @@ console.log(JSON.stringify(template(jsonObj2)) == ret2);
console.log(JSON.stringify(template(JSON.stringify(jsonObj2))) == ret2); console.log(JSON.stringify(template(JSON.stringify(jsonObj2))) == ret2);
``` ```
### javascript - jsonpath.reader(json: string|object) ### javascript - jsonpath.selector(json: string|object)
```javascript ```javascript
let jsonObj = { let jsonObj = {
@ -115,14 +116,55 @@ let ret1 = JSON.stringify([ {"id": 0}, {"id": 0} ]);
let ret2 = JSON.stringify([ {"id": 1}, {"id": 1} ]); let ret2 = JSON.stringify([ {"id": 1}, {"id": 1} ]);
// 1. read as json object // 1. read as json object
let reader = jsonpath.reader(jsonObj); let selector = jsonpath.selector(jsonObj);
console.log(JSON.stringify(reader("$..friends[0]")) == ret1); console.log(JSON.stringify(selector("$..friends[0]")) == ret1);
console.log(JSON.stringify(reader("$..friends[1]")) == ret2); console.log(JSON.stringify(selector("$..friends[1]")) == ret2);
// 2. read as json string // 2. read as json string
let reader2 = jsonpath.reader(JSON.stringify(jsonObj)); let selector = jsonpath.selector(JSON.stringify(jsonObj));
console.log(JSON.stringify(reader2("$..friends[0]")) == ret1); console.log(JSON.stringify(selector("$..friends[0]")) == ret1);
console.log(JSON.stringify(reader2("$..friends[1]")) == ret2); console.log(JSON.stringify(selector("$..friends[1]")) == ret2);
```
### javascript - alloc_json, dealloc_json
wasm-bindgen은 Javascript와 Webassembly 간 값을 주고받을 때 JSON 객체는 String으로 변환되기 때문에, 반복해서 사용되는 JSON 객체를 Webassembly 영역에 생성해 두면 성능에 도움이 된다.
Since wasm-bindgen converts JSON objects to String when exchanging values between Javascript and Webassembly, it is helpful to create repeated Json objects in Webassembly area.
```javascript
let jsonObj = {
"school": {
"friends": [{"id": 0}, {"id": 1}]
},
"friends": [{"id": 0},{"id": 1}]
};
let path = '$..friends[0]';
let template = jsonpath.compile(path);
let selector = jsonpath.selector(jsonObj);
let ptr = jsonpath.alloc_json(jsonObj);
if(ptr == 0) console.error('invalid ptr'); // `0` is invalid pointer
let selector2 = jsonpath.selector(ptr);
let ret1 = selector(path)
let ret2 = selector2(path)
let ret3 = template(jsonObj);
let ret4 = template(ptr);
let ret5 = jsonpath.select(jsonObj, path);
let ret6 = jsonpath.select(ptr, path);
console.log(
JSON.stringify(ret1) == JSON.stringify(ret2),// true
JSON.stringify(ret1) == JSON.stringify(ret3),// true
JSON.stringify(ret1) == JSON.stringify(ret4),// true
JSON.stringify(ret1) == JSON.stringify(ret5),// true
JSON.stringify(ret1) == JSON.stringify(ret6));// true
jsonpath.dealloc_json(ptr);
``` ```
### javascript - examples ### javascript - examples
@ -201,7 +243,7 @@ extern crate jsonpath_lib as jsonpath;
extern crate serde_json; extern crate serde_json;
``` ```
### rust - jsonpath::read(json: serde_json::value::Value, jsonpath: &str) ### rust - jsonpath::select(json: serde_json::value::Value, jsonpath: &str)
```rust ```rust
let json_obj = json!({ let json_obj = json!({
@ -210,7 +252,7 @@ let json_obj = json!({
}, },
"friends": [{"id": 0}, {"id": 1}] "friends": [{"id": 0}, {"id": 1}]
}); });
let json = jsonpath::read(json_obj, "$..friends[0]").unwrap(); let json = jsonpath::select(json_obj, "$..friends[0]").unwrap();
let ret = json!([ {"id": 0}, {"id": 0} ]); let ret = json!([ {"id": 0}, {"id": 0} ]);
assert_eq!(json, ret) assert_eq!(json, ret)
``` ```
@ -243,7 +285,7 @@ let ret = json!([ {"id": 0}, {"name": "Millicent Norman"} ]);
assert_eq!(json, ret); assert_eq!(json, ret);
``` ```
### rust - jsonpath::reader(json: serde_json::value::Value) ### rust - jsonpath::selector(json: serde_json::value::Value)
```rust ```rust
let json_obj = json!({ let json_obj = json!({
@ -253,13 +295,13 @@ let json_obj = json!({
"friends": [{"id": 0},{"id": 1}] "friends": [{"id": 0},{"id": 1}]
}); });
let mut reader = jsonpath::reader(json_obj); let mut selector = jsonpath::selector(json_obj);
let json = reader("$..friends[0]").unwrap(); let json = selector("$..friends[0]").unwrap();
let ret = json!([ {"id": 0}, {"id": 0} ]); let ret = json!([ {"id": 0}, {"id": 0} ]);
assert_eq!(json, ret); assert_eq!(json, ret);
let json = reader("$..friends[1]").unwrap(); let json = selector("$..friends[1]").unwrap();
let ret = json!([ {"id": 1}, {"id": 1} ]); let ret = json!([ {"id": 1}, {"id": 1} ]);
assert_eq!(json, ret); assert_eq!(json, ret);
``` ```
@ -305,13 +347,13 @@ let json_obj = json!({
"expensive": 10 "expensive": 10
}); });
let mut reader = jsonpath::reader(json_obj); let mut selector = jsonpath::selector(json_obj);
``` ```
#### $.store.book[*].author #### $.store.book[*].author
```rust ```rust
let json = reader("$.store.book[*].author").unwrap(); let json = selector("$.store.book[*].author").unwrap();
let ret = json!([ let ret = json!([
"Nigel Rees", "Nigel Rees",
"Evelyn Waugh", "Evelyn Waugh",
@ -323,7 +365,7 @@ assert_eq!(json, ret);
#### $..author #### $..author
```rust ```rust
let json = reader("$..author").unwrap(); let json = selector("$..author").unwrap();
let ret = json!([ let ret = json!([
"Nigel Rees", "Nigel Rees",
"Evelyn Waugh", "Evelyn Waugh",
@ -335,7 +377,7 @@ assert_eq!(json, ret);
#### $.store.* #### $.store.*
```rust ```rust
let json = reader("$.store.*").unwrap(); let json = selector("$.store.*").unwrap();
let ret = json!([ let ret = json!([
[ [
{ {
@ -375,14 +417,14 @@ assert_eq!(ret, json);
#### $.store..price #### $.store..price
```rust ```rust
let json = reader("$.store..price").unwrap(); let json = selector("$.store..price").unwrap();
let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]); let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]);
assert_eq!(ret, json); assert_eq!(ret, json);
``` ```
#### $..book[2] #### $..book[2]
```rust ```rust
let json = reader("$..book[2]").unwrap(); let json = selector("$..book[2]").unwrap();
let ret = json!([{ let ret = json!([{
"category" : "fiction", "category" : "fiction",
"author" : "Herman Melville", "author" : "Herman Melville",
@ -395,7 +437,7 @@ assert_eq!(ret, json);
#### $..book[-2] #### $..book[-2]
```rust ```rust
let json = reader("$..book[-2]").unwrap(); let json = selector("$..book[-2]").unwrap();
let ret = json!([{ let ret = json!([{
"category" : "fiction", "category" : "fiction",
"author" : "Herman Melville", "author" : "Herman Melville",
@ -408,7 +450,7 @@ assert_eq!(ret, json);
#### $..book[0,1] #### $..book[0,1]
```rust ```rust
let json = reader("$..book[0,1]").unwrap(); let json = selector("$..book[0,1]").unwrap();
let ret = json!([ let ret = json!([
{ {
"category": "reference", "category": "reference",
@ -428,7 +470,7 @@ assert_eq!(ret, json);
#### $..book[:2] #### $..book[:2]
```rust ```rust
let json = reader("$..book[:2]").unwrap(); let json = selector("$..book[:2]").unwrap();
let ret = json!([ let ret = json!([
{ {
"category": "reference", "category": "reference",
@ -448,7 +490,7 @@ assert_eq!(ret, json);
#### $..book[2:] #### $..book[2:]
```rust ```rust
let json = reader("$..book[2:]").unwrap(); let json = selector("$..book[2:]").unwrap();
let ret = json!([ let ret = json!([
{ {
"category": "fiction", "category": "fiction",
@ -470,7 +512,7 @@ assert_eq!(ret, json);
#### $..book[?(@.isbn)] #### $..book[?(@.isbn)]
```rust ```rust
let json = reader("$..book[?(@.isbn)]").unwrap(); let json = selector("$..book[?(@.isbn)]").unwrap();
let ret = json!([ let ret = json!([
{ {
"category": "fiction", "category": "fiction",
@ -492,7 +534,7 @@ assert_eq!(ret, json);
#### $.store.book[?(@.price < 10)] #### $.store.book[?(@.price < 10)]
```rust ```rust
let json = reader("$.store.book[?(@.price < 10)]").unwrap(); let json = selector("$.store.book[?(@.price < 10)]").unwrap();
let ret = json!([ let ret = json!([
{ {
"category": "reference", "category": "reference",
@ -513,7 +555,7 @@ assert_eq!(ret, json);
#### $..book[?((@.price == 12.99 || $.store.bicycle.price < @.price) || @.category == "reference")] #### $..book[?((@.price == 12.99 || $.store.bicycle.price < @.price) || @.category == "reference")]
```rust ```rust
let json = reader(r#"$..book[ let json = selector(r#"$..book[
?( ?(
(@.price == 12.99 || $.store.bicycle.price < @.price) (@.price == 12.99 || $.store.bicycle.price < @.price)
|| @.category == "reference" || @.category == "reference"
@ -554,15 +596,21 @@ assert_eq!(ret, json);
### Browser [Bench Demo](https://freestrings.github.io/jsonpath/bench) ### Browser [Bench Demo](https://freestrings.github.io/jsonpath/bench)
```
'$..book[?(@.price<30 && @.category=="fiction")]' (loop 2,000)
```
#### Chrome: 72.0 #### Chrome: 72.0
> Something to wrong in chrome > Something to wrong in chrome
``` ```
jsonpath, 134 jsonpath, 166
jsonpath-wasm- reader, 1409 jsonpath-wasm- selector, 256
jsonpath-wasm- compile, 3237 jsonpath-wasm- compile, 1168
jsonpath-wasm- read, 5302 jsonpath-wasm- compile-alloc, 645
jsonpath-wasm- select, 3224
jsonpath-wasm- select-alloc, 1427
``` ```
#### Firefox: 65.0 #### Firefox: 65.0
@ -570,40 +618,65 @@ jsonpath-wasm- read, 5302
> jsonpath-wasm is faster than jsonpath > jsonpath-wasm is faster than jsonpath
``` ```
jsonpath, 301 jsonpath, 125
jsonpath-wasm- reader, 166 jsonpath-wasm- selector, 101
jsonpath-wasm- compile, 130 jsonpath-wasm- compile, 169
jsonpath-wasm- read, 144 jsonpath-wasm- compile-alloc, 78
jsonpath-wasm- select, 186
jsonpath-wasm- select-alloc, 93
``` ```
### NodeJs ### NodeJs
* NodeJS: 11.0 * NodeJS: 11.0
* CPU: Intel Core i5-4460
* Memory: 16GB
> Rust > jsonpath > jsonpath-wasm > Rust > jsonpath > jsonpath-wasm
```bash ```bash
cd benches && ./bench_node_vs_rust.sh cd benches && ./bench_node_vs_rust.sh
$..book[?(@.price<30 && @.category==fiction)] (loop 100,000) $..book[?(@.price<30 && @.category==fiction)] (loop 100,000)
Rust: Rust:
real 0m1.141s real 0m0.862s
user 0m1.137s user 0m0.862s
sys 0m0.004s sys 0m0.000s
NodeJs - jsonpath module: NodeJs - jsonpath module:
real 0m3.718s real 0m3.667s
user 0m4.175s user 0m4.139s
sys 0m0.050s sys 0m0.045s
NodeJs - jsonpath-wasm module: NodeJs - jsonpath-wasm module - selector:
real 0m5.331s
user 0m5.494s
sys 0m0.093s
NodeJs - jsonpath-wasm module - compile:
real 0m8.665s
user 0m8.809s
sys 0m0.197s
NodeJs - jsonpath-wasm module - compile-alloc:
real 0m4.014s
user 0m4.173s
sys 0m0.088s
NodeJs - jsonpath-wasm module - select:
real 0m9.843s
user 0m9.897s
sys 0m0.244s
NodeJs - jsonpath-wasm module - select-alloc:
real 0m5.212s
user 0m5.339s
sys 0m0.096s
real 0m10.205s
user 0m10.281s
sys 0m0.383s
``` ```

View File

@ -1,6 +1,6 @@
[package] [package]
name = "bench_bin" name = "bench_bin"
version = "0.1.0" version = "0.1.1"
[dependencies] [dependencies]
jsonpath_lib = {path = "../../"} jsonpath_lib = {path = "../../"}

View File

@ -14,8 +14,8 @@ fn read_json(path: &str) -> String {
fn main() { fn main() {
let string = read_json("../example.json"); let string = read_json("../example.json");
let json: Value = serde_json::from_str(string.as_str()).unwrap(); let json: Value = serde_json::from_str(string.as_str()).unwrap();
let mut reader = jsonpath::reader(json); let mut selector = jsonpath::selector(json);
for _ in 1..100000 { for _ in 1..100000 {
let _ = reader(r#"$..book[?(@.price<30 && @.category=="fiction")]"#).unwrap(); let _ = selector(r#"$..book[?(@.price<30 && @.category=="fiction")]"#).unwrap();
} }
} }

View File

@ -10,6 +10,14 @@ printf "\n\n"
echo "Rust: " && time ./bench.sh echo "Rust: " && time ./bench.sh
printf "\n" printf "\n"
cd "${DIR}"/javascript && echo "NodeJs - jsonpath module: " && time ./bench.sh jsonpathOnly cd "${DIR}"/javascript && echo "NodeJs - jsonpath module: " && time ./bench.sh jsonpath
printf "\n" printf "\n"
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm module: " && time ./bench.sh jsonpathWasmOnly cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm module - selector: " && time ./bench.sh wasmSelector
printf "\n"
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm module - compile: " && time ./bench.sh wasmCompile
printf "\n"
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm module - compile-alloc: " && time ./bench.sh wasmCompileAlloc
printf "\n"
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm module - select:" && time ./bench.sh wasmSelect
printf "\n"
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm module - select-alloc:" && time ./bench.sh wasmSelectAlloc

View File

@ -1,118 +1,124 @@
let json = { let json = {
"store": { 'store': {
"book": [ 'book': [
{ {
"category": "reference", 'category': 'reference',
"author": "Nigel Rees", 'author': 'Nigel Rees',
"title": "Sayings of the Century", 'title': 'Sayings of the Century',
"price": 8.95 'price': 8.95,
}, },
{ {
"category": "fiction", 'category': 'fiction',
"author": "Evelyn Waugh", 'author': 'Evelyn Waugh',
"title": "Sword of Honour", 'title': 'Sword of Honour',
"price": 12.99 'price': 12.99,
}, },
{ {
"category": "fiction", 'category': 'fiction',
"author": "Herman Melville", 'author': 'Herman Melville',
"title": "Moby Dick", 'title': 'Moby Dick',
"isbn": "0-553-21311-3", 'isbn': '0-553-21311-3',
"price": 8.99 'price': 8.99,
}, },
{ {
"category": "fiction", 'category': 'fiction',
"author": "J. R. R. Tolkien", 'author': 'J. R. R. Tolkien',
"title": "The Lord of the Rings", 'title': 'The Lord of the Rings',
"isbn": "0-395-19395-8", 'isbn': '0-395-19395-8',
"price": 22.99 'price': 22.99,
} },
], ],
"bicycle": { 'bicycle': {
"color": "red", 'color': 'red',
"price": 19.95 'price': 19.95,
} },
}, },
"expensive": 10 'expensive': 10,
}; };
const jp = require('jsonpath'); const jp = require('jsonpath');
const jpw = require('@nodejs/jsonpath-wasm'); const jpw = require('@nodejs/jsonpath-wasm');
const Benchmark = require('benchmark'); const iter = 100000;
function compareJsonpath(path) { function jsonpath() {
let r1 = jp.query(json, path); for (var i = 0; i < iter; i++) {
let r2 = jpw.read(json, path);
let template = jpw.compile(path);
var suite = new Benchmark.Suite;
suite.add('jp', function() {
jp.query(json, path);
})
.add('jpw', function() {
template(json);
})
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').map('name'));
console.log('Slowest is ' + this.filter('slowest').map('name'));
})
.run({ 'async': true });
}
function compareEmptyFunction() {
var suite = new Benchmark.Suite;
suite.add('js', function() {
})
.add('rust', function() {
jpw.testa();
})
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').map('name'));
console.log('Slowest is ' + this.filter('slowest').map('name'));
})
.run({});
}
function jsonpathOnly() {
for(var i = 0; i < 100000 ; i++) {
let _ = jp.query(json, '$..book[?(@.price<30 && @.category=="fiction")]'); let _ = jp.query(json, '$..book[?(@.price<30 && @.category=="fiction")]');
} }
} }
function jsonpathWasmOnly() { function wasmSelector() {
let reader = jpw.reader(json); let selector = jpw.selector(json);
for(var i = 0; i < 100000 ; i++) { for (var i = 0; i < iter; i++) {
let _ = reader('$..book[?(@.price<30 && @.category=="fiction")]'); let _ = selector('$..book[?(@.price<30 && @.category=="fiction")]');
} }
} }
if(process.argv.length < 3) { function wasmCompile() {
let functions = ['', 'compareJsonpath', 'compareEmptyFunction', 'jsonpathOnly', 'jsonpathWasmOnly']; let template = jpw.compile('$..book[?(@.price<30 && @.category=="fiction")]');
console.log("node bench.js", functions.join("\n\t|")); for (var i = 0; i < iter; i++) {
return; let _ = template(json);
}
}
function wasmCompileAlloc() {
let ptr = jpw.alloc_json(json);
if (ptr == 0) {
console.error('Invalid pointer');
return;
}
try {
let template = jpw.compile('$..book[?(@.price<30 && @.category=="fiction")]');
for (var i = 0; i < iter; i++) {
let _ = template(ptr);
}
} finally {
jpw.dealloc_json(ptr);
}
}
function wasmSelect() {
for (var i = 0; i < iter; i++) {
let _ = jpw.select(json, '$..book[?(@.price<30 && @.category=="fiction")]');
}
}
function wasmSelectAlloc() {
let ptr = jpw.alloc_json(json);
if (ptr == 0) {
console.error('Invalid pointer');
return;
}
try {
for (var i = 0; i < iter; i++) {
let _ = jpw.select(ptr, '$..book[?(@.price<30 && @.category=="fiction")]');
}
} finally {
jpw.dealloc_json(ptr);
}
} }
let functionName = process.argv[2]; let functionName = process.argv[2];
switch (functionName) { switch (functionName) {
case 'compareJsonpath': case 'jsonpath':
compareJsonpath('$..book[?(@.price<30 && @.category=="fiction")]'); jsonpath();
break; break;
case 'compareEmptyFunction': case 'wasmSelector':
compareEmptyFunction(); wasmSelector();
break; break;
case 'jsonpathWasmOnly': case 'wasmCompile':
jsonpathWasmOnly(); wasmCompile();
break; break;
case 'wasmSelect':
wasmSelect();
break;
case 'wasmCompileAlloc':
wasmCompileAlloc();
break;
case 'wasmSelectAlloc':
wasmSelectAlloc();
default: default:
jsonpathOnly(); console.error('Invalid function name');
} }

View File

@ -9,15 +9,6 @@
"resolved": "https://registry.npmjs.org/JSONSelect/-/JSONSelect-0.4.0.tgz", "resolved": "https://registry.npmjs.org/JSONSelect/-/JSONSelect-0.4.0.tgz",
"integrity": "sha1-oI7cxn6z/L6Z7WMIVTRKDPKCu40=" "integrity": "sha1-oI7cxn6z/L6Z7WMIVTRKDPKCu40="
}, },
"benchmark": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz",
"integrity": "sha1-CfPeMckWQl1JjMLuVloOvzwqVik=",
"requires": {
"lodash": "^4.17.4",
"platform": "^1.3.3"
}
},
"cjson": { "cjson": {
"version": "0.2.1", "version": "0.2.1",
"resolved": "https://registry.npmjs.org/cjson/-/cjson-0.2.1.tgz", "resolved": "https://registry.npmjs.org/cjson/-/cjson-0.2.1.tgz",
@ -131,11 +122,6 @@
"resolved": "https://registry.npmjs.org/lex-parser/-/lex-parser-0.1.4.tgz", "resolved": "https://registry.npmjs.org/lex-parser/-/lex-parser-0.1.4.tgz",
"integrity": "sha1-ZMTwJfF/1Tv7RXY/rrFvAVp0dVA=" "integrity": "sha1-ZMTwJfF/1Tv7RXY/rrFvAVp0dVA="
}, },
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
},
"nomnom": { "nomnom": {
"version": "1.5.2", "version": "1.5.2",
"resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.5.2.tgz", "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.5.2.tgz",
@ -165,11 +151,6 @@
"wordwrap": "~1.0.0" "wordwrap": "~1.0.0"
} }
}, },
"platform": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/platform/-/platform-1.3.5.tgz",
"integrity": "sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q=="
},
"prelude-ls": { "prelude-ls": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",

View File

@ -6,7 +6,6 @@
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"dependencies": { "dependencies": {
"jsonpath": "*", "jsonpath": "*"
"benchmark": "*"
} }
} }

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -55,20 +55,29 @@
/******/ "../browser_pkg/jsonpath_wasm_bg.wasm": function() { /******/ "../browser_pkg/jsonpath_wasm_bg.wasm": function() {
/******/ return { /******/ return {
/******/ "./jsonpath_wasm": { /******/ "./jsonpath_wasm": {
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
/******/ },
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_clone_ref"](p0i32);
/******/ },
/******/ "__wbindgen_cb_forget": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
/******/ },
/******/ "__wbindgen_json_parse": function(p0i32,p1i32) { /******/ "__wbindgen_json_parse": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_parse"](p0i32,p1i32); /******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_parse"](p0i32,p1i32);
/******/ }, /******/ },
/******/ "__wbindgen_json_serialize": function(p0i32,p1i32) { /******/ "__wbindgen_json_serialize": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_serialize"](p0i32,p1i32); /******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_serialize"](p0i32,p1i32);
/******/ }, /******/ },
/******/ "__wbindgen_cb_forget": function(p0i32) { /******/ "__widl_f_log_1_": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32); /******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__widl_f_log_1_"](p0i32);
/******/ }, /******/ },
/******/ "__wbindgen_object_drop_ref": function(p0i32) { /******/ "__wbindgen_number_get": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32); /******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_number_get"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
/******/ }, /******/ },
/******/ "__wbindgen_is_string": function(p0i32) { /******/ "__wbindgen_is_string": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_is_string"](p0i32); /******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_is_string"](p0i32);
@ -76,17 +85,14 @@
/******/ "__wbindgen_string_get": function(p0i32,p1i32) { /******/ "__wbindgen_string_get": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_get"](p0i32,p1i32); /******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_get"](p0i32,p1i32);
/******/ }, /******/ },
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_clone_ref"](p0i32);
/******/ },
/******/ "__wbindgen_throw": function(p0i32,p1i32) { /******/ "__wbindgen_throw": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32); /******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32);
/******/ }, /******/ },
/******/ "__wbindgen_closure_wrapper33": function(p0i32,p1i32,p2i32) { /******/ "__wbindgen_closure_wrapper101": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper33"](p0i32,p1i32,p2i32); /******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper101"](p0i32,p1i32,p2i32);
/******/ }, /******/ },
/******/ "__wbindgen_closure_wrapper35": function(p0i32,p1i32,p2i32) { /******/ "__wbindgen_closure_wrapper103": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper35"](p0i32,p1i32,p2i32); /******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper103"](p0i32,p1i32,p2i32);
/******/ } /******/ }
/******/ } /******/ }
/******/ }; /******/ };
@ -186,7 +192,7 @@
/******/ promises.push(installedWasmModuleData); /******/ promises.push(installedWasmModuleData);
/******/ else { /******/ else {
/******/ var importObject = wasmImportObjects[wasmModuleId](); /******/ var importObject = wasmImportObjects[wasmModuleId]();
/******/ var req = fetch(__webpack_require__.p + "" + {"../browser_pkg/jsonpath_wasm_bg.wasm":"95acaf85df86c0a76234"}[wasmModuleId] + ".module.wasm"); /******/ var req = fetch(__webpack_require__.p + "" + {"../browser_pkg/jsonpath_wasm_bg.wasm":"9a826648f4cbc2bc8591"}[wasmModuleId] + ".module.wasm");
/******/ var promise; /******/ var promise;
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') { /******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) { /******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {

60
docs/bootstrap.js vendored
View File

@ -52,41 +52,47 @@
/******/ function promiseResolve() { return Promise.resolve(); } /******/ function promiseResolve() { return Promise.resolve(); }
/******/ /******/
/******/ var wasmImportObjects = { /******/ var wasmImportObjects = {
/******/ "../pkg/jsonpath_wasm_bg.wasm": function() { /******/ "../browser_pkg/jsonpath_wasm_bg.wasm": function() {
/******/ return { /******/ return {
/******/ "./jsonpath_wasm": { /******/ "./jsonpath_wasm": {
/******/ "__wbindgen_json_parse": function(p0i32,p1i32) { /******/ "__wbindgen_string_new": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_json_parse"](p0i32,p1i32); /******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_json_serialize": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_json_serialize"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_cb_forget": function(p0i32) {
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
/******/ }, /******/ },
/******/ "__wbindgen_object_drop_ref": function(p0i32) { /******/ "__wbindgen_object_drop_ref": function(p0i32) {
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32); /******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
/******/ },
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_is_string": function(p0i32) {
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_is_string"](p0i32);
/******/ },
/******/ "__wbindgen_string_get": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_string_get"](p0i32,p1i32);
/******/ }, /******/ },
/******/ "__wbindgen_object_clone_ref": function(p0i32) { /******/ "__wbindgen_object_clone_ref": function(p0i32) {
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_object_clone_ref"](p0i32); /******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_clone_ref"](p0i32);
/******/ },
/******/ "__wbindgen_cb_forget": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
/******/ },
/******/ "__wbindgen_json_parse": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_parse"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_json_serialize": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_serialize"](p0i32,p1i32);
/******/ },
/******/ "__widl_f_log_1_": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__widl_f_log_1_"](p0i32);
/******/ },
/******/ "__wbindgen_number_get": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_number_get"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_is_string": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_is_string"](p0i32);
/******/ },
/******/ "__wbindgen_string_get": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_get"](p0i32,p1i32);
/******/ }, /******/ },
/******/ "__wbindgen_throw": function(p0i32,p1i32) { /******/ "__wbindgen_throw": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32); /******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32);
/******/ }, /******/ },
/******/ "__wbindgen_closure_wrapper28": function(p0i32,p1i32,p2i32) { /******/ "__wbindgen_closure_wrapper101": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper28"](p0i32,p1i32,p2i32); /******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper101"](p0i32,p1i32,p2i32);
/******/ }, /******/ },
/******/ "__wbindgen_closure_wrapper30": function(p0i32,p1i32,p2i32) { /******/ "__wbindgen_closure_wrapper103": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper30"](p0i32,p1i32,p2i32); /******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper103"](p0i32,p1i32,p2i32);
/******/ } /******/ }
/******/ } /******/ }
/******/ }; /******/ };
@ -176,7 +182,7 @@
/******/ /******/
/******/ // Fetch + compile chunk loading for webassembly /******/ // Fetch + compile chunk loading for webassembly
/******/ /******/
/******/ var wasmModules = {"0":["../pkg/jsonpath_wasm_bg.wasm"]}[chunkId] || []; /******/ var wasmModules = {"0":["../browser_pkg/jsonpath_wasm_bg.wasm"]}[chunkId] || [];
/******/ /******/
/******/ wasmModules.forEach(function(wasmModuleId) { /******/ wasmModules.forEach(function(wasmModuleId) {
/******/ var installedWasmModuleData = installedWasmModules[wasmModuleId]; /******/ var installedWasmModuleData = installedWasmModules[wasmModuleId];
@ -186,7 +192,7 @@
/******/ promises.push(installedWasmModuleData); /******/ promises.push(installedWasmModuleData);
/******/ else { /******/ else {
/******/ var importObject = wasmImportObjects[wasmModuleId](); /******/ var importObject = wasmImportObjects[wasmModuleId]();
/******/ var req = fetch(__webpack_require__.p + "" + {"../pkg/jsonpath_wasm_bg.wasm":"d6c7cff8a1d228da11b7"}[wasmModuleId] + ".module.wasm"); /******/ var req = fetch(__webpack_require__.p + "" + {"../browser_pkg/jsonpath_wasm_bg.wasm":"9a826648f4cbc2bc8591"}[wasmModuleId] + ".module.wasm");
/******/ var promise; /******/ var promise;
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') { /******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) { /******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {

View File

@ -23,7 +23,7 @@ mod tests {
fn new_value_filter(file: &str) -> ValueFilter { fn new_value_filter(file: &str) -> ValueFilter {
let string = read_json(file); let string = read_json(file);
let json: Value = serde_json::from_str(string.as_str()).unwrap(); let json: Value = serde_json::from_str(string.as_str()).unwrap();
ValueFilter::new(json, false, false) ValueFilter::new(json.into(), false, false)
} }
fn do_filter(path: &str, file: &str) -> JsonValueFilter { fn do_filter(path: &str, file: &str) -> JsonValueFilter {
@ -71,7 +71,7 @@ mod tests {
"Vincent Cannon", "Vincent Cannon",
"Gray Berry" "Gray Berry"
]); ]);
assert_eq!(&friends, current.get_val()); assert_eq!(friends, current.get_val().into_value());
} }
let mut jf = new_value_filter("./benches/data_obj.json"); let mut jf = new_value_filter("./benches/data_obj.json");
{ {
@ -84,7 +84,7 @@ mod tests {
"Vincent Cannon", "Vincent Cannon",
"Gray Berry" "Gray Berry"
]); ]);
assert_eq!(&names, current.get_val()); assert_eq!(names, current.get_val().into_value());
} }
} }
@ -98,32 +98,32 @@ mod tests {
]); ]);
let jf = do_filter("$.school.friends[1, 2]", "./benches/data_obj.json"); let jf = do_filter("$.school.friends[1, 2]", "./benches/data_obj.json");
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
let jf = do_filter("$.school.friends[1:]", "./benches/data_obj.json"); let jf = do_filter("$.school.friends[1:]", "./benches/data_obj.json");
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
let jf = do_filter("$.school.friends[:-2]", "./benches/data_obj.json"); let jf = do_filter("$.school.friends[:-2]", "./benches/data_obj.json");
let friends = json!([ let friends = json!([
{"id": 0, "name": "Millicent Norman"} {"id": 0, "name": "Millicent Norman"}
]); ]);
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
let jf = do_filter("$..friends[2].name", "./benches/data_obj.json"); let jf = do_filter("$..friends[2].name", "./benches/data_obj.json");
let friends = json!(["Gray Berry", "Gray Berry"]); let friends = json!(["Gray Berry", "Gray Berry"]);
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
let jf = do_filter("$..friends[*].name", "./benches/data_obj.json"); let jf = do_filter("$..friends[*].name", "./benches/data_obj.json");
let friends = json!(["Vincent Cannon","Gray Berry","Millicent Norman","Vincent Cannon","Gray Berry"]); let friends = json!(["Vincent Cannon","Gray Berry","Millicent Norman","Vincent Cannon","Gray Berry"]);
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
let jf = do_filter("$['school']['friends'][*].['name']", "./benches/data_obj.json"); let jf = do_filter("$['school']['friends'][*].['name']", "./benches/data_obj.json");
let friends = json!(["Millicent Norman","Vincent Cannon","Gray Berry"]); let friends = json!(["Millicent Norman","Vincent Cannon","Gray Berry"]);
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
let jf = do_filter("$['school']['friends'][0].['name']", "./benches/data_obj.json"); let jf = do_filter("$['school']['friends'][0].['name']", "./benches/data_obj.json");
let friends = json!("Millicent Norman"); let friends = json!("Millicent Norman");
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
} }
#[test] #[test]
@ -139,16 +139,16 @@ mod tests {
}); });
let jf = do_filter("$.school", "./benches/data_obj.json"); let jf = do_filter("$.school", "./benches/data_obj.json");
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
let jf = do_filter("$.school[?(@.friends[0])]", "./benches/data_obj.json"); let jf = do_filter("$.school[?(@.friends[0])]", "./benches/data_obj.json");
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
let jf = do_filter("$.school[?(@.friends[10])]", "./benches/data_obj.json"); let jf = do_filter("$.school[?(@.friends[10])]", "./benches/data_obj.json");
assert_eq!(&Value::Null, jf.current_value()); assert_eq!(Value::Null, jf.current_value().into_value());
let jf = do_filter("$.school[?(1==1)]", "./benches/data_obj.json"); let jf = do_filter("$.school[?(1==1)]", "./benches/data_obj.json");
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
let jf = do_filter("$.school.friends[?(1==1)]", "./benches/data_obj.json"); let jf = do_filter("$.school.friends[?(1==1)]", "./benches/data_obj.json");
let friends = json!([ let friends = json!([
@ -156,7 +156,7 @@ mod tests {
{"id": 1, "name": "Vincent Cannon" }, {"id": 1, "name": "Vincent Cannon" },
{"id": 2, "name": "Gray Berry"} {"id": 2, "name": "Gray Berry"}
]); ]);
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
} }
#[test] #[test]
@ -171,42 +171,42 @@ mod tests {
{"id": 2, "name": "Gray Berry"} {"id": 2, "name": "Gray Berry"}
] ]
}); });
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
let jf = do_filter("$.friends[?(@.name)]", "./benches/data_obj.json"); let jf = do_filter("$.friends[?(@.name)]", "./benches/data_obj.json");
let friends = json!([ let friends = json!([
{ "id" : 1, "name" : "Vincent Cannon" }, { "id" : 1, "name" : "Vincent Cannon" },
{ "id" : 2, "name" : "Gray Berry" } { "id" : 2, "name" : "Gray Berry" }
]); ]);
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
let jf = do_filter("$.friends[?(@.id >= 2)]", "./benches/data_obj.json"); let jf = do_filter("$.friends[?(@.id >= 2)]", "./benches/data_obj.json");
let friends = json!([ let friends = json!([
{ "id" : 2, "name" : "Gray Berry" } { "id" : 2, "name" : "Gray Berry" }
]); ]);
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
let jf = do_filter("$.friends[?(@.id >= 2 || @.id == 1)]", "./benches/data_obj.json"); let jf = do_filter("$.friends[?(@.id >= 2 || @.id == 1)]", "./benches/data_obj.json");
let friends = json!([ let friends = json!([
{ "id" : 2, "name" : "Gray Berry" }, { "id" : 2, "name" : "Gray Berry" },
{ "id" : 1, "name" : "Vincent Cannon" } { "id" : 1, "name" : "Vincent Cannon" }
]); ]);
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
let jf = do_filter("$.friends[?( (@.id >= 2 || @.id == 1) && @.id == 0)]", "./benches/data_obj.json"); let jf = do_filter("$.friends[?( (@.id >= 2 || @.id == 1) && @.id == 0)]", "./benches/data_obj.json");
assert_eq!(&Value::Null, jf.current_value()); assert_eq!(Value::Null, jf.current_value().into_value());
let jf = do_filter("$..friends[?(@.id == $.index)].id", "./benches/data_obj.json"); let jf = do_filter("$..friends[?(@.id == $.index)].id", "./benches/data_obj.json");
let friends = json!([0, 0]); let friends = json!([0, 0]);
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
let jf = do_filter("$..book[?($.store.bicycle.price < @.price)].price", "./benches/example.json"); let jf = do_filter("$..book[?($.store.bicycle.price < @.price)].price", "./benches/example.json");
let friends = json!([22.99]); let friends = json!([22.99]);
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
let jf = do_filter("$..book[?( (@.price == 12.99 || @.category == 'reference') && @.price > 10)].price", "./benches/example.json"); let jf = do_filter("$..book[?( (@.price == 12.99 || @.category == 'reference') && @.price > 10)].price", "./benches/example.json");
let friends = json!([12.99]); let friends = json!([12.99]);
assert_eq!(&friends, jf.current_value()); assert_eq!(friends, jf.current_value().into_value());
} }
#[test] #[test]
@ -215,10 +215,10 @@ mod tests {
let jf = do_filter("$.store.book[*].author", "./benches/example.json"); let jf = do_filter("$.store.book[*].author", "./benches/example.json");
let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]); let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]);
assert_eq!(&ret, jf.current_value()); assert_eq!(ret, jf.current_value().into_value());
let jf = do_filter("$..author", "./benches/example.json"); let jf = do_filter("$..author", "./benches/example.json");
assert_eq!(&ret, jf.current_value()); assert_eq!(ret, jf.current_value().into_value());
let jf = do_filter("$.store.*", "./benches/example.json"); let jf = do_filter("$.store.*", "./benches/example.json");
let ret = json!([ let ret = json!([
@ -230,11 +230,11 @@ mod tests {
], ],
{"color" : "red","price" : 19.95}, {"color" : "red","price" : 19.95},
]); ]);
assert_eq!(&ret, jf.current_value()); assert_eq!(ret, jf.current_value().into_value());
let jf = do_filter("$.store..price", "./benches/example.json"); let jf = do_filter("$.store..price", "./benches/example.json");
let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]); let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]);
assert_eq!(&ret, jf.current_value()); assert_eq!(ret, jf.current_value().into_value());
let jf = do_filter("$..book[2]", "./benches/example.json"); let jf = do_filter("$..book[2]", "./benches/example.json");
let ret = json!([{ let ret = json!([{
@ -244,7 +244,7 @@ mod tests {
"isbn" : "0-553-21311-3", "isbn" : "0-553-21311-3",
"price" : 8.99 "price" : 8.99
}]); }]);
assert_eq!(&ret, jf.current_value()); assert_eq!(ret, jf.current_value().into_value());
let jf = do_filter("$..book[-2]", "./benches/example.json"); let jf = do_filter("$..book[-2]", "./benches/example.json");
let ret = json!([{ let ret = json!([{
@ -254,7 +254,7 @@ mod tests {
"isbn" : "0-553-21311-3", "isbn" : "0-553-21311-3",
"price" : 8.99 "price" : 8.99
}]); }]);
assert_eq!(&ret, jf.current_value()); assert_eq!(ret, jf.current_value().into_value());
let jf = do_filter("$..book[0,1]", "./benches/example.json"); let jf = do_filter("$..book[0,1]", "./benches/example.json");
let ret = json!([ let ret = json!([
@ -271,7 +271,7 @@ mod tests {
"price" : 12.99 "price" : 12.99
} }
]); ]);
assert_eq!(&ret, jf.current_value()); assert_eq!(ret, jf.current_value().into_value());
let jf = do_filter("$..book[:2]", "./benches/example.json"); let jf = do_filter("$..book[:2]", "./benches/example.json");
let ret = json!([ let ret = json!([
@ -288,7 +288,7 @@ mod tests {
"price" : 12.99 "price" : 12.99
} }
]); ]);
assert_eq!(&ret, jf.current_value()); assert_eq!(ret, jf.current_value().into_value());
let jf = do_filter("$..book[2:]", "./benches/example.json"); let jf = do_filter("$..book[2:]", "./benches/example.json");
let ret = json!([ let ret = json!([
@ -307,7 +307,7 @@ mod tests {
"price" : 22.99 "price" : 22.99
} }
]); ]);
assert_eq!(&ret, jf.current_value()); assert_eq!(ret, jf.current_value().into_value());
let jf = do_filter("$..book[?(@.isbn)]", "./benches/example.json"); let jf = do_filter("$..book[?(@.isbn)]", "./benches/example.json");
let ret = json!([ let ret = json!([
@ -326,7 +326,7 @@ mod tests {
"price" : 22.99 "price" : 22.99
} }
]); ]);
assert_eq!(&ret, jf.current_value()); assert_eq!(ret, jf.current_value().into_value());
let jf = do_filter("$.store.book[?(@.price < 10)]", "./benches/example.json"); let jf = do_filter("$.store.book[?(@.price < 10)]", "./benches/example.json");
let ret = json!([ let ret = json!([
@ -344,10 +344,10 @@ mod tests {
"price" : 8.99 "price" : 8.99
} }
]); ]);
assert_eq!(&ret, jf.current_value()); assert_eq!(ret, jf.current_value().into_value());
let jf = do_filter("$..*", "./benches/example.json"); let jf = do_filter("$..*", "./benches/example.json");
let json: Value = serde_json::from_str(read_json("./benches/giveme_every_thing_result.json").as_str()).unwrap(); let json: Value = serde_json::from_str(read_json("./benches/giveme_every_thing_result.json").as_str()).unwrap();
assert_eq!(&json, jf.current_value()); assert_eq!(json, jf.current_value().into_value());
} }
} }

View File

@ -9,7 +9,7 @@ pub enum TermContext {
} }
impl TermContext { impl TermContext {
fn cmp<F: PrivCmp + IntoType>(&mut self, other: &mut TermContext, cmp_fn: F, default: bool) -> TermContext { fn cmp<F: PrivCmp + IntoType>(&self, other: &TermContext, cmp_fn: F, default: bool) -> TermContext {
match self { match self {
TermContext::Constants(et) => { TermContext::Constants(et) => {
match other { match other {
@ -51,7 +51,7 @@ impl TermContext {
} }
} }
fn cmp_cond(&mut self, other: &mut TermContext, cmp_cond_type: CmpCondType) -> TermContext { fn cmp_cond(&self, other: &TermContext, cmp_cond_type: CmpCondType) -> TermContext {
match self { match self {
TermContext::Constants(et) => { TermContext::Constants(et) => {
match other { match other {
@ -86,35 +86,35 @@ impl TermContext {
} }
} }
pub fn eq(&mut self, other: &mut TermContext) -> TermContext { pub fn eq(&self, other: &TermContext) -> TermContext {
self.cmp(other, CmpEq, false) self.cmp(other, CmpEq, false)
} }
pub fn ne(&mut self, other: &mut TermContext) -> TermContext { pub fn ne(&self, other: &TermContext) -> TermContext {
self.cmp(other, CmpNe, true) self.cmp(other, CmpNe, true)
} }
pub fn gt(&mut self, other: &mut TermContext) -> TermContext { pub fn gt(&self, other: &TermContext) -> TermContext {
self.cmp(other, CmpGt, false) self.cmp(other, CmpGt, false)
} }
pub fn ge(&mut self, other: &mut TermContext) -> TermContext { pub fn ge(&self, other: &TermContext) -> TermContext {
self.cmp(other, CmpGe, false) self.cmp(other, CmpGe, false)
} }
pub fn lt(&mut self, other: &mut TermContext) -> TermContext { pub fn lt(&self, other: &TermContext) -> TermContext {
self.cmp(other, CmpLt, false) self.cmp(other, CmpLt, false)
} }
pub fn le(&mut self, other: &mut TermContext) -> TermContext { pub fn le(&self, other: &TermContext) -> TermContext {
self.cmp(other, CmpLe, false) self.cmp(other, CmpLe, false)
} }
pub fn and(&mut self, other: &mut TermContext) -> TermContext { pub fn and(&self, other: &TermContext) -> TermContext {
self.cmp_cond(other, CmpCondType::And) self.cmp_cond(other, CmpCondType::And)
} }
pub fn or(&mut self, other: &mut TermContext) -> TermContext { pub fn or(&self, other: &TermContext) -> TermContext {
self.cmp_cond(other, CmpCondType::Or) self.cmp_cond(other, CmpCondType::Or)
} }
} }

View File

@ -1,29 +1,28 @@
use core::borrow::Borrow;
use std::error::Error; use std::error::Error;
use std::rc::Rc;
use std::result; use std::result;
use ref_value::*;
use serde_json::Value; use serde_json::Value;
use super::parser::*; use super::parser::*;
use super::term::*; use super::term::*;
use super::value_wrapper::*; use super::value_wrapper::*;
trait ArrayIndex { trait ArrayIndex {
fn index(&self, v: &Value) -> usize; fn index(&self, v: &RefValueWrapper) -> usize;
fn take_value(&self, v: &mut Value) -> Value { fn take_value(&self, v: &RefValueWrapper) -> RefValueWrapper {
let idx = self.index(v); let idx = self.index(v);
match v.get_mut(idx) { match v.get(idx) {
Some(v) => v.take(), Some(v) => v,
_ => Value::Null _ => RefValue::Null.into()
} }
} }
} }
impl ArrayIndex for f64 { impl ArrayIndex for f64 {
fn index(&self, v: &Value) -> usize { fn index(&self, v: &RefValueWrapper) -> usize {
if v.is_array() && self < &0_f64 { if v.is_array() && self < &0_f64 {
(v.as_array().unwrap().len() as f64 + self) as usize (v.as_array().unwrap().len() as f64 + self) as usize
} else { } else {
@ -33,7 +32,7 @@ impl ArrayIndex for f64 {
} }
impl ArrayIndex for isize { impl ArrayIndex for isize {
fn index(&self, v: &Value) -> usize { fn index(&self, v: &RefValueWrapper) -> usize {
if v.is_array() && self < &0_isize { if v.is_array() && self < &0_isize {
(v.as_array().unwrap().len() as isize + self) as usize (v.as_array().unwrap().len() as isize + self) as usize
} else { } else {
@ -43,7 +42,7 @@ impl ArrayIndex for isize {
} }
impl ArrayIndex for usize { impl ArrayIndex for usize {
fn index(&self, _: &Value) -> usize { fn index(&self, _: &RefValueWrapper) -> usize {
*self as usize *self as usize
} }
} }
@ -63,54 +62,55 @@ pub struct ValueFilter {
} }
impl ValueFilter { impl ValueFilter {
pub fn new(v: Value, is_leaves: bool, filter_mode: bool) -> Self { pub fn new(v: RefValueWrapper, is_leaves: bool, filter_mode: bool) -> Self {
ValueFilter { vw: ValueWrapper::new(v, is_leaves), last_key: None, filter_mode } ValueFilter { vw: ValueWrapper::new(v, is_leaves), last_key: None, filter_mode }
} }
fn iter_to_value_vec<'a, I: Iterator<Item=&'a mut Value>>(iter: I) -> Vec<Value> { fn iter_to_value_vec<'a, I: Iterator<Item=&'a TypeRefValue>>(iter: I) -> Vec<TypeRefValue> {
iter.map(|v| v.take()) iter
.map(|v| v.clone())
.filter(|v| !v.is_null()) .filter(|v| !v.is_null())
.collect() .collect()
} }
fn get_nested_array<F: ArrayIndex>(v: &mut Value, key: F, filter_mode: bool) -> Value { fn get_nested_array<F: ArrayIndex>(v: &RefValueWrapper, key: F, filter_mode: bool) -> RefValueWrapper {
if v.is_array() && v.as_array().unwrap().get(key.index(v)).is_some() { if v.is_array() && v.as_array().unwrap().get(key.index(v)).is_some() {
if filter_mode { if filter_mode {
v.take() v.clone()
} else { } else {
let idx = key.index(v); let idx = key.index(v);
v.get_mut(idx).unwrap().take() v.get(idx).unwrap().clone()
} }
} else { } else {
key.take_value(v) key.take_value(v)
} }
} }
fn get_nested_object(v: &mut Value, key: &String, filter_mode: bool) -> Value { fn get_nested_object(v: &RefValueWrapper, key: &String, filter_mode: bool) -> RefValueWrapper {
if v.is_object() && v.as_object().unwrap().contains_key(key) { if v.is_object() && v.as_object().unwrap().contains_key(key) {
if filter_mode { if filter_mode {
v.take() v.clone()
} else { } else {
v.get_mut(key).unwrap().take() v.get(key.clone()).unwrap().clone()
} }
} else { } else {
Value::Null RefValue::Null.into()
} }
} }
fn collect_all(key: Option<&String>, v: &Value, buf: &mut Vec<Value>) { fn collect_all(key: Option<&String>, v: &RefValueWrapper, buf: &mut Vec<TypeRefValue>) {
match v { match v.get_data_ref() {
Value::Array(vec) => { RefValue::Array(vec) => {
if key.is_none() { if key.is_none() {
for v in vec { for v in vec {
buf.push(v.clone()); buf.push(v.clone());
} }
} }
for i in vec { for i in vec {
Self::collect_all(key, &i, buf); Self::collect_all(key, &i.into(), buf);
} }
} }
Value::Object(v) => { RefValue::Object(v) => {
for (k, v) in v.into_iter() { for (k, v) in v.into_iter() {
if match key { if match key {
Some(map_key) => map_key == k, Some(map_key) => map_key == k,
@ -120,7 +120,7 @@ impl ValueFilter {
} }
} }
for (_, v) in v.into_iter() { for (_, v) in v.into_iter() {
Self::collect_all(key, &v, buf); Self::collect_all(key, &v.into(), buf);
} }
} }
_ => {} _ => {}
@ -133,7 +133,7 @@ impl ValueFilter {
Self::collect_all(None, &self.vw.get_val(), &mut buf); Self::collect_all(None, &self.vw.get_val(), &mut buf);
trace!("step_leaves_all - {:?}", buf); trace!("step_leaves_all - {:?}", buf);
self.last_key = Some(ValueFilterKey::All); self.last_key = Some(ValueFilterKey::All);
self.vw = ValueWrapper::new(Value::Array(buf), true); self.vw = ValueWrapper::new(RefValue::Array(buf).into(), true);
&self.vw &self.vw
} }
@ -143,53 +143,63 @@ impl ValueFilter {
pub fn step_leaves_string(&mut self, key: &String) -> &ValueWrapper { pub fn step_leaves_string(&mut self, key: &String) -> &ValueWrapper {
debug!("step_leaves_string"); debug!("step_leaves_string");
let mut buf: Vec<Value> = Vec::new(); let mut buf = Vec::new();
Self::collect_all(Some(key), &self.vw.get_val(), &mut buf); Self::collect_all(Some(key), &self.vw.get_val(), &mut buf);
trace!("step_leaves_string - {:?}", buf); trace!("step_leaves_string - {:?}", buf);
self.last_key = Some(ValueFilterKey::String(key.clone())); self.last_key = Some(ValueFilterKey::String(key.clone()));
self.vw = ValueWrapper::new(Value::Array(buf), true); self.vw = ValueWrapper::new(RefValue::Array(buf).into(), true);
&self.vw &self.vw
} }
pub fn step_in_all(&mut self) -> &ValueWrapper { pub fn step_in_all(&mut self) -> &ValueWrapper {
debug!("step_in_all"); debug!("step_in_all");
let vec = match &mut self.vw.get_val_mut() { let vec = match self.vw.get_val().get_data_ref() {
Value::Object(map) => Self::iter_to_value_vec(map.values_mut()), RefValue::Object(ref map) => {
Value::Array(list) => Self::iter_to_value_vec(list.iter_mut()), Self::iter_to_value_vec(map.values())
Value::Null => Vec::new(), }
other => vec![other.take()] RefValue::Array(ref list) => {
Self::iter_to_value_vec(list.iter())
}
RefValue::Null => Vec::new(),
_ => vec![self.vw.get_val().clone_data()]
}; };
self.last_key = Some(ValueFilterKey::All); self.last_key = Some(ValueFilterKey::All);
self.vw.replace(Value::Array(vec)); self.vw.replace(RefValue::Array(vec).into());
trace!("step_in_all - {:?}", self.vw.get_val()); trace!("step_in_all - {:?}", self.vw.get_val().get_data_ref());
&self.vw &self.vw
} }
pub fn step_in_num(&mut self, key: &f64) -> &ValueWrapper { pub fn step_in_num(&mut self, key: &f64) -> &ValueWrapper {
debug!("step_in_num"); debug!("step_in_num");
trace!("step_in_num - before: leaves {}, filterMode {} - {:?}", self.vw.is_leaves(), self.filter_mode, self.vw.get_val()); trace!("step_in_num - before: leaves {}, filterMode {} - {:?}"
, self.vw.is_leaves()
, self.filter_mode
, self.vw.get_val().get_data_ref());
let v = if self.vw.is_leaves() { let v = if self.vw.is_leaves() {
let filter_mode = self.filter_mode; let filter_mode = self.filter_mode;
match &mut self.vw.get_val_mut() { match self.vw.get_val().get_data_ref() {
Value::Array(v) => { RefValue::Array(ref vec) => {
let vec: Vec<Value> = v.iter_mut() let mut ret = Vec::new();
.map(|v| Self::get_nested_array(v, *key, filter_mode)) for v in vec {
.filter(|v| !v.is_null()) let wrapper = Self::get_nested_array(&v.into(), *key, filter_mode);
.collect(); if !wrapper.is_null() {
Value::Array(vec) ret.push(wrapper.clone_data());
}
}
RefValue::Array(ret).into()
} }
other => key.take_value(other) _ => key.take_value(&self.vw.get_val())
} }
} else { } else {
key.take_value(self.vw.get_val_mut()) key.take_value(&self.vw.get_val())
}; };
self.last_key = Some(ValueFilterKey::Num(key.index(&v))); self.last_key = Some(ValueFilterKey::Num(key.index(&v)));
self.vw.replace(v); self.vw.replace(v);
trace!("step_in_num - after: {:?}", self.vw.get_val()); trace!("step_in_num - after: {:?}", self.vw.get_val().get_data_ref());
&self.vw &self.vw
} }
@ -199,55 +209,68 @@ impl ValueFilter {
pub fn step_in_string(&mut self, key: &String) -> &ValueWrapper { pub fn step_in_string(&mut self, key: &String) -> &ValueWrapper {
debug!("step_in_string"); debug!("step_in_string");
trace!("step_in_string - before: {},{},{:?}", self.vw.is_leaves(), self.filter_mode, self.vw.get_val()); trace!("step_in_string - before: {},{},{:?}"
, self.vw.is_leaves()
, self.filter_mode
, self.vw.get_val().get_data_ref());
let filter_mode = self.filter_mode; let filter_mode = self.filter_mode;
let is_leaves = self.vw.is_leaves(); let is_leaves = self.vw.is_leaves();
let v = match &mut self.vw.get_val_mut() { let val = match self.vw.get_val().get_data_ref() {
Value::Array(ref mut vec) if is_leaves => { RefValue::Array(ref vec) if is_leaves => {
let mut buf = Vec::new(); let mut buf = Vec::new();
for mut item in vec { for mut v in vec {
if let Value::Array(v) = item { let wrapper: RefValueWrapper = v.into();
let mut ret: Vec<Value> = v.iter_mut() if wrapper.is_array() {
.map(|v| Self::get_nested_object(v, key, filter_mode)) let vec = wrapper.as_array().unwrap();
.filter(|v| !v.is_null()) let mut ret = Vec::new();
.collect(); for v in vec {
let nested_wrapper = Self::get_nested_object(&v.into(), key, filter_mode);
if !nested_wrapper.is_null() {
ret.push(nested_wrapper.clone_data());
}
}
buf.append(&mut ret); buf.append(&mut ret);
} else { } else {
match item.get_mut(key) { match wrapper.get(key.clone()) {
Some(v) => buf.push(v.take()), Some(v) => buf.push(v.clone_data()),
_ => {} _ => {}
} }
} }
} }
Value::Array(buf) RefValue::Array(buf).into()
} }
Value::Array(v) if !is_leaves => { RefValue::Array(ref vec) if !is_leaves => {
let vec: Vec<Value> = v.iter_mut() let mut ret = Vec::new();
.map(|v| Self::get_nested_object(v, key, filter_mode)) for v in vec {
.filter(|v| !v.is_null()) let wrapper = Self::get_nested_object(&v.into(), key, filter_mode);
.collect(); if !wrapper.is_null() {
ret.push(wrapper.clone_data());
Value::Array(vec) }
}
RefValue::Array(ret).into()
} }
other => { _ => {
match other.get_mut(key) { match self.vw.get_val().get(key.clone()) {
Some(v) => v.take(), Some(v) => v.clone(),
_ => Value::Null _ => RefValue::Null.into()
} }
} }
}; };
self.last_key = Some(ValueFilterKey::String(key.clone())); self.last_key = Some(ValueFilterKey::String(key.clone()));
self.vw.replace(v); self.vw.replace(val);
trace!("step_in_string - after: {},{},{:?}", self.vw.is_leaves(), self.filter_mode, self.vw.get_val()); trace!("step_in_string - after: {},{},{:?}"
, self.vw.is_leaves()
, self.filter_mode
, self.vw.get_val().get_data_ref());
&self.vw &self.vw
} }
} }
pub struct JsonValueFilter { pub struct JsonValueFilter {
json: Rc<Box<Value>>, json: RefValueWrapper,
filter_stack: Vec<ValueFilter>, filter_stack: Vec<ValueFilter>,
token_stack: Vec<ParseToken>, token_stack: Vec<ParseToken>,
term_stack: Vec<TermContext>, term_stack: Vec<TermContext>,
@ -257,12 +280,12 @@ impl JsonValueFilter {
pub fn new(json: &str) -> result::Result<Self, String> { pub fn new(json: &str) -> result::Result<Self, String> {
let json: Value = serde_json::from_str(json) let json: Value = serde_json::from_str(json)
.map_err(|e| e.description().to_string())?; .map_err(|e| e.description().to_string())?;
Ok(JsonValueFilter::new_from_value(Rc::new(Box::new(json)))) Ok(JsonValueFilter::new_from_value(json.into()))
} }
pub fn new_from_value(json: Rc<Box<Value>>) -> Self { pub fn new_from_value(json: RefValueWrapper) -> Self {
JsonValueFilter { JsonValueFilter {
json: json, json,
filter_stack: Vec::new(), filter_stack: Vec::new(),
token_stack: Vec::new(), token_stack: Vec::new(),
term_stack: Vec::new(), term_stack: Vec::new(),
@ -287,14 +310,13 @@ impl JsonValueFilter {
Some(self.filter_stack.push(vf)) Some(self.filter_stack.push(vf))
}); });
} else { } else {
let v: &Value = self.json.as_ref().borrow();
self.filter_stack.push({ self.filter_stack.push({
ValueFilter::new(v.clone(), false, from_current) ValueFilter::new(self.json.clone(), false, from_current)
}); });
} }
} }
fn replace_filter_stack(&mut self, v: Value, is_leaves: bool) { fn replace_filter_stack(&mut self, v: RefValueWrapper, is_leaves: bool) {
if self.filter_stack.is_empty() { if self.filter_stack.is_empty() {
self.filter_stack.push(ValueFilter::new(v, is_leaves, false)); self.filter_stack.push(ValueFilter::new(v, is_leaves, false));
} else { } else {
@ -312,17 +334,17 @@ impl JsonValueFilter {
} }
} }
pub fn current_value(&self) -> &Value { pub fn current_value(&self) -> RefValueWrapper {
match self.filter_stack.last() { match self.filter_stack.last() {
Some(v) => &v.vw.get_val(), Some(v) => v.vw.get_val().clone(),
_ => &Value::Null _ => RefValue::Null.into()
} }
} }
pub fn take_value(&mut self) -> Value { pub fn take_value(&mut self) -> RefValueWrapper {
match self.filter_stack.last_mut() { match self.filter_stack.last_mut() {
Some(v) => v.vw.get_val_mut().take(), Some(v) => v.vw.get_val().clone(),
_ => Value::Null _ => RefValue::Null.into()
} }
} }
@ -331,25 +353,28 @@ impl JsonValueFilter {
match self.filter_stack.last_mut() { match self.filter_stack.last_mut() {
Some(ref mut vf) if vf.vw.is_array() && vf.vw.is_leaves() => { Some(ref mut vf) if vf.vw.is_array() && vf.vw.is_leaves() => {
if let Value::Array(mut val) = vf.vw.get_val_mut().take() { let mut ret = Vec::new();
let mut ret = Vec::new(); if let RefValue::Array(val) = vf.vw.get_val().get_data_ref() {
for mut v in &mut val { for mut v in val {
for i in &indices { for i in &indices {
let v = i.take_value(v); let v = i.take_value(&v.into());
if !v.is_null() { if !v.is_null() {
ret.push(v); ret.push(v.clone_data());
} }
} }
} }
vf.vw.replace(Value::Array(ret));
} }
vf.vw.replace(RefValue::Array(ret).into());
} }
Some(ref mut vf) if vf.vw.is_array() && !vf.vw.is_leaves() => { Some(ref mut vf) if vf.vw.is_array() && !vf.vw.is_leaves() => {
let ret = indices.into_iter() let mut ret = Vec::new();
.map(|i| i.take_value(vf.vw.get_val_mut())) for i in indices {
.filter(|v| !v.is_null()) let wrapper = i.take_value(&vf.vw.get_val());
.collect(); if !wrapper.is_null() {
vf.vw.replace(Value::Array(ret)); ret.push(wrapper.clone_data());
}
}
vf.vw.replace(RefValue::Array(ret).into());
} }
_ => {} _ => {}
} }
@ -358,43 +383,51 @@ impl JsonValueFilter {
fn token_range(&mut self, from: Option<isize>, to: Option<isize>) { fn token_range(&mut self, from: Option<isize>, to: Option<isize>) {
self.token_stack.pop(); self.token_stack.pop();
fn _from_to<F: ArrayIndex>(from: Option<F>, to: Option<F>, val: &Value) -> (usize, usize) { fn _from_to<F: ArrayIndex>(from: Option<F>, to: Option<F>, val: &RefValueWrapper) -> (usize, usize) {
let from = match from { let from = match from {
Some(v) => v.index(val), Some(v) => v.index(val),
_ => 0 _ => 0
}; };
let to = match to { let to = match to {
Some(v) => v.index(val), Some(v) => v.index(val),
_ => if let Value::Array(v) = val { v.len() } else { 0 } _ => {
if let RefValue::Array(v) = val.get_data_ref() {
v.len()
} else {
0
}
}
}; };
(from, to) (from, to)
} }
fn _range(from: usize, to: usize, v: &mut Value) -> Vec<Value> { fn _range(from: usize, to: usize, v: &RefValueWrapper) -> Vec<TypeRefValue> {
trace!("range - {}:{}", from, to); trace!("range - {}:{}", from, to);
(from..to).into_iter() (from..to).into_iter()
.map(|i| i.take_value(v)) .map(|i| i.take_value(v))
.filter(|v| !v.is_null()) .filter(|v| !v.is_null())
.map(|v| v.clone_data())
.collect() .collect()
} }
match self.filter_stack.last_mut() { match self.filter_stack.last_mut() {
Some(ref mut vf) if vf.vw.is_array() && vf.vw.is_leaves() => { Some(ref mut vf) if vf.vw.is_array() && vf.vw.is_leaves() => {
if let Value::Array(mut vec) = vf.vw.get_val_mut().take() { let mut buf = Vec::new();
let mut buf = Vec::new(); if let RefValue::Array(vec) = vf.vw.get_val().get_data_ref() {
for mut item in &mut vec { for mut v in vec {
let (from, to) = _from_to(from, to, item); let wrapper = v.into();
let mut v: Vec<Value> = _range(from, to, item); let (from, to) = _from_to(from, to, &wrapper);
let mut v: Vec<TypeRefValue> = _range(from, to, &wrapper);
buf.append(&mut v); buf.append(&mut v);
} }
vf.vw.replace(Value::Array(buf));
} }
vf.vw.replace(RefValue::Array(buf).into());
} }
Some(ref mut vf) if vf.vw.is_array() && !vf.vw.is_leaves() => { Some(ref mut vf) if vf.vw.is_array() && !vf.vw.is_leaves() => {
let (from, to) = _from_to(from, to, vf.vw.get_val()); let (from, to) = _from_to(from, to, &vf.vw.get_val());
let v: Vec<Value> = _range(from, to, vf.vw.get_val_mut()); let vec: Vec<TypeRefValue> = _range(from, to, vf.vw.get_val());
vf.vw.replace(Value::Array(v)); vf.vw.replace(RefValue::Array(vec).into());
} }
_ => {} _ => {}
} }
@ -449,19 +482,19 @@ impl JsonValueFilter {
_ => {} _ => {}
} }
} }
Some(TermContext::Json(_, mut vw)) => { Some(TermContext::Json(_, vw)) => {
self.replace_filter_stack(vw.get_val_mut().take(), vw.is_leaves()); self.replace_filter_stack(vw.get_val().clone(), vw.is_leaves());
} }
_ => { _ => {
match self.filter_stack.pop() { match self.filter_stack.pop() {
Some(mut vf) => { Some(mut vf) => {
let is_leaves = vf.vw.is_leaves(); let is_leaves = vf.vw.is_leaves();
match vf.vw.get_val_mut() { match vf.vw.get_val().get_data_ref() {
Value::Null | Value::Bool(false) => { RefValue::Null | RefValue::Bool(false) => {
self.replace_filter_stack(Value::Null, is_leaves); self.replace_filter_stack(RefValue::Null.into(), is_leaves);
} }
other => { _ => {
self.replace_filter_stack(other.take(), is_leaves); self.replace_filter_stack(vf.vw.get_val().clone(), is_leaves);
} }
} }
} }
@ -479,18 +512,18 @@ impl JsonValueFilter {
trace!("right {:?}", right); trace!("right {:?}", right);
if left.is_some() && right.is_some() { if left.is_some() && right.is_some() {
let mut left = left.unwrap(); let left = left.unwrap();
let mut right = right.unwrap(); let right = right.unwrap();
let tc = match ft { let tc = match ft {
FilterToken::Equal => left.eq(&mut right), FilterToken::Equal => left.eq(&right),
FilterToken::NotEqual => left.ne(&mut right), FilterToken::NotEqual => left.ne(&right),
FilterToken::Greater => left.gt(&mut right), FilterToken::Greater => left.gt(&right),
FilterToken::GreaterOrEqual => left.ge(&mut right), FilterToken::GreaterOrEqual => left.ge(&right),
FilterToken::Little => left.lt(&mut right), FilterToken::Little => left.lt(&right),
FilterToken::LittleOrEqual => left.le(&mut right), FilterToken::LittleOrEqual => left.le(&right),
FilterToken::And => left.and(&mut right), FilterToken::And => left.and(&right),
FilterToken::Or => left.or(&mut right), FilterToken::Or => left.or(&right),
}; };
self.term_stack.push(tc); self.term_stack.push(tc);
} }

View File

@ -1,6 +1,5 @@
use indexmap::map::IndexMap; use indexmap::map::IndexMap;
use ref_value::*;
use serde_json::Value;
use super::cmp::*; use super::cmp::*;
use super::term::*; use super::term::*;
@ -8,12 +7,12 @@ use super::value_filter::*;
#[derive(Debug)] #[derive(Debug)]
pub struct ValueWrapper { pub struct ValueWrapper {
val: Value, val: RefValueWrapper,
is_leaves: bool, is_leaves: bool,
} }
impl ValueWrapper { impl ValueWrapper {
pub fn new(val: Value, leaves: bool) -> Self { pub fn new(val: RefValueWrapper, leaves: bool) -> Self {
ValueWrapper { val, is_leaves: leaves } ValueWrapper { val, is_leaves: leaves }
} }
@ -25,7 +24,7 @@ impl ValueWrapper {
self.is_leaves = is_leaves; self.is_leaves = is_leaves;
} }
pub fn cmp(&mut self, other: &mut ValueWrapper, cmp_type: CmpType) -> TermContext { pub fn cmp(&self, other: &ValueWrapper, cmp_type: CmpType) -> TermContext {
match cmp_type { match cmp_type {
CmpType::Eq => { CmpType::Eq => {
TermContext::Json(None, self.intersect(other)) TermContext::Json(None, self.intersect(other))
@ -39,24 +38,19 @@ impl ValueWrapper {
} }
} }
fn cmp_with_term<F: PrivCmp>(val: &Value, et: &ExprTerm, cmp_fn: &F, default: bool, reverse: bool) -> bool { fn cmp_with_term<F: PrivCmp>(val: &RefValueWrapper, et: &ExprTerm, cmp_fn: &F, default: bool, reverse: bool) -> bool {
match val { match val.get_data_ref() {
Value::Bool(ref v1) => { RefValue::Bool(ref v1) => {
match et { match et {
ExprTerm::Bool(v2) => if reverse { cmp_fn.cmp_bool(v2, v1) } else { cmp_fn.cmp_bool(v1, v2) }, ExprTerm::Bool(v2) => if reverse { cmp_fn.cmp_bool(v2, v1) } else { cmp_fn.cmp_bool(v1, v2) },
_ => default _ => default
} }
} }
Value::Number(ref v1) => match v1.as_f64() { RefValue::Number(ref v1) => match et {
Some(ref v1) => { ExprTerm::Number(v2) => if reverse { cmp_fn.cmp_f64(v2, &v1.as_f64().unwrap()) } else { cmp_fn.cmp_f64(&v1.as_f64().unwrap(), v2) },
match et {
ExprTerm::Number(v2) => if reverse { cmp_fn.cmp_f64(v2, v1) } else { cmp_fn.cmp_f64(v1, v2) },
_ => default
}
}
_ => default _ => default
}, },
Value::String(ref v1) => { RefValue::String(ref v1) => {
match et { match et {
ExprTerm::String(v2) => if reverse { cmp_fn.cmp_string(v2, v1) } else { cmp_fn.cmp_string(v1, v2) }, ExprTerm::String(v2) => if reverse { cmp_fn.cmp_string(v2, v1) } else { cmp_fn.cmp_string(v1, v2) },
_ => default _ => default
@ -66,12 +60,12 @@ impl ValueWrapper {
} }
} }
fn take_object_in_array<F: PrivCmp>(&mut self, key: &String, et: &ExprTerm, cmp: &F, reverse: bool) -> Option<Self> { fn take_object_in_array<F: PrivCmp>(&self, key: &String, et: &ExprTerm, cmp: &F, reverse: bool) -> Option<Self> {
fn _filter_with_object<F: Fn(&Value) -> bool>(v: &&mut Value, key: &String, fun: F) -> bool { fn _filter_with_object<F: Fn(&RefValueWrapper) -> bool>(v: &RefValueWrapper, key: &String, fun: F) -> bool {
match &v { match v.get_data_ref() {
Value::Object(map) => { RefValue::Object(map) => {
match map.get(key) { match map.get(key) {
Some(vv) => fun(vv), Some(val) => fun(&val.into()),
_ => false _ => false
} }
} }
@ -79,21 +73,24 @@ impl ValueWrapper {
} }
} }
match self.val.take() { match self.val.get_data_ref() {
Value::Array(mut vec) => { RefValue::Array(vec) => {
let mut ret: Vec<Value> = vec.iter_mut() let mut ret = Vec::new();
.filter(|v| { for v in vec {
_filter_with_object(v, key, |vv| Self::cmp_with_term(vv, et, cmp, false, reverse)) if _filter_with_object(&v.into(), key, |vv| {
}) Self::cmp_with_term(vv, et, cmp, false, reverse)
.map(|v| v.take()) }) {
.collect(); ret.push(v.clone());
Some(ValueWrapper::new(Value::Array(ret), false)) }
}
Some(ValueWrapper::new(RefValue::Array(ret).into(), false))
} }
_ => None _ => None
} }
} }
fn take_with_key_type<F: PrivCmp>(&mut self, key: &Option<ValueFilterKey>, et: &ExprTerm, cmp: &F, reverse: bool) -> Option<Self> { fn take_with_key_type<F: PrivCmp>(&self, key: &Option<ValueFilterKey>, et: &ExprTerm, cmp: &F, reverse: bool) -> Option<Self> {
match key { match key {
Some(ValueFilterKey::String(key)) => { Some(ValueFilterKey::String(key)) => {
self.take_object_in_array(key, et, cmp, reverse) self.take_object_in_array(key, et, cmp, reverse)
@ -102,23 +99,25 @@ impl ValueWrapper {
} }
} }
pub fn take_with<F: PrivCmp>(&mut self, key: &Option<ValueFilterKey>, et: &ExprTerm, cmp: F, reverse: bool) -> Self { pub fn take_with<F: PrivCmp>(&self, key: &Option<ValueFilterKey>, et: &ExprTerm, cmp: F, reverse: bool) -> Self {
match self.take_with_key_type(key, et, &cmp, reverse) { match self.take_with_key_type(key, et, &cmp, reverse) {
Some(vw) => vw, Some(vw) => vw,
_ => { _ => {
match self.val.take() { match self.val.get_data_ref() {
Value::Array(mut vec) => { RefValue::Array(vec) => {
let mut ret = vec.iter_mut() let mut ret = Vec::new();
.filter(|v| Self::cmp_with_term(&v, et, &cmp, false, reverse)) for v in vec {
.map(|v| v.take()) if Self::cmp_with_term(&v.into(), et, &cmp, false, reverse) {
.collect(); ret.push(v.clone());
ValueWrapper::new(Value::Array(ret), false) }
}
ValueWrapper::new(RefValue::Array(ret).into(), false)
} }
other => { _ => {
if Self::cmp_with_term(&other, et, &cmp, false, reverse) { if Self::cmp_with_term(&self.val, et, &cmp, false, reverse) {
ValueWrapper::new(other, false) ValueWrapper::new(self.val.clone(), false)
} else { } else {
ValueWrapper::new(Value::Null, false) ValueWrapper::new(RefValue::Null.into(), false)
} }
} }
} }
@ -126,24 +125,25 @@ impl ValueWrapper {
} }
} }
pub fn replace(&mut self, val: Value) { pub fn replace(&mut self, val: RefValueWrapper) {
let is_null = match &val { let is_null = match val.get_data_ref() {
Value::Array(v) => if v.is_empty() { true } else { false }, RefValue::Array(v) => if v.is_empty() { true } else { false },
Value::Object(m) => if m.is_empty() { true } else { false }, RefValue::Object(m) => if m.is_empty() { true } else { false },
_ => val.is_null() _ => val.is_null()
}; };
self.val = if is_null { Value::Null } else { val }; self.val = if is_null {
let v = RefValueWrapper::wrap(RefValue::Null);
RefValueWrapper::new(v)
} else {
val
};
} }
pub fn get_val(&self) -> &Value { pub fn get_val(&self) -> &RefValueWrapper {
&self.val &self.val
} }
pub fn get_val_mut(&mut self) -> &mut Value { pub fn clone_val(&self) -> RefValueWrapper {
&mut self.val
}
pub fn clone_val(&self) -> Value {
self.val.clone() self.val.clone()
} }
@ -151,150 +151,161 @@ impl ValueWrapper {
self.val.is_array() self.val.is_array()
} }
fn uuid(v: &Value) -> String { fn uuid(v: &RefValueWrapper) -> String {
fn _fn(v: &Value) -> String { fn _fn(v: &RefValueWrapper, acc: &mut String) {
match v { match v.get_data_ref() {
Value::Null => "null".to_string(), RefValue::Null => acc.push_str("null"),
Value::String(v) => v.to_string(), RefValue::String(v) => acc.push_str(v),
Value::Bool(v) => v.to_string(), RefValue::Bool(v) => acc.push_str(if *v { "true" } else { "false" }),
Value::Number(v) => v.to_string(), RefValue::Number(v) => acc.push_str(&*v.to_string()),
Value::Array(v) => { RefValue::Array(v) => {
v.iter().enumerate() for (i, v) in v.iter().enumerate() {
.map(|(i, v)| { format!("{}{}", i, _fn(v)) }) acc.push_str(&*i.to_string());
.collect() _fn(&v.into(), acc);
}
} }
Value::Object(v) => { RefValue::Object(ref v) => {
v.into_iter().map(|(k, v)| { format!("{}{}", k, _fn(v)) }).collect() for (k, v) in v.into_iter() {
acc.push_str(&*k.to_string());
_fn(&v.into(), acc);
}
} }
} }
} }
_fn(v) let mut acc = String::new();
_fn(v, &mut acc);
acc
} }
fn into_map(&mut self) -> IndexMap<String, Value> { fn into_map(&self) -> IndexMap<String, RefValueWrapper> {
let mut map = IndexMap::new(); let mut map = IndexMap::new();
match &mut self.val { match self.val.get_data_ref() {
Value::Array(v1) => { RefValue::Array(ref v1) => {
for v in v1 { for v in v1 {
map.insert(Self::uuid(v), v.take()); let wrapper = v.into();
let key = Self::uuid(&wrapper);
map.insert(key, wrapper);
} }
} }
other => { _ => {
map.insert(Self::uuid(other), other.take()); map.insert(Self::uuid(&self.val), self.val.clone());
} }
} }
map map
} }
pub fn except(&mut self, other: &mut Self) -> Self { pub fn except(&self, other: &Self) -> Self {
let map = self.into_map(); let map = self.into_map();
let mut ret: IndexMap<String, Value> = IndexMap::new(); let mut ret: IndexMap<String, RefValueWrapper> = IndexMap::new();
match &mut other.val { match other.val.get_data_ref() {
Value::Array(v1) => { RefValue::Array(ref v1) => {
for v in v1 { for v in v1 {
let key = Self::uuid(v); let wrapper = v.into();
let key = Self::uuid(&wrapper);
if !map.contains_key(&key) { if !map.contains_key(&key) {
ret.insert(key, v.take()); ret.insert(key, wrapper);
} }
} }
} }
other => { _ => {
let key = Self::uuid(other); let key = Self::uuid(&other.val);
if !map.contains_key(&key) { if !map.contains_key(&key) {
ret.insert(key, other.take()); ret.insert(key, other.val.clone());
} }
} }
} }
let v = ret.values_mut().into_iter().map(|v| v.take()).collect(); let vec = ret.values().into_iter().map(|v| v.clone_data()).collect();
ValueWrapper::new(v, false) ValueWrapper::new(RefValue::Array(vec).into(), false)
} }
pub fn intersect(&mut self, other: &mut Self) -> Self { pub fn intersect(&self, other: &Self) -> Self {
let map = self.into_map(); let map = self.into_map();
let mut ret: IndexMap<String, Value> = IndexMap::new(); let mut ret: IndexMap<String, RefValueWrapper> = IndexMap::new();
match &mut other.val { match other.val.get_data_ref() {
Value::Array(v1) => { RefValue::Array(ref v1) => {
for v in v1 { for v in v1 {
let key = Self::uuid(v); let wrapper = v.into();
let key = Self::uuid(&wrapper);
if map.contains_key(&key) { if map.contains_key(&key) {
ret.insert(key, v.take()); ret.insert(key, wrapper);
} }
} }
} }
other => { _ => {
let key = Self::uuid(other); let key = Self::uuid(&other.val);
if map.contains_key(&key) { if map.contains_key(&key) {
ret.insert(key, other.take()); ret.insert(key, other.val.clone());
} }
} }
} }
let v = ret.values_mut().into_iter().map(|v| v.take()).collect(); let vec = ret.values().into_iter().map(|v| v.clone_data()).collect();
ValueWrapper::new(v, false) ValueWrapper::new(RefValue::Array(vec).into(), false)
} }
pub fn union(&mut self, other: &mut Self) -> Self { pub fn union(&self, other: &Self) -> Self {
let mut map = self.into_map(); let mut map = self.into_map();
match &mut other.val { match other.val.get_data_ref() {
Value::Array(v1) => { RefValue::Array(ref v1) => {
for v in v1 { for v in v1 {
let key = Self::uuid(v); let wrapper = v.into();
let key = Self::uuid(&wrapper);
if !map.contains_key(&key) { if !map.contains_key(&key) {
map.insert(key, v.take()); map.insert(key, wrapper);
} }
} }
} }
other => { _ => {
let key = Self::uuid(other); let key = Self::uuid(&other.val);
if !map.contains_key(&key) { if !map.contains_key(&key) {
map.insert(key, other.take()); map.insert(key, other.val.clone());
} }
} }
} }
let mut vw = ValueWrapper::new(Value::Null, false); let mut vw = ValueWrapper::new(RefValue::Null.into(), false);
let list: Vec<Value> = map.values_mut().into_iter().map(|val| val.take()).collect(); let list = map.values().into_iter().map(|val| val.clone_data()).collect();
vw.replace(Value::Array(list)); vw.replace(RefValue::Array(list).into());
vw vw
} }
pub fn into_term(&mut self, key: &mut Option<ValueFilterKey>) -> TermContext { pub fn into_term(&self, key: &Option<ValueFilterKey>) -> TermContext {
match self.val.take() { match self.val.get_data_ref() {
Value::String(s) => TermContext::Constants(ExprTerm::String(s)), RefValue::String(ref s) => TermContext::Constants(ExprTerm::String(s.clone())),
Value::Number(n) => TermContext::Constants(ExprTerm::Number(n.as_f64().unwrap())), RefValue::Number(ref n) => TermContext::Constants(ExprTerm::Number(n.as_f64().unwrap())),
Value::Bool(b) => TermContext::Constants(ExprTerm::Bool(b)), RefValue::Bool(b) => TermContext::Constants(ExprTerm::Bool(*b)),
other => TermContext::Json(match key { _ => TermContext::Json(match key {
Some(vk) => Some(vk.clone()), Some(vk) => Some(vk.clone()),
_ => None _ => None
}, ValueWrapper::new(other, false)) }, ValueWrapper::new(self.val.clone(), false))
} }
} }
pub fn filter(&mut self, key: &mut Option<ValueFilterKey>) -> Self { pub fn filter(&self, key: &Option<ValueFilterKey>) -> Self {
let v = match &mut self.val { let v = match self.val.get_data_ref() {
Value::Array(vec) => { RefValue::Array(ref vec) => {
let ret = vec.iter_mut() let mut ret = Vec::new();
.filter(|v| match key { for v in vec {
Some(ValueFilterKey::String(val_key)) => { if let Some(ValueFilterKey::String(k)) = key {
v.get(val_key.as_str()).is_some() let wrapper: RefValueWrapper = v.into();
if wrapper.get(k.clone()).is_some() {
ret.push(v.clone());
} }
_ => false }
}) }
.map(|v| v.take()) RefValue::Array(ret).into()
.collect();
Value::Array(ret)
} }
Value::Object(map) => { RefValue::Object(ref map) => {
match key { match key {
Some(ValueFilterKey::String(val_key)) => match map.get_mut(val_key) { Some(ValueFilterKey::String(k)) => match map.get(k) {
Some(v) => v.take(), Some(v) => v.into(),
_ => Value::Null _ => RefValue::Null.into()
}, },
_ => Value::Null _ => RefValue::Null.into()
} }
} }
other => other.take() _ => self.val.clone()
}; };
ValueWrapper::new(v, false) ValueWrapper::new(v, false)

View File

@ -43,26 +43,26 @@
//! "expensive": 10 //! "expensive": 10
//! }); //! });
//! //!
//! let mut reader = jsonpath::reader(json_obj); //! let mut selector = jsonpath::selector(json_obj);
//! //!
//! // //! //
//! // $.store.book[*].author //! // $.store.book[*].author
//! // //! //
//! let json = reader("$.store.book[*].author").unwrap(); //! let json = selector("$.store.book[*].author").unwrap();
//! let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]); //! let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]);
//! assert_eq!(json, ret); //! assert_eq!(json, ret);
//! //!
//! // //! //
//! // $..author //! // $..author
//! // //! //
//! let json = reader("$..author").unwrap(); //! let json = selector("$..author").unwrap();
//! let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]); //! let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]);
//! assert_eq!(json, ret); //! assert_eq!(json, ret);
//! //!
//! // //! //
//! // $.store.* //! // $.store.*
//! // //! //
//! let json = reader("$.store.*").unwrap(); //! let json = selector("$.store.*").unwrap();
//! let ret = json!([ //! let ret = json!([
//! [ //! [
//! {"category" : "reference", "author" : "Nigel Rees","title" : "Sayings of the Century", "price" : 8.95}, //! {"category" : "reference", "author" : "Nigel Rees","title" : "Sayings of the Century", "price" : 8.95},
@ -77,14 +77,14 @@
//! // //! //
//! // $.store..price //! // $.store..price
//! // //! //
//! let json = reader("$.store..price").unwrap(); //! let json = selector("$.store..price").unwrap();
//! let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]); //! let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]);
//! assert_eq!(ret, json); //! assert_eq!(ret, json);
//! //!
//! // //! //
//! // $..book[2] //! // $..book[2]
//! // //! //
//! let json = reader("$..book[2]").unwrap(); //! let json = selector("$..book[2]").unwrap();
//! let ret = json!([{ //! let ret = json!([{
//! "category" : "fiction", //! "category" : "fiction",
//! "author" : "Herman Melville", //! "author" : "Herman Melville",
@ -97,7 +97,7 @@
//! // //! //
//! // $..book[-2] //! // $..book[-2]
//! // //! //
//! let json = reader("$..book[-2]").unwrap(); //! let json = selector("$..book[-2]").unwrap();
//! let ret = json!([{ //! let ret = json!([{
//! "category" : "fiction", //! "category" : "fiction",
//! "author" : "Herman Melville", //! "author" : "Herman Melville",
@ -110,7 +110,7 @@
//! // //! //
//! // $..book[0,1] //! // $..book[0,1]
//! // //! //
//! let json = reader("$..book[0,1]").unwrap(); //! let json = selector("$..book[0,1]").unwrap();
//! let ret = json!([ //! let ret = json!([
//! {"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}, //! {"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95},
//! {"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99} //! {"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99}
@ -120,7 +120,7 @@
//! // //! //
//! // $..book[:2] //! // $..book[:2]
//! // //! //
//! let json = reader("$..book[:2]").unwrap(); //! let json = selector("$..book[:2]").unwrap();
//! let ret = json!([ //! let ret = json!([
//! {"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}, //! {"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95},
//! {"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99} //! {"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99}
@ -130,7 +130,7 @@
//! // //! //
//! // $..book[2:] //! // $..book[2:]
//! // //! //
//! let json = reader("$..book[2:]").unwrap(); //! let json = selector("$..book[2:]").unwrap();
//! let ret = json!([ //! let ret = json!([
//! {"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}, //! {"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99},
//! {"category" : "fiction","author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99} //! {"category" : "fiction","author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99}
@ -140,7 +140,7 @@
//! // //! //
//! // $..book[?(@.isbn)] //! // $..book[?(@.isbn)]
//! // //! //
//! let json = reader("$..book[?(@.isbn)]").unwrap(); //! let json = selector("$..book[?(@.isbn)]").unwrap();
//! let ret = json!([ //! let ret = json!([
//! {"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}, //! {"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99},
//! {"category" : "fiction","author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99} //! {"category" : "fiction","author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99}
@ -150,7 +150,7 @@
//! // //! //
//! // $.store.book[?(@.price < 10)] //! // $.store.book[?(@.price < 10)]
//! // //! //
//! let json = reader("$.store.book[?(@.price < 10)]").unwrap(); //! let json = selector("$.store.book[?(@.price < 10)]").unwrap();
//! let ret = json!([ //! let ret = json!([
//! {"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}, //! {"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95},
//! {"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99} //! {"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}
@ -175,14 +175,17 @@ extern crate indexmap;
pub mod parser; pub mod parser;
#[doc(hidden)] #[doc(hidden)]
pub mod filter; pub mod filter;
#[doc(hidden)]
pub mod ref_value;
use parser::parser::*; use parser::parser::*;
use filter::value_filter::*; use filter::value_filter::*;
use std::result; use std::result;
use std::rc::Rc;
use serde_json::Value; use serde_json::Value;
use ref_value::*;
type Result = result::Result<Value, String>; type Result = result::Result<Value, String>;
/// # Read multiple Json multiple times with the same JsonPath /// # Read multiple Json multiple times with the same JsonPath
@ -223,9 +226,9 @@ pub fn compile<'a>(path: &'a str) -> impl FnMut(Value) -> Result + 'a {
move |json| { move |json| {
match &node { match &node {
Ok(n) => { Ok(n) => {
let mut jf = JsonValueFilter::new_from_value(Rc::new(Box::new(json))); let mut jf = JsonValueFilter::new_from_value(json.into());
jf.visit(n.clone()); jf.visit(n.clone());
Ok(jf.take_value()) Ok(jf.take_value().into_value())
} }
Err(e) => Err(e.clone()) Err(e) => Err(e.clone())
} }
@ -246,26 +249,31 @@ pub fn compile<'a>(path: &'a str) -> impl FnMut(Value) -> Result + 'a {
/// "friends": [{"id": 0},{"id": 1}] /// "friends": [{"id": 0},{"id": 1}]
/// }); /// });
/// ///
/// let mut reader = jsonpath::reader(json_obj); /// let mut selector = jsonpath::selector(json_obj);
/// ///
/// let json = reader("$..friends[0]").unwrap(); /// let json = selector("$..friends[0]").unwrap();
/// let ret = json!([ {"id": 0}, {"id": 0} ]); /// let ret = json!([ {"id": 0}, {"id": 0} ]);
/// assert_eq!(json, ret); /// assert_eq!(json, ret);
/// ///
/// let json = reader("$..friends[1]").unwrap(); /// let json = selector("$..friends[1]").unwrap();
/// let ret = json!([ {"id": 1}, {"id": 1} ]); /// let ret = json!([ {"id": 1}, {"id": 1} ]);
/// assert_eq!(json, ret); /// assert_eq!(json, ret);
/// ``` /// ```
pub fn reader(json: Value) -> impl FnMut(&str) -> Result { pub fn selector(json: Value) -> impl FnMut(&str) -> Result {
let n = Rc::new(Box::new(json)); let wrapper: RefValueWrapper = json.into();
move |path: &str| { move |path: &str| {
let mut jf = JsonValueFilter::new_from_value(n.clone()); let mut jf = JsonValueFilter::new_from_value(wrapper.clone());
let mut parser = Parser::new(path); let mut parser = Parser::new(path);
parser.parse(&mut jf)?; parser.parse(&mut jf)?;
Ok(jf.take_value()) Ok(jf.take_value().into_value())
} }
} }
/// # Read the same Json multiple times using different JsonPath - Deprecated. use selector
pub fn reader(json: Value) -> impl FnMut(&str) -> Result {
selector(json)
}
/// # Read Json using JsonPath /// # Read Json using JsonPath
/// ///
/// ```rust /// ```rust
@ -278,15 +286,20 @@ pub fn reader(json: Value) -> impl FnMut(&str) -> Result {
/// }, /// },
/// "friends": [{"id": 0}, {"id": 1}] /// "friends": [{"id": 0}, {"id": 1}]
/// }); /// });
/// let json = jsonpath::read(json_obj, "$..friends[0]").unwrap(); /// let json = jsonpath::select(json_obj, "$..friends[0]").unwrap();
/// let ret = json!([ {"id": 0}, {"id": 0} ]); /// let ret = json!([ {"id": 0}, {"id": 0} ]);
/// assert_eq!(json, ret); /// assert_eq!(json, ret);
/// ``` /// ```
pub fn read(json: Value, path: &str) -> Result { pub fn select(json: Value, path: &str) -> Result {
let mut jf = JsonValueFilter::new_from_value(Rc::new(Box::new(json))); let mut jf = JsonValueFilter::new_from_value(json.into());
let mut parser = Parser::new(path); let mut parser = Parser::new(path);
parser.parse(&mut jf)?; parser.parse(&mut jf)?;
Ok(jf.take_value()) Ok(jf.take_value().into_value())
}
/// # Read Json using JsonPath - Deprecated. use select
pub fn read(json: Value, path: &str) -> Result {
select(json, path)
} }
#[cfg(test)] #[cfg(test)]
@ -323,9 +336,9 @@ mod tests {
} }
#[test] #[test]
fn reader() { fn selector() {
let json_obj = read_json("./benches/data_obj.json"); let json_obj = read_json("./benches/data_obj.json");
let mut reader = super::reader(json_obj); let mut reader = super::selector(json_obj);
let json = reader("$..friends[2]").unwrap(); let json = reader("$..friends[2]").unwrap();
let ret = json!([ let ret = json!([
{"id": 2,"name": "Gray Berry"}, {"id": 2,"name": "Gray Berry"},
@ -342,9 +355,9 @@ mod tests {
} }
#[test] #[test]
fn read() { fn select() {
let json_obj = read_json("./benches/example.json"); let json_obj = read_json("./benches/example.json");
let json = super::read(json_obj, "$..book[2]").unwrap(); let json = super::select(json_obj, "$..book[2]").unwrap();
let ret = json!([{ let ret = json!([{
"category" : "fiction", "category" : "fiction",
"author" : "Herman Melville", "author" : "Herman Melville",

View File

@ -13,25 +13,21 @@ type Result<T> = result::Result<T, String>;
mod utils { mod utils {
use std::result; use std::result;
pub fn vec_to_int<F>(vec: &Vec<char>, msg_handler: F) -> result::Result<isize, String> pub fn string_to_isize<F>(string: &String, msg_handler: F) -> result::Result<isize, String>
where F: Fn() -> String { where F: Fn() -> String {
match vec.iter().map(|c| *c).collect::<String>().as_str().parse::<isize>() { match string.as_str().parse::<isize>() {
Ok(n) => Ok(n), Ok(n) => Ok(n),
_ => Err(msg_handler()) _ => Err(msg_handler())
} }
} }
pub fn vec_to_float<F>(vec: &Vec<char>, msg_handler: F) -> result::Result<f64, String> pub fn string_to_f64<F>(string: &String, msg_handler: F) -> result::Result<f64, String>
where F: Fn() -> String { where F: Fn() -> String {
match vec.iter().map(|c| *c).collect::<String>().as_str().parse::<f64>() { match string.as_str().parse::<f64>() {
Ok(n) => Ok(n), Ok(n) => Ok(n),
_ => Err(msg_handler()) _ => Err(msg_handler())
} }
} }
pub fn vec_to_string(vec: &Vec<char>) -> String {
vec.iter().map(|c| *c).collect::<String>()
}
} }
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
@ -236,7 +232,7 @@ impl<'a> Parser<'a> {
debug!("#key"); debug!("#key");
match self.tokenizer.next_token() { match self.tokenizer.next_token() {
Ok(Token::Key(_, v)) => { Ok(Token::Key(_, v)) => {
Ok(self.node(ParseToken::Key(utils::vec_to_string(&v)))) Ok(self.node(ParseToken::Key(v)))
} }
_ => { _ => {
Err(self.tokenizer.err_msg()) Err(self.tokenizer.err_msg())
@ -247,9 +243,9 @@ impl<'a> Parser<'a> {
fn array_quota_value(&mut self) -> Result<Node> { fn array_quota_value(&mut self) -> Result<Node> {
debug!("#array_quota_value"); debug!("#array_quota_value");
match self.tokenizer.next_token() { match self.tokenizer.next_token() {
Ok(Token::SingleQuoted(_, ref vec)) Ok(Token::SingleQuoted(_, val))
| Ok(Token::DoubleQuoted(_, ref vec)) => { | Ok(Token::DoubleQuoted(_, val)) => {
Ok(self.node(ParseToken::Key(utils::vec_to_string(vec)))) Ok(self.node(ParseToken::Key(val)))
} }
Err(TokenError::Eof) => { Err(TokenError::Eof) => {
Ok(self.node(ParseToken::Eof)) Ok(self.node(ParseToken::Eof))
@ -299,9 +295,8 @@ impl<'a> Parser<'a> {
fn array_value_key(&mut self) -> Result<Node> { fn array_value_key(&mut self) -> Result<Node> {
debug!("#array_value_key"); debug!("#array_value_key");
match self.tokenizer.next_token() { match self.tokenizer.next_token() {
Ok(Token::Key(pos, ref vec)) => { Ok(Token::Key(pos, ref val)) => {
let digit = utils::vec_to_int(vec, let digit = utils::string_to_isize(val, || self.tokenizer.err_msg_with_pos(pos))?;
|| self.tokenizer.err_msg_with_pos(pos))?;
self.eat_whitespace(); self.eat_whitespace();
match self.tokenizer.peek_token() { match self.tokenizer.peek_token() {
@ -357,9 +352,8 @@ impl<'a> Parser<'a> {
self.eat_token(); self.eat_token();
self.eat_whitespace(); self.eat_whitespace();
match self.tokenizer.next_token() { match self.tokenizer.next_token() {
Ok(Token::Key(pos, ref vec)) => { Ok(Token::Key(pos, ref val)) => {
let digit = utils::vec_to_int(vec, let digit = utils::string_to_isize(val, || self.tokenizer.err_msg_with_pos(pos))?;
|| self.tokenizer.err_msg_with_pos(pos))?;
values.push(digit); values.push(digit);
} }
_ => { _ => {
@ -387,9 +381,8 @@ impl<'a> Parser<'a> {
fn range_to(&mut self) -> Result<Node> { fn range_to(&mut self) -> Result<Node> {
debug!("#range_to"); debug!("#range_to");
match self.tokenizer.next_token() { match self.tokenizer.next_token() {
Ok(Token::Key(pos, ref vec)) => { Ok(Token::Key(pos, ref val)) => {
let digit = utils::vec_to_int(vec, let digit = utils::string_to_isize(val, || self.tokenizer.err_msg_with_pos(pos))?;
|| self.tokenizer.err_msg_with_pos(pos))?;
Ok(self.node(ParseToken::Range(None, Some(digit)))) Ok(self.node(ParseToken::Range(None, Some(digit))))
} }
_ => { _ => {
@ -401,9 +394,8 @@ impl<'a> Parser<'a> {
fn range(&mut self, num: isize) -> Result<Node> { fn range(&mut self, num: isize) -> Result<Node> {
debug!("#range"); debug!("#range");
match self.tokenizer.next_token() { match self.tokenizer.next_token() {
Ok(Token::Key(pos, ref vec)) => { Ok(Token::Key(pos, ref val)) => {
let digit = utils::vec_to_int(vec, let digit = utils::string_to_isize(val, || self.tokenizer.err_msg_with_pos(pos))?;
|| self.tokenizer.err_msg_with_pos(pos))?;
Ok(self.node(ParseToken::Range(Some(num), Some(digit)))) Ok(self.node(ParseToken::Range(Some(num), Some(digit))))
} }
_ => { _ => {
@ -505,14 +497,13 @@ impl<'a> Parser<'a> {
fn term_num(&mut self) -> Result<Node> { fn term_num(&mut self) -> Result<Node> {
debug!("#term_num"); debug!("#term_num");
match self.tokenizer.next_token() { match self.tokenizer.next_token() {
Ok(Token::Key(pos, mut vec)) => { Ok(Token::Key(pos, val)) => {
match self.tokenizer.peek_token() { match self.tokenizer.peek_token() {
Ok(Token::Dot(_)) => { Ok(Token::Dot(_)) => {
self.term_num_float(&mut vec) self.term_num_float(val.as_str())
} }
_ => { _ => {
let number = utils::vec_to_float(&vec, let number = utils::string_to_f64(&val, || self.tokenizer.err_msg_with_pos(pos))?;
|| self.tokenizer.err_msg_with_pos(pos))?;
Ok(self.node(ParseToken::Number(number))) Ok(self.node(ParseToken::Number(number)))
} }
} }
@ -526,17 +517,16 @@ impl<'a> Parser<'a> {
} }
} }
fn term_num_float(&mut self, mut num: &mut Vec<char>) -> Result<Node> { fn term_num_float(&mut self, mut num: &str) -> Result<Node> {
debug!("#term_num_float"); debug!("#term_num_float");
self.eat_token(); self.eat_token();
match self.tokenizer.next_token() { match self.tokenizer.next_token() {
Ok(Token::Key(pos, mut frac)) => { Ok(Token::Key(pos, frac)) => {
let mut f = vec![]; let mut f = String::new();
f.append(&mut num); f.push_str(&mut num);
f.push('.'); f.push('.');
f.append(&mut frac); f.push_str(frac.as_str());
let number = utils::vec_to_float(&f, let number = utils::string_to_f64(&f, || self.tokenizer.err_msg_with_pos(pos))?;
|| self.tokenizer.err_msg_with_pos(pos))?;
Ok(self.node(ParseToken::Number(number))) Ok(self.node(ParseToken::Number(number)))
} }
_ => { _ => {

View File

@ -23,19 +23,23 @@ impl<'a> PathReader<'a> {
Ok((self.pos + ch.len_utf8(), ch)) Ok((self.pos + ch.len_utf8(), ch))
} }
pub fn take_while<F>(&mut self, fun: F) -> result::Result<(usize, Vec<char>), ReaderError> pub fn take_while<F>(&mut self, fun: F) -> result::Result<(usize, String), ReaderError>
where where
F: Fn(&char) -> bool F: Fn(&char) -> bool
{ {
let vec: Vec<char> = self.input.chars() let mut char_len: usize = 0;
.by_ref() let mut ret = String::new();
.take_while(fun) for c in self.input.chars().by_ref() {
.collect(); if !fun(&c) {
break;
}
char_len += c.len_utf8();
ret.push(c);
}
let char_len: usize = vec.iter().by_ref().map(|c| c.len_utf8()).sum();
self.pos += char_len; self.pos += char_len;
self.input = &self.input[char_len..]; self.input = &self.input[char_len..];
Ok((self.pos, vec)) Ok((self.pos, ret))
} }
pub fn next_char(&mut self) -> result::Result<(usize, char), ReaderError> { pub fn next_char(&mut self) -> result::Result<(usize, char), ReaderError> {

View File

@ -75,9 +75,9 @@ pub enum Token {
Split(usize), Split(usize),
OpenParenthesis(usize), OpenParenthesis(usize),
CloseParenthesis(usize), CloseParenthesis(usize),
Key(usize, Vec<char>), Key(usize, String),
DoubleQuoted(usize, Vec<char>), DoubleQuoted(usize, String),
SingleQuoted(usize, Vec<char>), SingleQuoted(usize, String),
Equal(usize), Equal(usize),
GreaterOrEqual(usize), GreaterOrEqual(usize),
Greater(usize), Greater(usize),
@ -153,15 +153,15 @@ impl<'a> Tokenizer<'a> {
} }
fn single_quota(&mut self, pos: usize, ch: char) -> result::Result<Token, TokenError> { fn single_quota(&mut self, pos: usize, ch: char) -> result::Result<Token, TokenError> {
let (_, vec) = self.input.take_while(|c| *c != ch).map_err(to_token_error)?; let (_, val) = self.input.take_while(|c| *c != ch).map_err(to_token_error)?;
self.input.next_char().map_err(to_token_error)?; self.input.next_char().map_err(to_token_error)?;
Ok(Token::SingleQuoted(pos, vec)) Ok(Token::SingleQuoted(pos, val))
} }
fn double_quota(&mut self, pos: usize, ch: char) -> result::Result<Token, TokenError> { fn double_quota(&mut self, pos: usize, ch: char) -> result::Result<Token, TokenError> {
let (_, vec) = self.input.take_while(|c| *c != ch).map_err(to_token_error)?; let (_, val) = self.input.take_while(|c| *c != ch).map_err(to_token_error)?;
self.input.next_char().map_err(to_token_error)?; self.input.next_char().map_err(to_token_error)?;
Ok(Token::DoubleQuoted(pos, vec)) Ok(Token::DoubleQuoted(pos, val))
} }
fn equal(&mut self, pos: usize, _: char) -> result::Result<Token, TokenError> { fn equal(&mut self, pos: usize, _: char) -> result::Result<Token, TokenError> {
@ -414,9 +414,9 @@ mod tests {
vec![ vec![
Token::Absolute(0), Token::Absolute(0),
Token::Dot(1), Token::Dot(1),
Token::Key(2, vec!['0', '1']), Token::Key(2, "01".to_string()),
Token::Dot(4), Token::Dot(4),
Token::Key(5, vec!['a']) Token::Key(5, "a".to_string())
] ]
, Some(TokenError::Eof) , Some(TokenError::Eof)
)); ));
@ -449,7 +449,7 @@ mod tests {
Token::Absolute(0), Token::Absolute(0),
Token::Dot(1), Token::Dot(1),
Token::Dot(2), Token::Dot(2),
Token::Key(3, vec!['a', 'b']) Token::Key(3, "ab".to_string())
] ]
, Some(TokenError::Eof) , Some(TokenError::Eof)
)); ));
@ -460,7 +460,7 @@ mod tests {
Token::Absolute(0), Token::Absolute(0),
Token::Dot(1), Token::Dot(1),
Token::Dot(2), Token::Dot(2),
Token::Key(3, vec!['가']), Token::Key(3, "".to_string()),
Token::Whitespace(6, 0), Token::Whitespace(6, 0),
Token::OpenArray(7), Token::OpenArray(7),
] ]
@ -471,10 +471,10 @@ mod tests {
( (
vec![ vec![
Token::OpenArray(0), Token::OpenArray(0),
Token::Key(1, vec!['-', '1']), Token::Key(1, "-1".to_string()),
Token::Comma(3), Token::Comma(3),
Token::Whitespace(4, 0), Token::Whitespace(4, 0),
Token::Key(5, vec!['2']), Token::Key(5, "2".to_string()),
Token::Whitespace(6, 0), Token::Whitespace(6, 0),
Token::CloseArray(7), Token::CloseArray(7),
] ]
@ -486,19 +486,19 @@ mod tests {
vec![ vec![
Token::OpenArray(0), Token::OpenArray(0),
Token::Whitespace(1, 0), Token::Whitespace(1, 0),
Token::Key(2, vec!['1']), Token::Key(2, "1".to_string()),
Token::Whitespace(3, 0), Token::Whitespace(3, 0),
Token::Key(4, vec!['2']), Token::Key(4, "2".to_string()),
Token::Whitespace(5, 0), Token::Whitespace(5, 0),
Token::Comma(6), Token::Comma(6),
Token::Whitespace(7, 0), Token::Whitespace(7, 0),
Token::Key(8, vec!['3']), Token::Key(8, "3".to_string()),
Token::Whitespace(9, 0), Token::Whitespace(9, 0),
Token::DoubleQuoted(10, vec!['a', 'b', 'c']), Token::DoubleQuoted(10, "abc".to_string()),
Token::Whitespace(15, 0), Token::Whitespace(15, 0),
Token::Split(16), Token::Split(16),
Token::Whitespace(17, 0), Token::Whitespace(17, 0),
Token::Key(18, vec!['-', '1', '0']), Token::Key(18, "-10".to_string()),
Token::Whitespace(21, 0), Token::Whitespace(21, 0),
Token::CloseArray(22), Token::CloseArray(22),
] ]
@ -512,12 +512,12 @@ mod tests {
Token::OpenParenthesis(1), Token::OpenParenthesis(1),
Token::At(2), Token::At(2),
Token::Dot(3), Token::Dot(3),
Token::Key(4, vec!['a', '가']), Token::Key(4, "a가".to_string()),
Token::Whitespace(8, 0), Token::Whitespace(8, 0),
Token::Little(9), Token::Little(9),
Token::Key(10, vec!['4', '1']), Token::Key(10, "41".to_string()),
Token::Dot(12), Token::Dot(12),
Token::Key(13, vec!['0', '1']), Token::Key(13, "01".to_string()),
Token::CloseParenthesis(15), Token::CloseParenthesis(15),
] ]
, Some(TokenError::Eof) , Some(TokenError::Eof)
@ -530,12 +530,12 @@ mod tests {
Token::OpenParenthesis(1), Token::OpenParenthesis(1),
Token::At(2), Token::At(2),
Token::Dot(3), Token::Dot(3),
Token::Key(4, vec!['a']), Token::Key(4, "a".to_string()),
Token::Whitespace(5, 0), Token::Whitespace(5, 0),
Token::Little(6), Token::Little(6),
Token::Key(7, vec!['4', 'a']), Token::Key(7, "4a".to_string()),
Token::Dot(9), Token::Dot(9),
Token::Key(10, vec!['0', '1']), Token::Key(10, "01".to_string()),
Token::CloseParenthesis(12), Token::CloseParenthesis(12),
] ]
, Some(TokenError::Eof) , Some(TokenError::Eof)
@ -547,11 +547,11 @@ mod tests {
Token::OpenParenthesis(1), Token::OpenParenthesis(1),
Token::Absolute(2), Token::Absolute(2),
Token::Dot(3), Token::Dot(3),
Token::Key(4, vec!['c']), Token::Key(4, "c".to_string()),
Token::Greater(5), Token::Greater(5),
Token::At(6), Token::At(6),
Token::Dot(7), Token::Dot(7),
Token::Key(8, vec!['d']), Token::Key(8, "d".to_string()),
Token::CloseParenthesis(9) Token::CloseParenthesis(9)
] ]
, Some(TokenError::Eof) , Some(TokenError::Eof)

384
src/ref_value/mod.rs Normal file
View File

@ -0,0 +1,384 @@
extern crate indexmap;
extern crate serde_json;
use std::sync::Arc;
use std::convert::Into;
use indexmap::map::IndexMap;
use serde_json::Number;
use serde_json::Value;
pub type TypeRefValue = Arc<Box<RefValue>>;
impl Into<RefValueWrapper> for TypeRefValue {
fn into(self) -> RefValueWrapper {
RefValueWrapper::new(self.clone())
}
}
impl Into<RefValueWrapper> for &TypeRefValue {
fn into(self) -> RefValueWrapper {
RefValueWrapper::new(self.clone())
}
}
///
/// serde_json::Value 참고
///
pub trait RefIndex {
fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v TypeRefValue>;
fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut TypeRefValue>;
fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut TypeRefValue;
}
impl RefIndex for usize {
fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v TypeRefValue> {
match *v {
RefValue::Array(ref vec) => vec.get(*self),
_ => None,
}
}
fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut TypeRefValue> {
match *v {
RefValue::Array(ref mut vec) => vec.get_mut(*self),
_ => None,
}
}
fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut TypeRefValue {
match *v {
RefValue::Array(ref mut vec) => {
let len = vec.len();
vec.get_mut(*self).unwrap_or_else(|| {
panic!(
"cannot access index {} of JSON array of length {}",
self, len
)
})
}
_ => panic!("cannot access index {} of JSON {:?}", self, v),
}
}
}
impl RefIndex for str {
fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v TypeRefValue> {
match *v {
RefValue::Object(ref map) => map.get(self),
_ => None,
}
}
fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut TypeRefValue> {
match *v {
RefValue::Object(ref mut map) => map.get_mut(self),
_ => None,
}
}
fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut TypeRefValue {
if let RefValue::Null = *v {
*v = RefValue::Object(IndexMap::new());
}
match *v {
RefValue::Object(ref mut map) => {
map.entry(self.to_owned()).or_insert(RefValueWrapper::wrap(RefValue::Null))
},
_ => panic!("cannot access key {:?} in JSON {:?}", self, v),
}
}
}
impl RefIndex for String {
fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v TypeRefValue> {
self[..].index_into(v)
}
fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut TypeRefValue> {
self[..].index_into_mut(v)
}
fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut TypeRefValue {
self[..].index_or_insert(v)
}
}
#[derive(Debug)]
pub struct RefValueWrapper {
data: TypeRefValue
}
impl RefValueWrapper {
pub fn new(ref_value: TypeRefValue) -> Self {
RefValueWrapper { data: ref_value }
}
pub fn wrap(ref_val: RefValue) -> TypeRefValue {
Arc::new(Box::new(ref_val))
}
pub fn into_value(&self) -> Value {
ValueConverter::new(&self.data)
}
pub fn clone(&self) -> Self {
RefValueWrapper { data: self.data.clone() }
}
pub fn clone_data(&self) -> TypeRefValue {
self.data.clone()
}
pub fn get<I: RefIndex>(&self, index: I) -> Option<RefValueWrapper> {
index.index_into(&**self.data).map(|v| Self::new(v.clone()))
}
pub fn is_object(&self) -> bool {
(**self.data).is_object()
}
pub fn as_object(&self) -> Option<&IndexMap<String, TypeRefValue>> {
(**self.data).as_object()
}
pub fn is_array(&self) -> bool {
(**self.data).is_array()
}
pub fn as_array(&self) -> Option<&Vec<TypeRefValue>> {
(**self.data).as_array()
}
pub fn is_string(&self) -> bool {
(**self.data).is_string()
}
pub fn as_str(&self) -> Option<&str> {
(**self.data).as_str()
}
pub fn is_number(&self) -> bool {
(**self.data).is_number()
}
pub fn as_number(&self) -> Option<Number> {
(**self.data).as_number()
}
pub fn is_boolean(&self) -> bool {
(**self.data).is_boolean()
}
pub fn as_bool(&self) -> Option<bool> {
(**self.data).as_bool()
}
pub fn is_null(&self) -> bool {
(**self.data).is_null()
}
pub fn as_null(&self) -> Option<()> {
(**self.data).as_null()
}
pub fn get_data_ref(&self) -> &RefValue {
&(**self.data)
}
}
impl Into<RefValueWrapper> for Value {
fn into(self) -> RefValueWrapper {
let ref_val = RefValueConverter::new(self);
RefValueWrapper::new(ref_val)
}
}
#[derive(Debug)]
pub enum RefValue {
Null,
Bool(bool),
Number(Number),
String(String),
Array(Vec<TypeRefValue>),
Object(IndexMap<String, TypeRefValue>),
}
impl RefValue {
pub fn get<I: RefIndex>(&self, index: I) -> Option<&TypeRefValue> {
index.index_into(self)
}
pub fn is_object(&self) -> bool {
self.as_object().is_some()
}
pub fn as_object(&self) -> Option<&IndexMap<String, TypeRefValue>> {
match *self {
RefValue::Object(ref map) => Some(map),
_ => None,
}
}
pub fn is_array(&self) -> bool {
self.as_array().is_some()
}
pub fn as_array(&self) -> Option<&Vec<TypeRefValue>> {
match *self {
RefValue::Array(ref array) => Some(&*array),
_ => None,
}
}
pub fn is_string(&self) -> bool {
self.as_str().is_some()
}
pub fn as_str(&self) -> Option<&str> {
match *self {
RefValue::String(ref s) => Some(s),
_ => None,
}
}
pub fn is_number(&self) -> bool {
match *self {
RefValue::Number(_) => true,
_ => false,
}
}
pub fn as_number(&self) -> Option<Number> {
match *self {
RefValue::Number(ref n) => Some(n.clone()),
_ => None,
}
}
pub fn is_boolean(&self) -> bool {
self.as_bool().is_some()
}
pub fn as_bool(&self) -> Option<bool> {
match *self {
RefValue::Bool(b) => Some(b),
_ => None,
}
}
pub fn is_null(&self) -> bool {
self.as_null().is_some()
}
pub fn as_null(&self) -> Option<()> {
match *self {
RefValue::Null => Some(()),
_ => None,
}
}
}
impl Into<RefValueWrapper> for RefValue {
fn into(self) -> RefValueWrapper {
let wrap = RefValueWrapper::wrap(self);
RefValueWrapper::new(wrap)
}
}
struct RefValueConverter;
impl RefValueConverter {
fn new(value: Value) -> TypeRefValue {
RefValueConverter {}.visit_value(value)
}
fn visit_value(&self, value: Value) -> TypeRefValue {
match value {
Value::Null => self.visit_null(),
Value::Bool(v) => self.visit_bool(v),
Value::Number(v) => self.visit_number(v),
Value::String(v) => self.visit_string(v),
Value::Array(v) => self.visit_array(v),
Value::Object(v) => self.visit_object(v),
}
}
fn visit_null(&self) -> TypeRefValue {
RefValueWrapper::wrap(RefValue::Null)
}
fn visit_bool(&self, value: bool) -> TypeRefValue {
RefValueWrapper::wrap(RefValue::Bool(value))
}
fn visit_number(&self, value: serde_json::Number) -> TypeRefValue {
RefValueWrapper::wrap(RefValue::Number(value))
}
fn visit_string(&self, value: String) -> TypeRefValue {
RefValueWrapper::wrap(RefValue::String(value.to_string()))
}
fn visit_array(&self, value: Vec<Value>) -> TypeRefValue {
let mut values = Vec::new();
for v in value {
values.push(self.visit_value(v));
}
RefValueWrapper::wrap(RefValue::Array(values))
}
fn visit_object(&self, mut value: serde_json::Map<String, Value>) -> TypeRefValue {
let mut map = IndexMap::new();
let keys: Vec<String> = value.keys().into_iter().map(|k| k.to_string()).collect();
for k in keys {
let value = self.visit_value(match value.get_mut(&k) {
Some(v) => v.take(),
_ => Value::Null
});
map.insert(k, value);
}
RefValueWrapper::wrap(RefValue::Object(map))
}
}
struct ValueConverter;
impl ValueConverter {
fn new(value: &TypeRefValue) -> Value {
ValueConverter {}.visit_value(value)
}
fn visit_value(&self, value: &TypeRefValue) -> Value {
match &***value {
RefValue::Null => self.visit_null(),
RefValue::Bool(v) => self.visit_bool(v),
RefValue::Number(v) => self.visit_number(v),
RefValue::String(v) => self.visit_string(v),
RefValue::Array(v) => self.visit_array(v),
RefValue::Object(v) => self.visit_object(v),
}
}
fn visit_null(&self) -> Value {
Value::Null
}
fn visit_bool(&self, value: &bool) -> Value {
Value::Bool(*value)
}
fn visit_number(&self, value: &serde_json::Number) -> Value {
Value::Number(value.clone())
}
fn visit_string(&self, value: &String) -> Value {
Value::String(value.clone())
}
fn visit_array(&self, value: &Vec<TypeRefValue>) -> Value {
let mut values = Vec::new();
for v in value {
values.push(self.visit_value(v));
}
Value::Array(values)
}
fn visit_object(&self, map: &IndexMap<String, TypeRefValue>) -> Value {
let mut ret = serde_json::Map::new();
let keys: Vec<String> = map.keys().into_iter().map(|k: &String| k.to_string()).collect();
let tmp_null = &RefValueWrapper::wrap(RefValue::Null);
for k in keys {
let value = self.visit_value(match map.get(&k) {
Some(e) => e,
_ => tmp_null
});
ret.insert(k, value);
}
Value::Object(ret)
}
}

2
wasm/.gitignore vendored
View File

@ -4,3 +4,5 @@ Cargo.lock
bin/ bin/
pkg/ pkg/
wasm-pack.log wasm-pack.log
.idea/*
.vscode

View File

@ -1,6 +1,6 @@
[package] [package]
name = "jsonpath-wasm" name = "jsonpath-wasm"
version = "0.1.2" version = "0.1.3"
authors = ["Changseok Han <freestrings@gmail.com>"] authors = ["Changseok Han <freestrings@gmail.com>"]
description = "JsonPath Webassembly version compiled by Rust - Demo: https://freestrings.github.io/jsonpath" description = "JsonPath Webassembly version compiled by Rust - Demo: https://freestrings.github.io/jsonpath"
@ -22,8 +22,10 @@ wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
console_error_panic_hook = { version = "0.1.1", optional = true } console_error_panic_hook = { version = "0.1.1", optional = true }
wee_alloc = { version = "0.4.2", optional = true } wee_alloc = { version = "0.4.2", optional = true }
jsonpath_lib = {path = "../"} jsonpath_lib = { path = "../" }
serde_json = { version = "1.0", features = ["preserve_order"] } serde_json = { version = "1.0", features = ["preserve_order"] }
lazy_static = "1.3.0"
web-sys = { version = "0.3", features = ['console'] }
[dev-dependencies] [dev-dependencies]
wasm-bindgen-test = "0.2" wasm-bindgen-test = "0.2"

View File

@ -6,8 +6,10 @@ set -e
DIR="$(pwd)" DIR="$(pwd)"
cd "${DIR}"/www && \ cd "${DIR}"/www && \
rm -rf "${DIR}"/dist && \ rm -rf "${DIR}"/www/dist && \
rm -rf "${DIR}"/node_modules && \ rm -rf "${DIR}"/www/node_modules && \
rm -rf "${DIR}"/www_bench/dist && \
rm -rf "${DIR}"/www_bench/node_modules && \
npm install && \ npm install && \
cd "${DIR}" cd "${DIR}"
@ -24,6 +26,10 @@ echo "-------------------- build nodejs pkg done --------------------"
cd "${DIR}" cd "${DIR}"
echo
echo
echo
echo
echo echo
echo echo
echo "-------------------- start build browser pkg --------------------" echo "-------------------- start build browser pkg --------------------"
@ -34,10 +40,40 @@ cd "${DIR}"/browser_pkg && npm link && \
cd "${DIR}"/www && npm link @browser/jsonpath-wasm cd "${DIR}"/www && npm link @browser/jsonpath-wasm
echo "-------------------- build browser pkg done --------------------" echo "-------------------- build browser pkg done --------------------"
echo
echo
echo
echo
echo echo
echo echo
echo "-------------------- start build browser bench pkg --------------------" echo "-------------------- start build browser bench pkg --------------------"
echo echo
rm -rf "${DIR}"/www_bench/node_modules && \ rm -rf "${DIR}"/www_bench/node_modules && \
cd "${DIR}"/www_bench && npm install && npm link @browser/jsonpath-wasm cd "${DIR}"/www_bench && npm install && npm link @browser/jsonpath-wasm
echo "-------------------- build browser bench pkg done --------------------" echo "-------------------- build browser bench pkg done --------------------"
echo
echo
echo
echo
echo
echo
echo "-------------------- start build docs --------------------"
cd "${DIR}"/www && \
npm run build && \
rm -f "${DIR}"/../docs/*.js && rm -f "${DIR}"/../docs/*.wasm && rm -f "${DIR}"/../docs/*.html && \
cp "${DIR}"/www/dist/*.* "${DIR}"/../docs/
echo "-------------------- build docs done --------------------"
echo
echo
echo
echo
echo
echo
echo "-------------------- start build docs bench --------------------"
cd "${DIR}"/www_bench && \
npm run build && \
rm -f "${DIR}"/../docs/bench/*.js && rm -f "${DIR}"/../docs/bench/*.wasm && rm -f "${DIR}"/../docs/bench/*.html && \
cp "${DIR}"/www_bench/dist/*.* "${DIR}"/../docs/bench/
echo "-------------------- build docs bench done --------------------"

View File

@ -1,19 +1,24 @@
extern crate cfg_if; extern crate cfg_if;
extern crate wasm_bindgen;
extern crate serde_json;
extern crate jsonpath_lib as jsonpath; extern crate jsonpath_lib as jsonpath;
#[macro_use]
extern crate lazy_static;
extern crate serde_json;
extern crate wasm_bindgen;
extern crate web_sys;
mod utils; use std::collections::HashMap;
use std::result::Result;
use std::sync::Mutex;
use cfg_if::cfg_if; use cfg_if::cfg_if;
use wasm_bindgen::prelude::*;
use std::result::Result;
use std::rc::Rc;
use serde_json::Value;
use jsonpath::parser::parser::*;
use jsonpath::filter::value_filter::*; use jsonpath::filter::value_filter::*;
use jsonpath::parser::parser::*;
use jsonpath::ref_value::*;
use serde_json::Value;
use wasm_bindgen::prelude::*;
use web_sys::console;
mod utils;
cfg_if! { cfg_if! {
if #[cfg(feature = "wee_alloc")] { if #[cfg(feature = "wee_alloc")] {
@ -23,17 +28,17 @@ cfg_if! {
} }
} }
fn filter_value(json: Value, node: Node) -> JsValue { fn filter_ref_value(json: RefValueWrapper, node: Node) -> JsValue {
let mut jf = JsonValueFilter::new_from_value(Rc::new(Box::new(json))); let mut jf = JsonValueFilter::new_from_value(json);
jf.visit(node); jf.visit(node);
let taken = jf.take_value(); let taken = jf.take_value().into_value();
match JsValue::from_serde(&taken) { match JsValue::from_serde(&taken) {
Ok(js_value) => js_value, Ok(js_value) => js_value,
Err(e) => JsValue::from_str(&format!("Json deserialize error: {:?}", e)) Err(e) => JsValue::from_str(&format!("Json deserialize error: {:?}", e))
} }
} }
fn into_value(js_value: &JsValue) -> Result<Value, String> { fn into_serde_json(js_value: &JsValue) -> Result<Value, String> {
if js_value.is_string() { if js_value.is_string() {
match serde_json::from_str(js_value.as_string().unwrap().as_str()) { match serde_json::from_str(js_value.as_string().unwrap().as_str()) {
Ok(json) => Ok(json), Ok(json) => Ok(json),
@ -47,20 +52,64 @@ fn into_value(js_value: &JsValue) -> Result<Value, String> {
} }
} }
fn into_js_value(js_value: &JsValue, node: Node) -> JsValue { fn into_ref_value(js_value: &JsValue, node: Node) -> JsValue {
match into_value(js_value) { match into_serde_json(js_value) {
Ok(json) => filter_value(json, node), Ok(json) => filter_ref_value(json.into(), node),
Err(e) => JsValue::from_str(&format!("Json serialize error: {}", e)) Err(e) => JsValue::from_str(&format!("Json serialize error: {}", e))
} }
} }
fn get_ref_value(js_value: JsValue, node: Node) -> JsValue {
match js_value.as_f64() {
Some(val) => {
match CACHE_JSON.lock().unwrap().get(&(val as usize)) {
Some(json) => filter_ref_value(json.clone(), node),
_ => JsValue::from_str("Invalid pointer")
}
}
_ => into_ref_value(&js_value, node)
}
}
lazy_static! {
static ref CACHE_JSON: Mutex<HashMap<usize, RefValueWrapper>> = Mutex::new(HashMap::new());
static ref CACHE_JSON_IDX: Mutex<usize> = Mutex::new(0);
}
#[wasm_bindgen]
pub fn alloc_json(js_value: JsValue) -> usize {
match into_serde_json(&js_value) {
Ok(json) => {
let mut map = CACHE_JSON.lock().unwrap();
if map.len() >= std::u8::MAX as usize {
return 0;
}
let mut idx = CACHE_JSON_IDX.lock().unwrap();
*idx += 1;
map.insert(*idx, json.into());
*idx
}
Err(e) => {
console::log_1(&e.into());
0
}
}
}
#[wasm_bindgen]
pub fn dealloc_json(ptr: usize) -> bool {
let mut map = CACHE_JSON.lock().unwrap();
map.remove(&ptr).is_some()
}
#[wasm_bindgen] #[wasm_bindgen]
pub fn compile(path: &str) -> JsValue { pub fn compile(path: &str) -> JsValue {
let mut parser = Parser::new(path); let mut parser = Parser::new(path);
let node = parser.compile(); let node = parser.compile();
let cb = Closure::wrap(Box::new(move |js_value: JsValue| { let cb = Closure::wrap(Box::new(move |js_value: JsValue| {
match &node { match &node {
Ok(node) => into_js_value(&js_value, node.clone()), Ok(node) => get_ref_value(js_value, node.clone()),
Err(e) => JsValue::from_str(&format!("Json path error: {:?}", e)) Err(e) => JsValue::from_str(&format!("Json path error: {:?}", e))
} }
}) as Box<Fn(JsValue) -> JsValue>); }) as Box<Fn(JsValue) -> JsValue>);
@ -70,12 +119,35 @@ pub fn compile(path: &str) -> JsValue {
ret ret
} }
///
/// deprecated. use selector
///
#[wasm_bindgen] #[wasm_bindgen]
pub fn reader(js_value: JsValue) -> JsValue { pub fn reader(js_value: JsValue) -> JsValue {
selector(js_value)
}
#[wasm_bindgen]
pub fn selector(js_value: JsValue) -> JsValue {
let json = match js_value.as_f64() {
Some(val) => {
match CACHE_JSON.lock().unwrap().get(&(val as usize)) {
Some(json) => json.clone(),
_ => return JsValue::from_str("Invalid pointer")
}
}
_ => {
match into_serde_json(&js_value) {
Ok(json) => json.into(),
Err(e) => return JsValue::from_str(e.as_str())
}
}
};
let cb = Closure::wrap(Box::new(move |path: String| { let cb = Closure::wrap(Box::new(move |path: String| {
let mut parser = Parser::new(path.as_str()); let mut parser = Parser::new(path.as_str());
match parser.compile() { match parser.compile() {
Ok(node) => into_js_value(&js_value, node), Ok(node) => filter_ref_value(json.clone(), node),
Err(e) => return JsValue::from_str(e.as_str()) Err(e) => return JsValue::from_str(e.as_str())
} }
}) as Box<Fn(String) -> JsValue>); }) as Box<Fn(String) -> JsValue>);
@ -86,14 +158,21 @@ pub fn reader(js_value: JsValue) -> JsValue {
} }
#[wasm_bindgen] #[wasm_bindgen]
pub fn read(js_value: JsValue, path: &str) -> JsValue { pub fn select(js_value: JsValue, path: &str) -> JsValue {
let mut parser = Parser::new(path); let mut parser = Parser::new(path);
match parser.compile() { match parser.compile() {
Ok(node) => into_js_value(&js_value, node), Ok(node) => get_ref_value(js_value, node),
Err(e) => return JsValue::from_str(e.as_str()) Err(e) => return JsValue::from_str(e.as_str())
} }
} }
///
/// deprecated. use select
///
#[wasm_bindgen] #[wasm_bindgen]
pub fn testa() { pub fn read(js_value: JsValue, path: &str) -> JsValue {
} select(js_value, path)
}
#[wasm_bindgen]
pub fn testa() {}

View File

@ -2,11 +2,14 @@ import * as jpw from "@browser/jsonpath-wasm";
import * as jp from "jsonpath/jsonpath.js"; import * as jp from "jsonpath/jsonpath.js";
function run(message, iter, cb) { function run(message, iter, cb) {
let d = Date.now(); return new Promise(function(resolve, _reject) {
for (let i = 0; i < iter; i++) { let d = Date.now();
cb(); for (let i = 0; i < iter; i++) {
} cb();
msg([message, Date.now() - d].join(", ")); }
msg([message, Date.now() - d].join(", "));
setTimeout(resolve, 0);
})
} }
function msg(msg) { function msg(msg) {
@ -54,12 +57,33 @@ let json = {
"expensive": 10 "expensive": 10
}; };
setTimeout(function() { let path = '$..book[?(@.price<30 && @.category=="fiction")]';
let path = '$..book[?(@.price<30 && @.category=="fiction")]'; let template = jpw.compile(path);
let template = jpw.compile(path); let selector = jpw.selector(json);
let reader = jpw.reader(json);
run('jsonpath', 1000, function() { jp.query(json, path) }); let ptr = jpw.alloc_json(json);
run('jsonpath-wasm- reader', 1000, function() { reader(path) }); if(ptr == 0) console.error('invalid ptr');
run('jsonpath-wasm- compile', 1000, function() { template(json) });
run('jsonpath-wasm- read', 1000, function() { jpw.read(json, path) }); let iterCount = 2000;
}, 0);
run('jsonpath', iterCount, function() { jp.query(json, path) })
.then(function() {
return run('jsonpath-wasm- selector', iterCount, function() { selector(path) });
})
.then(function() {
return run('jsonpath-wasm- compile', iterCount, function() { template(json) });
})
.then(function() {
return run('jsonpath-wasm- compile-alloc', iterCount, function() { template(ptr) });
})
.then(function() {
return run('jsonpath-wasm- select', iterCount, function() { jpw.select(json, path) });
})
.then(function() {
return run('jsonpath-wasm- select-alloc', iterCount, function() { jpw.select(ptr, path) });
})
.finally(function() {
if(!jpw.dealloc_json(ptr)) {
console.error('fail to dealloc');
}
});