mirror of
https://github.com/fluencelabs/jsonpath
synced 2025-04-25 09:22:19 +00:00
RefValue serde 구현. bump up version. 0.1.5
This commit is contained in:
parent
482c957003
commit
b24a8c18a9
12
.idea/runConfigurations/serde.xml
generated
Normal file
12
.idea/runConfigurations/serde.xml
generated
Normal file
@ -0,0 +1,12 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="serde" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="command" value="test --package jsonpath_lib --test serde """ />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="nocapture" value="true" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "jsonpath_lib"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
authors = ["Changseok Han <freestrings@gmail.com>"]
|
||||
|
||||
description = "JsonPath in Rust and Webassembly - Webassembly Demo: https://freestrings.github.io/jsonpath"
|
||||
|
19
README.md
19
README.md
@ -29,6 +29,7 @@ To enjoy Rust!
|
||||
|
||||
- [jsonpath_lib library](#jsonpath_lib-library)
|
||||
- [rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str)](#rust---jsonpathselectjson-serde_jsonvaluevalue-jsonpath-str)
|
||||
- [rust - jsonpath::select_str(json_str: &str, jsonpath: &str)](#rust---jsonpathselect_strjson-str-jsonpath-str)
|
||||
- [rust - jsonpath::compile(jsonpath: &str)](#rust---jsonpathcompilejsonpath-str)
|
||||
- [rust - jsonpath::selector(json: &serde_json::value::Value)](#rust---jsonpathselectorjson-serde_jsonvaluevalue)
|
||||
- [rust - examples](https://github.com/freestrings/jsonpath/wiki/rust-examples)
|
||||
@ -36,6 +37,7 @@ To enjoy Rust!
|
||||
[With AWS API Gateway](#)
|
||||
|
||||
[Simple time check - webassembly](https://github.com/freestrings/jsonpath/wiki/Simple-timecheck---jsonpath-wasm)
|
||||
|
||||
[Simple time check - native addon for NodeJs](https://github.com/freestrings/jsonpath/wiki/Simple-timecheck-jsonpath-native)
|
||||
|
||||
## With Javascript
|
||||
@ -192,7 +194,7 @@ extern crate jsonpath_lib as jsonpath;
|
||||
extern crate serde_json;
|
||||
```
|
||||
|
||||
### rust - jsonpath::select(&json: serde_json::value::Value, jsonpath: &str)
|
||||
### rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str)
|
||||
|
||||
```rust
|
||||
let json_obj = json!({
|
||||
@ -206,6 +208,21 @@ let ret = json!([ {"id": 0}, {"id": 0} ]);
|
||||
assert_eq!(json, ret)
|
||||
```
|
||||
|
||||
### rust - jsonpath::select_str(json: &str, jsonpath: &str)
|
||||
|
||||
```rust
|
||||
let json_obj = json!({
|
||||
"school": {
|
||||
"friends": [{"id": 0}, {"id": 1}]
|
||||
},
|
||||
"friends": [{"id": 0}, {"id": 1}]
|
||||
});
|
||||
let json_str = jsonpath::select_str(&serde_json::to_string(&json_obj).unwrap(), "$..friends[0]").unwrap();
|
||||
let json: Value = serde_json::from_str(&json_str).unwrap();
|
||||
let ret = json!([ {"id": 0}, {"id": 0} ]);
|
||||
assert_eq!(json, ret)
|
||||
```
|
||||
|
||||
### rust - jsonpath::compile(jsonpath: &str)
|
||||
|
||||
```rust
|
||||
|
@ -14,40 +14,57 @@ fn read_json(path: &str) -> String {
|
||||
contents
|
||||
}
|
||||
|
||||
fn get_string() -> String {
|
||||
read_json("./benches/example.json")
|
||||
}
|
||||
|
||||
fn get_json() -> Value {
|
||||
let string = get_string();
|
||||
serde_json::from_str(string.as_str()).unwrap()
|
||||
}
|
||||
|
||||
fn get_path() -> &'static str {
|
||||
r#"$..book[?(@.price<30 && @.category=="fiction")]"#
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_selector(b: &mut Bencher) {
|
||||
let string = read_json("./benches/example.json");
|
||||
let path = r#"$..book[?(@.price<30 && @.category=="fiction")]"#;
|
||||
let json: Value = serde_json::from_str(string.as_str()).unwrap();
|
||||
let json = get_json();
|
||||
let mut selector = jsonpath::selector(&json);
|
||||
b.iter(move || {
|
||||
for _ in 1..1000 {
|
||||
let _ = selector(path).unwrap();
|
||||
for _ in 1..100 {
|
||||
let _ = selector(get_path()).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_select(b: &mut Bencher) {
|
||||
let string = read_json("./benches/example.json");
|
||||
let path = r#"$..book[?(@.price<30 && @.category=="fiction")]"#;
|
||||
let json: Value = serde_json::from_str(string.as_str()).unwrap();
|
||||
fn bench_select_val(b: &mut Bencher) {
|
||||
let json = get_json();
|
||||
b.iter(move || {
|
||||
for _ in 1..1000 {
|
||||
let _ = jsonpath::select(&json, path).unwrap();
|
||||
for _ in 1..100 {
|
||||
let _ = jsonpath::select(&json, get_path()).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_select_str(b: &mut Bencher) {
|
||||
let json = get_string();
|
||||
b.iter(move || {
|
||||
for _ in 1..100 {
|
||||
let _ = jsonpath::select_str(&json, get_path()).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_compile(b: &mut Bencher) {
|
||||
let string = read_json("./benches/example.json");
|
||||
let path = r#"$..book[?(@.price<30 && @.category=="fiction")]"#;
|
||||
let json: Value = serde_json::from_str(string.as_str()).unwrap();
|
||||
let mut template = jsonpath::compile(path);
|
||||
let json = get_json();
|
||||
let mut template = jsonpath::compile(get_path());
|
||||
b.iter(move || {
|
||||
for _ in 1..1000 {
|
||||
for _ in 1..100 {
|
||||
let _ = template(&json).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
3
benches/package-lock.json
generated
Normal file
3
benches/package-lock.json
generated
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"lockfileVersion": 1
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
10
docs/bench/bootstrap.js
vendored
10
docs/bench/bootstrap.js
vendored
@ -88,11 +88,11 @@
|
||||
/******/ "__wbindgen_throw": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_closure_wrapper99": function(p0i32,p1i32,p2i32) {
|
||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper99"](p0i32,p1i32,p2i32);
|
||||
/******/ "__wbindgen_closure_wrapper100": function(p0i32,p1i32,p2i32) {
|
||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper100"](p0i32,p1i32,p2i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_closure_wrapper101": function(p0i32,p1i32,p2i32) {
|
||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper101"](p0i32,p1i32,p2i32);
|
||||
/******/ "__wbindgen_closure_wrapper102": function(p0i32,p1i32,p2i32) {
|
||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper102"](p0i32,p1i32,p2i32);
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ };
|
||||
@ -192,7 +192,7 @@
|
||||
/******/ promises.push(installedWasmModuleData);
|
||||
/******/ else {
|
||||
/******/ var importObject = wasmImportObjects[wasmModuleId]();
|
||||
/******/ var req = fetch(__webpack_require__.p + "" + {"../browser_pkg/jsonpath_wasm_bg.wasm":"db8564aae9d99ec41b79"}[wasmModuleId] + ".module.wasm");
|
||||
/******/ var req = fetch(__webpack_require__.p + "" + {"../browser_pkg/jsonpath_wasm_bg.wasm":"e354e10adee0b37b85d7"}[wasmModuleId] + ".module.wasm");
|
||||
/******/ var promise;
|
||||
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
|
||||
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
|
||||
|
Binary file not shown.
BIN
docs/bench/e354e10adee0b37b85d7.module.wasm
Normal file
BIN
docs/bench/e354e10adee0b37b85d7.module.wasm
Normal file
Binary file not shown.
10
docs/bootstrap.js
vendored
10
docs/bootstrap.js
vendored
@ -88,11 +88,11 @@
|
||||
/******/ "__wbindgen_throw": function(p0i32,p1i32) {
|
||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_closure_wrapper99": function(p0i32,p1i32,p2i32) {
|
||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper99"](p0i32,p1i32,p2i32);
|
||||
/******/ "__wbindgen_closure_wrapper100": function(p0i32,p1i32,p2i32) {
|
||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper100"](p0i32,p1i32,p2i32);
|
||||
/******/ },
|
||||
/******/ "__wbindgen_closure_wrapper101": function(p0i32,p1i32,p2i32) {
|
||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper101"](p0i32,p1i32,p2i32);
|
||||
/******/ "__wbindgen_closure_wrapper102": function(p0i32,p1i32,p2i32) {
|
||||
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper102"](p0i32,p1i32,p2i32);
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ };
|
||||
@ -192,7 +192,7 @@
|
||||
/******/ promises.push(installedWasmModuleData);
|
||||
/******/ else {
|
||||
/******/ var importObject = wasmImportObjects[wasmModuleId]();
|
||||
/******/ var req = fetch(__webpack_require__.p + "" + {"../browser_pkg/jsonpath_wasm_bg.wasm":"db8564aae9d99ec41b79"}[wasmModuleId] + ".module.wasm");
|
||||
/******/ var req = fetch(__webpack_require__.p + "" + {"../browser_pkg/jsonpath_wasm_bg.wasm":"e354e10adee0b37b85d7"}[wasmModuleId] + ".module.wasm");
|
||||
/******/ var promise;
|
||||
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
|
||||
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
|
||||
|
Binary file not shown.
BIN
docs/e354e10adee0b37b85d7.module.wasm
Normal file
BIN
docs/e354e10adee0b37b85d7.module.wasm
Normal file
Binary file not shown.
@ -6,7 +6,7 @@ function compile(path) {
|
||||
if(typeof json != 'string') {
|
||||
json = JSON.stringify(json)
|
||||
}
|
||||
return compile.template(json);
|
||||
return JSON.parse(compile.template(json));
|
||||
};
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ function selector(json) {
|
||||
}
|
||||
let selector = new Selector(json);
|
||||
return (path) => {
|
||||
return selector.selector(path);
|
||||
return JSON.parse(selector.selector(path));
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ function select(json, path) {
|
||||
if(typeof json != 'string') {
|
||||
json = JSON.stringify(json)
|
||||
}
|
||||
return selectStr(json, path);
|
||||
return JSON.parse(selectStr(json, path));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "jsonpath-rs"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
authors = ["Changseok Han <freestrings@gmail.com>"]
|
||||
description = "JsonPath engine for NodeJs with Rust native implementation."
|
||||
keywords = ["library", "jsonpath", "json"]
|
||||
|
@ -24,13 +24,9 @@ fn select(mut ctx: FunctionContext) -> JsResult<JsValue> {
|
||||
|
||||
fn select_str(mut ctx: FunctionContext) -> JsResult<JsValue> {
|
||||
let json_val = ctx.argument::<JsString>(0)?.value();
|
||||
let json: Value = match serde_json::from_str(json_val.as_str()) {
|
||||
Ok(json) => json,
|
||||
Err(e) => panic!("{:?}", e)
|
||||
};
|
||||
let path = ctx.argument::<JsString>(1)?.value();
|
||||
match jsonpath::select(&json, path.as_str()) {
|
||||
Ok(value) => Ok(neon_serde::to_value(&mut ctx, &value)?),
|
||||
match jsonpath::select_str(&json_val, path.as_str()) {
|
||||
Ok(value) => Ok(JsString::new(&mut ctx, &value).upcast()),
|
||||
Err(e) => panic!("{:?}", e)
|
||||
}
|
||||
}
|
||||
@ -66,31 +62,30 @@ declare_types! {
|
||||
this.node.clone()
|
||||
};
|
||||
|
||||
// let o = ctx.argument::<JsValue>(0)?;
|
||||
// let json: Value = neon_serde::from_value(&mut ctx, o)?;
|
||||
let json_str = ctx.argument::<JsString>(0)?.value();
|
||||
let json: Value = match serde_json::from_str(&json_str) {
|
||||
Ok(json) => json,
|
||||
let ref_value: RefValue = match serde_json::from_str(&json_str) {
|
||||
Ok(ref_value) => ref_value,
|
||||
Err(e) => panic!("{:?}", e)
|
||||
};
|
||||
let mut jf = JsonValueFilter::new_from_value((&json).into());
|
||||
|
||||
let mut jf = JsonValueFilter::new_from_value(ref_value.into());
|
||||
jf.visit(node);
|
||||
let v = jf.take_value().into_value();
|
||||
Ok(neon_serde::to_value(&mut ctx, &v)?)
|
||||
match serde_json::to_string(&jf.take_value()) {
|
||||
Ok(json_str) => Ok(JsString::new(&mut ctx, &json_str).upcast()),
|
||||
Err(e) => panic!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub class JsSelector for Selector {
|
||||
init(mut ctx) {
|
||||
// let o = ctx.argument::<JsValue>(0)?;
|
||||
// let json: Value = neon_serde::from_value(&mut ctx, o)?;
|
||||
let json_str = ctx.argument::<JsString>(0)?.value();
|
||||
let json: Value = match serde_json::from_str(&json_str) {
|
||||
Ok(json) => json,
|
||||
let ref_value: RefValue = match serde_json::from_str(&json_str) {
|
||||
Ok(ref_value) => ref_value,
|
||||
Err(e) => panic!("{:?}", e)
|
||||
};
|
||||
|
||||
Ok(Selector { json: (&json).into() })
|
||||
Ok(Selector { json: ref_value.into() })
|
||||
}
|
||||
|
||||
method selector(mut ctx) {
|
||||
@ -112,8 +107,10 @@ declare_types! {
|
||||
|
||||
let mut jf = JsonValueFilter::new_from_value(json);
|
||||
jf.visit(node);
|
||||
let v = jf.take_value().into_value();
|
||||
Ok(neon_serde::to_value(&mut ctx, &v)?)
|
||||
match serde_json::to_string(&jf.take_value()) {
|
||||
Ok(json_str) => Ok(JsString::new(&mut ctx, &json_str).upcast()),
|
||||
Err(e) => panic!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ describe('compile test', () => {
|
||||
it('basic', (done) => {
|
||||
let template = jsonpath.compile('$.a');
|
||||
let result = template({'a': 1});
|
||||
if (result == 1) {
|
||||
if (result === 1) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
@ -14,7 +14,7 @@ describe('selector test', () => {
|
||||
it('basic', (done) => {
|
||||
let selector = jsonpath.selector({'a': 1});
|
||||
let result = selector('$.a');
|
||||
if (result == 1) {
|
||||
if (result === 1) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
@ -23,7 +23,7 @@ describe('selector test', () => {
|
||||
describe('select test', () => {
|
||||
it('basic', (done) => {
|
||||
let result = jsonpath.select({'a': 1}, '$.a');
|
||||
if (result == 1) {
|
||||
if (result === 1) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
@ -66,7 +66,7 @@ impl TermContext {
|
||||
}
|
||||
}
|
||||
TermContext::Json(_, v) => {
|
||||
TermContext::Json(None, ValueWrapper::new(v.clone_val(), false))
|
||||
TermContext::Json(None, ValueWrapper::new(v.get_val().clone(), false))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -79,7 +79,7 @@ impl TermContext {
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
TermContext::Json(None, ValueWrapper::new(v.clone_val(), false))
|
||||
TermContext::Json(None, ValueWrapper::new(v.get_val().clone(), false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
use std::error::Error;
|
||||
use std::result::Result;
|
||||
use std::ops::Deref;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use ref_value::*;
|
||||
|
||||
use parser::prelude::*;
|
||||
use filter::term::*;
|
||||
use filter::value_wrapper::*;
|
||||
use parser::prelude::*;
|
||||
use ref_value::model::*;
|
||||
|
||||
trait ArrayIndex {
|
||||
fn index(&self, v: &RefValueWrapper) -> usize;
|
||||
@ -15,7 +15,7 @@ trait ArrayIndex {
|
||||
fn take_value(&self, v: &RefValueWrapper) -> RefValueWrapper {
|
||||
let idx = self.index(v);
|
||||
match v.get(idx) {
|
||||
Some(v) => v,
|
||||
Some(v) => v.clone(),
|
||||
_ => RefValue::Null.into()
|
||||
}
|
||||
}
|
||||
@ -66,7 +66,7 @@ impl ValueFilter {
|
||||
ValueFilter { vw: ValueWrapper::new(v, is_leaves), last_key: None, filter_mode }
|
||||
}
|
||||
|
||||
fn iter_to_value_vec<'a, I: Iterator<Item=&'a TypeRefValue>>(iter: I) -> Vec<TypeRefValue> {
|
||||
fn iter_to_value_vec<'a, I: Iterator<Item=&'a RefValueWrapper>>(iter: I) -> Vec<RefValueWrapper> {
|
||||
iter
|
||||
.map(|v| v.clone())
|
||||
.filter(|v| !v.is_null())
|
||||
@ -98,8 +98,8 @@ impl ValueFilter {
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_all(key: Option<&String>, v: &RefValueWrapper, buf: &mut Vec<TypeRefValue>) {
|
||||
match v.get_data_ref() {
|
||||
fn collect_all(key: Option<&String>, v: &RefValueWrapper, buf: &mut Vec<RefValueWrapper>) {
|
||||
match v.deref() {
|
||||
RefValue::Array(vec) => {
|
||||
if key.is_none() {
|
||||
for v in vec {
|
||||
@ -107,7 +107,7 @@ impl ValueFilter {
|
||||
}
|
||||
}
|
||||
for i in vec {
|
||||
Self::collect_all(key, &i.into(), buf);
|
||||
Self::collect_all(key, i, buf);
|
||||
}
|
||||
}
|
||||
RefValue::Object(v) => {
|
||||
@ -120,7 +120,7 @@ impl ValueFilter {
|
||||
}
|
||||
}
|
||||
for (_, v) in v.into_iter() {
|
||||
Self::collect_all(key, &v.into(), buf);
|
||||
Self::collect_all(key, v, buf);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@ -154,7 +154,7 @@ impl ValueFilter {
|
||||
pub fn step_in_all(&mut self) -> &ValueWrapper {
|
||||
debug!("step_in_all");
|
||||
|
||||
let vec = match self.vw.get_val().get_data_ref() {
|
||||
let vec = match self.vw.get_val().deref() {
|
||||
RefValue::Object(ref map) => {
|
||||
Self::iter_to_value_vec(map.values())
|
||||
}
|
||||
@ -162,12 +162,12 @@ impl ValueFilter {
|
||||
Self::iter_to_value_vec(list.iter())
|
||||
}
|
||||
RefValue::Null => Vec::new(),
|
||||
_ => vec![self.vw.get_val().clone_data()]
|
||||
_ => vec![self.vw.get_val().clone()]
|
||||
};
|
||||
|
||||
self.last_key = Some(ValueFilterKey::All);
|
||||
self.vw.replace(RefValue::Array(vec).into());
|
||||
trace!("step_in_all - {:?}", self.vw.get_val().get_data_ref());
|
||||
trace!("step_in_all - {:?}", self.vw.get_val());
|
||||
&self.vw
|
||||
}
|
||||
|
||||
@ -176,17 +176,17 @@ impl ValueFilter {
|
||||
trace!("step_in_num - before: leaves {}, filterMode {} - {:?}"
|
||||
, self.vw.is_leaves()
|
||||
, self.filter_mode
|
||||
, self.vw.get_val().get_data_ref());
|
||||
, self.vw.get_val());
|
||||
|
||||
let v = if self.vw.is_leaves() {
|
||||
let filter_mode = self.filter_mode;
|
||||
match self.vw.get_val().get_data_ref() {
|
||||
match self.vw.get_val().deref() {
|
||||
RefValue::Array(ref vec) => {
|
||||
let mut ret = Vec::new();
|
||||
for v in vec {
|
||||
let wrapper = Self::get_nested_array(&v.into(), *key, filter_mode);
|
||||
let wrapper = Self::get_nested_array(v, *key, filter_mode);
|
||||
if !wrapper.is_null() {
|
||||
ret.push(wrapper.clone_data());
|
||||
ret.push(wrapper.clone());
|
||||
}
|
||||
}
|
||||
RefValue::Array(ret).into()
|
||||
@ -199,7 +199,7 @@ impl ValueFilter {
|
||||
|
||||
self.last_key = Some(ValueFilterKey::Num(key.index(&v)));
|
||||
self.vw.replace(v);
|
||||
trace!("step_in_num - after: {:?}", self.vw.get_val().get_data_ref());
|
||||
trace!("step_in_num - after: {:?}", self.vw.get_val());
|
||||
&self.vw
|
||||
}
|
||||
|
||||
@ -212,28 +212,27 @@ impl ValueFilter {
|
||||
trace!("step_in_string - before: {},{},{:?}"
|
||||
, self.vw.is_leaves()
|
||||
, self.filter_mode
|
||||
, self.vw.get_val().get_data_ref());
|
||||
, self.vw.get_val());
|
||||
|
||||
let filter_mode = self.filter_mode;
|
||||
let is_leaves = self.vw.is_leaves();
|
||||
let val = match self.vw.get_val().get_data_ref() {
|
||||
let val = match self.vw.get_val().deref() {
|
||||
RefValue::Array(ref vec) if is_leaves => {
|
||||
let mut buf = Vec::new();
|
||||
for mut v in vec {
|
||||
let wrapper: RefValueWrapper = v.into();
|
||||
if wrapper.is_array() {
|
||||
let vec = wrapper.as_array().unwrap();
|
||||
if v.is_array() {
|
||||
let vec = v.as_array().unwrap();
|
||||
let mut ret = Vec::new();
|
||||
for v in vec {
|
||||
let nested_wrapper = Self::get_nested_object(&v.into(), key, filter_mode);
|
||||
let nested_wrapper = Self::get_nested_object(v, key, filter_mode);
|
||||
if !nested_wrapper.is_null() {
|
||||
ret.push(nested_wrapper.clone_data());
|
||||
ret.push(nested_wrapper.clone());
|
||||
}
|
||||
}
|
||||
buf.append(&mut ret);
|
||||
} else {
|
||||
match wrapper.get(key.clone()) {
|
||||
Some(v) => buf.push(v.clone_data()),
|
||||
match v.get(key.clone()) {
|
||||
Some(v) => buf.push(v.clone()),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -244,9 +243,9 @@ impl ValueFilter {
|
||||
RefValue::Array(ref vec) if !is_leaves => {
|
||||
let mut ret = Vec::new();
|
||||
for v in vec {
|
||||
let wrapper = Self::get_nested_object(&v.into(), key, filter_mode);
|
||||
let wrapper = Self::get_nested_object(v, key, filter_mode);
|
||||
if !wrapper.is_null() {
|
||||
ret.push(wrapper.clone_data());
|
||||
ret.push(wrapper.clone());
|
||||
}
|
||||
}
|
||||
RefValue::Array(ret).into()
|
||||
@ -264,7 +263,7 @@ impl ValueFilter {
|
||||
trace!("step_in_string - after: {},{},{:?}"
|
||||
, self.vw.is_leaves()
|
||||
, self.filter_mode
|
||||
, self.vw.get_val().get_data_ref());
|
||||
, self.vw.get_val());
|
||||
&self.vw
|
||||
}
|
||||
}
|
||||
@ -304,7 +303,7 @@ impl JsonValueFilter {
|
||||
if from_current {
|
||||
self.filter_stack.last()
|
||||
.map(|vf| {
|
||||
ValueFilter::new(vf.vw.clone_val(), vf.vw.is_leaves(), from_current)
|
||||
ValueFilter::new(vf.vw.get_val().clone(), vf.vw.is_leaves(), from_current)
|
||||
})
|
||||
.and_then(|vf| {
|
||||
Some(self.filter_stack.push(vf))
|
||||
@ -334,10 +333,10 @@ impl JsonValueFilter {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current_value(&self) -> RefValueWrapper {
|
||||
pub fn into_value(&self) -> Value {
|
||||
match self.filter_stack.last() {
|
||||
Some(v) => v.vw.get_val().clone(),
|
||||
_ => RefValue::Null.into()
|
||||
Some(v) => v.vw.into_value(),
|
||||
_ => Value::Null
|
||||
}
|
||||
}
|
||||
|
||||
@ -354,12 +353,12 @@ impl JsonValueFilter {
|
||||
match self.filter_stack.last_mut() {
|
||||
Some(ref mut vf) if vf.vw.is_array() && vf.vw.is_leaves() => {
|
||||
let mut ret = Vec::new();
|
||||
if let RefValue::Array(val) = vf.vw.get_val().get_data_ref() {
|
||||
if let RefValue::Array(val) = vf.vw.get_val().deref() {
|
||||
for mut v in val {
|
||||
for i in &indices {
|
||||
let v = i.take_value(&v.into());
|
||||
let v = i.take_value(v);
|
||||
if !v.is_null() {
|
||||
ret.push(v.clone_data());
|
||||
ret.push(v.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -371,7 +370,7 @@ impl JsonValueFilter {
|
||||
for i in indices {
|
||||
let wrapper = i.take_value(&vf.vw.get_val());
|
||||
if !wrapper.is_null() {
|
||||
ret.push(wrapper.clone_data());
|
||||
ret.push(wrapper.clone());
|
||||
}
|
||||
}
|
||||
vf.vw.replace(RefValue::Array(ret).into());
|
||||
@ -391,7 +390,7 @@ impl JsonValueFilter {
|
||||
let to = match to {
|
||||
Some(v) => v.index(val),
|
||||
_ => {
|
||||
if let RefValue::Array(v) = val.get_data_ref() {
|
||||
if let RefValue::Array(v) = val.deref() {
|
||||
v.len()
|
||||
} else {
|
||||
0
|
||||
@ -401,24 +400,23 @@ impl JsonValueFilter {
|
||||
(from, to)
|
||||
}
|
||||
|
||||
fn _range(from: usize, to: usize, v: &RefValueWrapper) -> Vec<TypeRefValue> {
|
||||
fn _range(from: usize, to: usize, v: &RefValueWrapper) -> Vec<RefValueWrapper> {
|
||||
trace!("range - {}:{}", from, to);
|
||||
|
||||
(from..to).into_iter()
|
||||
.map(|i| i.take_value(v))
|
||||
.filter(|v| !v.is_null())
|
||||
.map(|v| v.clone_data())
|
||||
.map(|v| v.clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
match self.filter_stack.last_mut() {
|
||||
Some(ref mut vf) if vf.vw.is_array() && vf.vw.is_leaves() => {
|
||||
let mut buf = Vec::new();
|
||||
if let RefValue::Array(vec) = vf.vw.get_val().get_data_ref() {
|
||||
if let RefValue::Array(vec) = vf.vw.get_val().deref() {
|
||||
for mut v in vec {
|
||||
let wrapper = v.into();
|
||||
let (from, to) = _from_to(from, to, &wrapper);
|
||||
let mut v: Vec<TypeRefValue> = _range(from, to, &wrapper);
|
||||
let (from, to) = _from_to(from, to, v);
|
||||
let mut v: Vec<RefValueWrapper> = _range(from, to, v);
|
||||
buf.append(&mut v);
|
||||
}
|
||||
}
|
||||
@ -426,7 +424,7 @@ impl JsonValueFilter {
|
||||
}
|
||||
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 vec: Vec<TypeRefValue> = _range(from, to, vf.vw.get_val());
|
||||
let vec: Vec<RefValueWrapper> = _range(from, to, vf.vw.get_val());
|
||||
vf.vw.replace(RefValue::Array(vec).into());
|
||||
}
|
||||
_ => {}
|
||||
@ -489,7 +487,7 @@ impl JsonValueFilter {
|
||||
match self.filter_stack.pop() {
|
||||
Some(mut vf) => {
|
||||
let is_leaves = vf.vw.is_leaves();
|
||||
match vf.vw.get_val().get_data_ref() {
|
||||
match vf.vw.get_val().deref() {
|
||||
RefValue::Null | RefValue::Bool(false) => {
|
||||
self.replace_filter_stack(RefValue::Null.into(), is_leaves);
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
use indexmap::map::IndexMap;
|
||||
use std::ops::Deref;
|
||||
|
||||
use ref_value::*;
|
||||
use indexmap::IndexSet;
|
||||
use serde_json::Value;
|
||||
|
||||
use ref_value::model::*;
|
||||
|
||||
use super::cmp::*;
|
||||
use super::term::*;
|
||||
@ -40,7 +43,7 @@ impl ValueWrapper {
|
||||
}
|
||||
|
||||
fn cmp_with_term<F: PrivCmp>(val: &RefValueWrapper, et: &ExprTerm, cmp_fn: &F, default: bool, reverse: bool) -> bool {
|
||||
match val.get_data_ref() {
|
||||
match val.deref() {
|
||||
RefValue::Bool(ref v1) => {
|
||||
match et {
|
||||
ExprTerm::Bool(v2) => if reverse { cmp_fn.cmp_bool(v2, v1) } else { cmp_fn.cmp_bool(v1, v2) },
|
||||
@ -63,10 +66,10 @@ impl ValueWrapper {
|
||||
|
||||
fn take_object_in_array<F: PrivCmp>(&self, key: &String, et: &ExprTerm, cmp: &F, reverse: bool) -> Option<Self> {
|
||||
fn _filter_with_object<F: Fn(&RefValueWrapper) -> bool>(v: &RefValueWrapper, key: &String, fun: F) -> bool {
|
||||
match v.get_data_ref() {
|
||||
match v.deref() {
|
||||
RefValue::Object(map) => {
|
||||
match map.get(key) {
|
||||
Some(val) => fun(&val.into()),
|
||||
Some(val) => fun(val),
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
@ -74,11 +77,11 @@ impl ValueWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
match self.val.get_data_ref() {
|
||||
match self.val.deref() {
|
||||
RefValue::Array(vec) => {
|
||||
let mut ret = Vec::new();
|
||||
for v in vec {
|
||||
if _filter_with_object(&v.into(), key, |vv| {
|
||||
if _filter_with_object(v, key, |vv| {
|
||||
Self::cmp_with_term(vv, et, cmp, false, reverse)
|
||||
}) {
|
||||
ret.push(v.clone());
|
||||
@ -104,11 +107,11 @@ impl ValueWrapper {
|
||||
match self.take_with_key_type(key, et, &cmp, reverse) {
|
||||
Some(vw) => vw,
|
||||
_ => {
|
||||
match self.val.get_data_ref() {
|
||||
match &(*self.val) {
|
||||
RefValue::Array(vec) => {
|
||||
let mut ret = Vec::new();
|
||||
for v in vec {
|
||||
if Self::cmp_with_term(&v.into(), et, &cmp, false, reverse) {
|
||||
if Self::cmp_with_term(v, et, &cmp, false, reverse) {
|
||||
ret.push(v.clone());
|
||||
}
|
||||
}
|
||||
@ -127,14 +130,13 @@ impl ValueWrapper {
|
||||
}
|
||||
|
||||
pub fn replace(&mut self, val: RefValueWrapper) {
|
||||
let is_null = match val.get_data_ref() {
|
||||
let is_null = match val.deref() {
|
||||
RefValue::Array(v) => if v.is_empty() { true } else { false },
|
||||
RefValue::Object(m) => if m.is_empty() { true } else { false },
|
||||
_ => val.is_null()
|
||||
};
|
||||
self.val = if is_null {
|
||||
let v = RefValueWrapper::wrap(RefValue::Null);
|
||||
RefValueWrapper::new(v)
|
||||
RefValue::Null.into()
|
||||
} else {
|
||||
val
|
||||
};
|
||||
@ -144,135 +146,98 @@ impl ValueWrapper {
|
||||
&self.val
|
||||
}
|
||||
|
||||
pub fn clone_val(&self) -> RefValueWrapper {
|
||||
self.val.clone()
|
||||
pub fn into_value(&self) -> Value {
|
||||
self.get_val().into()
|
||||
}
|
||||
|
||||
pub fn is_array(&self) -> bool {
|
||||
self.val.is_array()
|
||||
}
|
||||
|
||||
fn uuid(v: &RefValueWrapper) -> String {
|
||||
fn _fn(v: &RefValueWrapper, acc: &mut String) {
|
||||
match v.get_data_ref() {
|
||||
RefValue::Null => acc.push_str("null"),
|
||||
RefValue::String(v) => acc.push_str(v),
|
||||
RefValue::Bool(v) => acc.push_str(if *v { "true" } else { "false" }),
|
||||
RefValue::Number(v) => acc.push_str(&*v.to_string()),
|
||||
RefValue::Array(v) => {
|
||||
for (i, v) in v.iter().enumerate() {
|
||||
acc.push_str(&*i.to_string());
|
||||
_fn(&v.into(), acc);
|
||||
}
|
||||
}
|
||||
RefValue::Object(ref v) => {
|
||||
for (k, v) in v.into_iter() {
|
||||
acc.push_str(&*k.to_string());
|
||||
_fn(&v.into(), acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut acc = String::new();
|
||||
_fn(v, &mut acc);
|
||||
acc
|
||||
}
|
||||
|
||||
fn into_map(&self) -> IndexMap<String, RefValueWrapper> {
|
||||
let mut map = IndexMap::new();
|
||||
match self.val.get_data_ref() {
|
||||
fn into_hashset(&self) -> IndexSet<RefValueWrapper> {
|
||||
let mut hashset = IndexSet::new();
|
||||
match self.val.deref() {
|
||||
RefValue::Array(ref v1) => {
|
||||
for v in v1 {
|
||||
let wrapper = v.into();
|
||||
let key = Self::uuid(&wrapper);
|
||||
map.insert(key, wrapper);
|
||||
hashset.insert(v.clone());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
map.insert(Self::uuid(&self.val), self.val.clone());
|
||||
hashset.insert(self.val.clone());
|
||||
}
|
||||
}
|
||||
map
|
||||
hashset
|
||||
}
|
||||
|
||||
pub fn except(&self, other: &Self) -> Self {
|
||||
let map = self.into_map();
|
||||
let mut ret: IndexMap<String, RefValueWrapper> = IndexMap::new();
|
||||
match other.val.get_data_ref() {
|
||||
let hashset = self.into_hashset();
|
||||
let mut ret: IndexSet<RefValueWrapper> = IndexSet::new();
|
||||
match &(*other.val) {
|
||||
RefValue::Array(ref v1) => {
|
||||
for v in v1 {
|
||||
let wrapper = v.into();
|
||||
let key = Self::uuid(&wrapper);
|
||||
if !map.contains_key(&key) {
|
||||
ret.insert(key, wrapper);
|
||||
if !hashset.contains(v) {
|
||||
ret.insert(v.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let key = Self::uuid(&other.val);
|
||||
if !map.contains_key(&key) {
|
||||
ret.insert(key, other.val.clone());
|
||||
if !hashset.contains(&other.val) {
|
||||
ret.insert(other.val.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let vec = ret.values().into_iter().map(|v| v.clone_data()).collect();
|
||||
let vec = ret.into_iter().map(|v| v.clone()).collect();
|
||||
ValueWrapper::new(RefValue::Array(vec).into(), false)
|
||||
}
|
||||
|
||||
pub fn intersect(&self, other: &Self) -> Self {
|
||||
let map = self.into_map();
|
||||
let mut ret: IndexMap<String, RefValueWrapper> = IndexMap::new();
|
||||
match other.val.get_data_ref() {
|
||||
let hashset = self.into_hashset();
|
||||
let mut ret: IndexSet<RefValueWrapper> = IndexSet::new();
|
||||
match other.val.deref() {
|
||||
RefValue::Array(ref v1) => {
|
||||
for v in v1 {
|
||||
let wrapper = v.into();
|
||||
let key = Self::uuid(&wrapper);
|
||||
if map.contains_key(&key) {
|
||||
ret.insert(key, wrapper);
|
||||
if hashset.contains(v) {
|
||||
ret.insert(v.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let key = Self::uuid(&other.val);
|
||||
if map.contains_key(&key) {
|
||||
ret.insert(key, other.val.clone());
|
||||
if hashset.contains(&other.val) {
|
||||
ret.insert(other.val.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let vec = ret.values().into_iter().map(|v| v.clone_data()).collect();
|
||||
let vec = ret.into_iter().map(|v| v.clone()).collect();
|
||||
ValueWrapper::new(RefValue::Array(vec).into(), false)
|
||||
}
|
||||
|
||||
pub fn union(&self, other: &Self) -> Self {
|
||||
let mut map = self.into_map();
|
||||
match other.val.get_data_ref() {
|
||||
let mut hashset = self.into_hashset();
|
||||
match other.val.deref() {
|
||||
RefValue::Array(ref v1) => {
|
||||
for v in v1 {
|
||||
let wrapper = v.into();
|
||||
let key = Self::uuid(&wrapper);
|
||||
if !map.contains_key(&key) {
|
||||
map.insert(key, wrapper);
|
||||
if !hashset.contains(v) {
|
||||
hashset.insert(v.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let key = Self::uuid(&other.val);
|
||||
if !map.contains_key(&key) {
|
||||
map.insert(key, other.val.clone());
|
||||
if !hashset.contains(&other.val) {
|
||||
hashset.insert(other.val.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut vw = ValueWrapper::new(RefValue::Null.into(), false);
|
||||
let list = map.values().into_iter().map(|val| val.clone_data()).collect();
|
||||
let list = hashset.into_iter().map(|val| val.clone()).collect();
|
||||
vw.replace(RefValue::Array(list).into());
|
||||
vw
|
||||
}
|
||||
|
||||
pub fn into_term(&self, key: &Option<ValueFilterKey>) -> TermContext {
|
||||
match self.val.get_data_ref() {
|
||||
match self.val.deref() {
|
||||
RefValue::String(ref s) => TermContext::Constants(ExprTerm::String(s.clone())),
|
||||
RefValue::Number(ref n) => TermContext::Constants(ExprTerm::Number(n.as_f64().unwrap())),
|
||||
RefValue::Bool(b) => TermContext::Constants(ExprTerm::Bool(*b)),
|
||||
@ -284,13 +249,12 @@ impl ValueWrapper {
|
||||
}
|
||||
|
||||
pub fn filter(&self, key: &Option<ValueFilterKey>) -> Self {
|
||||
let v = match self.val.get_data_ref() {
|
||||
let v = match self.val.deref() {
|
||||
RefValue::Array(ref vec) => {
|
||||
let mut ret = Vec::new();
|
||||
for v in vec {
|
||||
if let Some(ValueFilterKey::String(k)) = key {
|
||||
let wrapper: RefValueWrapper = v.into();
|
||||
if wrapper.get(k.clone()).is_some() {
|
||||
if v.get(k.clone()).is_some() {
|
||||
ret.push(v.clone());
|
||||
}
|
||||
}
|
||||
@ -300,7 +264,7 @@ impl ValueWrapper {
|
||||
RefValue::Object(ref map) => {
|
||||
match key {
|
||||
Some(ValueFilterKey::String(k)) => match map.get(k) {
|
||||
Some(v) => v.into(),
|
||||
Some(v) => v.clone(),
|
||||
_ => RefValue::Null.into()
|
||||
},
|
||||
_ => RefValue::Null.into()
|
||||
|
51
src/lib.rs
51
src/lib.rs
@ -158,11 +158,18 @@
|
||||
//! assert_eq!(ret, json);
|
||||
//! ```
|
||||
|
||||
extern crate env_logger;
|
||||
extern crate indexmap;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate env_logger;
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
extern crate indexmap;
|
||||
|
||||
use std::result;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use prelude::*;
|
||||
|
||||
#[doc(hidden)]
|
||||
mod parser;
|
||||
@ -172,14 +179,6 @@ mod filter;
|
||||
mod ref_value;
|
||||
pub mod prelude;
|
||||
|
||||
use parser::prelude::*;
|
||||
use filter::prelude::*;
|
||||
|
||||
use std::result;
|
||||
use serde_json::Value;
|
||||
|
||||
use ref_value::*;
|
||||
|
||||
type Result = result::Result<Value, String>;
|
||||
|
||||
/// # Read multiple Json multiple times with the same JsonPath
|
||||
@ -222,7 +221,7 @@ pub fn compile<'a>(path: &'a str) -> impl FnMut(&Value) -> Result + 'a {
|
||||
Ok(n) => {
|
||||
let mut jf = JsonValueFilter::new_from_value(json.into());
|
||||
jf.visit(n.clone());
|
||||
Ok(jf.take_value().into_value())
|
||||
Ok(jf.take_value().into())
|
||||
}
|
||||
Err(e) => Err(e.clone())
|
||||
}
|
||||
@ -259,7 +258,7 @@ pub fn selector(json: &Value) -> impl FnMut(&str) -> Result {
|
||||
let mut jf = JsonValueFilter::new_from_value(wrapper.clone());
|
||||
let mut parser = Parser::new(path);
|
||||
parser.parse(&mut jf)?;
|
||||
Ok(jf.take_value().into_value())
|
||||
Ok(jf.take_value().into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,7 +287,7 @@ pub fn select(json: &Value, path: &str) -> Result {
|
||||
let mut jf = JsonValueFilter::new_from_value(json.into());
|
||||
let mut parser = Parser::new(path);
|
||||
parser.parse(&mut jf)?;
|
||||
Ok(jf.take_value().into_value())
|
||||
Ok(jf.take_value().into())
|
||||
}
|
||||
|
||||
/// # Read Json using JsonPath - Deprecated. use select
|
||||
@ -296,3 +295,29 @@ pub fn read(json: &Value, path: &str) -> Result {
|
||||
select(json, path)
|
||||
}
|
||||
|
||||
/// # Read Json string using JsonPath
|
||||
///
|
||||
/// ```rust
|
||||
/// extern crate jsonpath_lib as jsonpath;
|
||||
/// #[macro_use] extern crate serde_json;
|
||||
///
|
||||
/// use serde_json::Value;
|
||||
///
|
||||
/// let json_obj = json!({
|
||||
/// "school": {
|
||||
/// "friends": [{"id": 0}, {"id": 1}]
|
||||
/// },
|
||||
/// "friends": [{"id": 0}, {"id": 1}]
|
||||
/// });
|
||||
/// let json_str = jsonpath::select_str(&serde_json::to_string(&json_obj).unwrap(), "$..friends[0]").unwrap();
|
||||
/// let json: Value = serde_json::from_str(&json_str).unwrap();
|
||||
/// let ret = json!([ {"id": 0}, {"id": 0} ]);
|
||||
/// assert_eq!(json, ret);
|
||||
/// ```
|
||||
pub fn select_str(json: &str, path: &str) -> result::Result<String, String> {
|
||||
let ref_value: RefValue = serde_json::from_str(json).map_err(|e| format!("{:?}", e))?;
|
||||
let mut jf = JsonValueFilter::new_from_value(ref_value.into());
|
||||
let mut parser = Parser::new(path);
|
||||
parser.parse(&mut jf)?;
|
||||
serde_json::to_string(&jf.take_value()).map_err(|e| format!("{:?}", e))
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
pub use parser::prelude::*;
|
||||
pub use filter::prelude::*;
|
||||
pub use ref_value::*;
|
||||
pub use ref_value::model::*;
|
111
src/ref_value/convert.rs
Normal file
111
src/ref_value/convert.rs
Normal file
@ -0,0 +1,111 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use serde_json::Value;
|
||||
|
||||
use ref_value::model::{RefValue, RefValueWrapper};
|
||||
|
||||
pub struct RefValueConverter;
|
||||
|
||||
impl RefValueConverter {
|
||||
pub fn new(value: &Value) -> RefValueWrapper {
|
||||
RefValueConverter {}.visit_value(value)
|
||||
}
|
||||
|
||||
fn visit_value(&self, value: &Value) -> RefValueWrapper {
|
||||
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) -> RefValueWrapper {
|
||||
RefValue::Null.into()
|
||||
}
|
||||
|
||||
fn visit_bool(&self, value: &bool) -> RefValueWrapper {
|
||||
RefValue::Bool(*value).into()
|
||||
}
|
||||
|
||||
fn visit_number(&self, value: &serde_json::Number) -> RefValueWrapper {
|
||||
RefValue::Number(value.clone()).into()
|
||||
}
|
||||
|
||||
fn visit_string(&self, value: &String) -> RefValueWrapper {
|
||||
RefValue::String(value.to_string()).into()
|
||||
}
|
||||
|
||||
fn visit_array(&self, value: &Vec<Value>) -> RefValueWrapper {
|
||||
let mut values = Vec::new();
|
||||
for v in value {
|
||||
values.push(self.visit_value(v));
|
||||
}
|
||||
RefValue::Array(values).into()
|
||||
}
|
||||
|
||||
fn visit_object(&self, value: &serde_json::Map<String, Value>) -> RefValueWrapper {
|
||||
let mut map = IndexMap::new();
|
||||
for (key, _) in value {
|
||||
let value = self.visit_value(match value.get(key) {
|
||||
Some(v) => v,
|
||||
_ => &Value::Null
|
||||
});
|
||||
map.insert(key.clone(), value);
|
||||
}
|
||||
RefValue::Object(map).into()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ValueConverter;
|
||||
|
||||
impl ValueConverter {
|
||||
pub fn new(value: &RefValueWrapper) -> Value {
|
||||
ValueConverter {}.visit_value(value)
|
||||
}
|
||||
|
||||
fn visit_value(&self, value: &RefValueWrapper) -> Value {
|
||||
match value.deref() {
|
||||
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<RefValueWrapper>) -> 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, RefValueWrapper>) -> Value {
|
||||
let mut ret = serde_json::Map::new();
|
||||
let tmp_null = &RefValue::Null.into();
|
||||
for (k, _) in map {
|
||||
let value = self.visit_value(match map.get(k) {
|
||||
Some(e) => e,
|
||||
_ => tmp_null
|
||||
});
|
||||
ret.insert(k.to_string(), value);
|
||||
}
|
||||
Value::Object(ret)
|
||||
}
|
||||
}
|
119
src/ref_value/de.rs
Normal file
119
src/ref_value/de.rs
Normal file
@ -0,0 +1,119 @@
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::result::Result;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use serde::de::{MapAccess, SeqAccess, Visitor};
|
||||
use serde_json::Value;
|
||||
|
||||
use super::model::*;
|
||||
|
||||
impl<'de> Deserialize<'de> for RefValue {
|
||||
fn deserialize<D>(deserializer: D) -> Result<RefValue, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_any(RefValueVisitor {})
|
||||
}
|
||||
}
|
||||
|
||||
struct RefValueVisitor {}
|
||||
|
||||
impl<'de> Visitor<'de> for RefValueVisitor {
|
||||
type Value = RefValue;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("any valid JSON value")
|
||||
}
|
||||
|
||||
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error, {
|
||||
Ok(RefValue::Bool(v))
|
||||
}
|
||||
|
||||
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error, {
|
||||
Ok(RefValue::Number(v.into()))
|
||||
}
|
||||
|
||||
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error, {
|
||||
Ok(RefValue::Number(v.into()))
|
||||
}
|
||||
|
||||
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error, {
|
||||
let n: Value = v.into();
|
||||
if let Value::Number(n) = n {
|
||||
Ok(RefValue::Number(n))
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error, {
|
||||
self.visit_string(String::from(v))
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error, {
|
||||
Ok(RefValue::String(v))
|
||||
}
|
||||
|
||||
fn visit_none<E>(self) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error, {
|
||||
Ok(RefValue::Null)
|
||||
}
|
||||
|
||||
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error> where
|
||||
D: Deserializer<'de>, {
|
||||
Deserialize::deserialize(deserializer)
|
||||
}
|
||||
|
||||
fn visit_unit<E>(self) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error, {
|
||||
Ok(RefValue::Null)
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut visitor: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>, {
|
||||
let mut vec = Vec::new();
|
||||
|
||||
while let Some(elem) = visitor.next_element()? {
|
||||
let e: RefValue = elem;
|
||||
let v: RefValueWrapper = e.into();
|
||||
vec.push(v);
|
||||
}
|
||||
|
||||
Ok(RefValue::Array(vec))
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, mut visitor: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: MapAccess<'de>, {
|
||||
let mut values = IndexMap::new();
|
||||
match visitor.next_key() {
|
||||
Ok(Some(first_key)) => {
|
||||
let next: RefValue = visitor.next_value()?;
|
||||
values.insert(first_key, next.into());
|
||||
while let Some((k, v)) = visitor.next_entry()? {
|
||||
let value: RefValue = v;
|
||||
values.insert(k, value.into());
|
||||
}
|
||||
Ok(RefValue::Object(values))
|
||||
}
|
||||
_ => Ok(RefValue::Object(IndexMap::new())),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,382 +1,5 @@
|
||||
extern crate indexmap;
|
||||
extern crate serde_json;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::convert::Into;
|
||||
|
||||
use indexmap::map::IndexMap;
|
||||
use serde_json::{Number, 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.clone()))
|
||||
}
|
||||
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, 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(&k) {
|
||||
Some(v) => v,
|
||||
_ => &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)
|
||||
}
|
||||
}
|
||||
pub mod model;
|
||||
mod convert;
|
||||
pub mod de;
|
||||
pub mod ser;
|
||||
//mod utf8;
|
257
src/ref_value/model.rs
Normal file
257
src/ref_value/model.rs
Normal file
@ -0,0 +1,257 @@
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
use indexmap::map::IndexMap;
|
||||
use serde_json::{Number, Value};
|
||||
|
||||
use super::convert::*;
|
||||
|
||||
type TypeRefValue = Arc<Box<RefValue>>;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct RefValueWrapper {
|
||||
data: TypeRefValue
|
||||
}
|
||||
|
||||
impl Eq for RefValueWrapper {}
|
||||
|
||||
impl Deref for RefValueWrapper {
|
||||
type Target = RefValue;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&(**self.data)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for RefValueWrapper {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.deref().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for RefValueWrapper {
|
||||
fn clone(&self) -> Self {
|
||||
RefValueWrapper {
|
||||
data: self.data.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// serde_json::Value 참고
|
||||
///
|
||||
pub trait RefIndex {
|
||||
fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v RefValueWrapper>;
|
||||
fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut RefValueWrapper>;
|
||||
fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut RefValueWrapper;
|
||||
}
|
||||
|
||||
impl RefIndex for usize {
|
||||
fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v RefValueWrapper> {
|
||||
match *v {
|
||||
RefValue::Array(ref vec) => vec.get(*self),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut RefValueWrapper> {
|
||||
match *v {
|
||||
RefValue::Array(ref mut vec) => vec.get_mut(*self),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut RefValueWrapper {
|
||||
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 RefValueWrapper> {
|
||||
match *v {
|
||||
RefValue::Object(ref map) => map.get(self),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut RefValueWrapper> {
|
||||
match *v {
|
||||
RefValue::Object(ref mut map) => map.get_mut(self),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut RefValueWrapper {
|
||||
if let RefValue::Null = *v {
|
||||
*v = RefValue::Object(IndexMap::new());
|
||||
}
|
||||
match *v {
|
||||
RefValue::Object(ref mut map) => {
|
||||
map.entry(self.to_owned()).or_insert(RefValue::Null.into())
|
||||
}
|
||||
_ => panic!("cannot access key {:?} in JSON {:?}", self, v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RefIndex for String {
|
||||
fn index_into<'v>(&self, v: &'v RefValue) -> Option<&'v RefValueWrapper> {
|
||||
self[..].index_into(v)
|
||||
}
|
||||
fn index_into_mut<'v>(&self, v: &'v mut RefValue) -> Option<&'v mut RefValueWrapper> {
|
||||
self[..].index_into_mut(v)
|
||||
}
|
||||
fn index_or_insert<'v>(&self, v: &'v mut RefValue) -> &'v mut RefValueWrapper {
|
||||
self[..].index_or_insert(v)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum RefValue {
|
||||
Null,
|
||||
Bool(bool),
|
||||
Number(Number),
|
||||
String(String),
|
||||
Array(Vec<RefValueWrapper>),
|
||||
Object(IndexMap<String, RefValueWrapper>),
|
||||
}
|
||||
|
||||
impl Hash for RefValue {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
match self {
|
||||
RefValue::Null => RefValue::Null.hash(state),
|
||||
RefValue::Bool(b) => b.hash(state),
|
||||
RefValue::Number(n) => {
|
||||
if n.is_f64() {
|
||||
n.as_f64().unwrap().to_string().hash(state)
|
||||
} else if n.is_i64() {
|
||||
n.as_i64().unwrap().hash(state);
|
||||
} else {
|
||||
n.as_u64().unwrap().hash(state);
|
||||
}
|
||||
}
|
||||
RefValue::String(s) => s.hash(state),
|
||||
RefValue::Object(map) => {
|
||||
for (_, v) in map {
|
||||
v.hash(state);
|
||||
}
|
||||
}
|
||||
RefValue::Array(v) => {
|
||||
for i in v {
|
||||
i.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for RefValue {}
|
||||
|
||||
impl RefValue {
|
||||
pub fn get<I: RefIndex>(&self, index: I) -> Option<&RefValueWrapper> {
|
||||
index.index_into(self)
|
||||
}
|
||||
|
||||
pub fn is_object(&self) -> bool {
|
||||
self.as_object().is_some()
|
||||
}
|
||||
|
||||
pub fn as_object(&self) -> Option<&IndexMap<String, RefValueWrapper>> {
|
||||
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<RefValueWrapper>> {
|
||||
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 {
|
||||
RefValueWrapper {
|
||||
data: Arc::new(Box::new(self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<RefValueWrapper> for &Value {
|
||||
fn into(self) -> RefValueWrapper {
|
||||
RefValueConverter::new(&self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Value> for RefValueWrapper {
|
||||
fn into(self) -> Value {
|
||||
ValueConverter::new(&self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Value> for &RefValueWrapper {
|
||||
fn into(self) -> Value {
|
||||
ValueConverter::new(&self)
|
||||
}
|
||||
}
|
63
src/ref_value/ser.rs
Normal file
63
src/ref_value/ser.rs
Normal file
@ -0,0 +1,63 @@
|
||||
use std::result::Result;
|
||||
|
||||
use serde::{self, Serialize};
|
||||
|
||||
use ref_value::model::{RefValue, RefValueWrapper};
|
||||
|
||||
impl Serialize for RefValue {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where
|
||||
S: serde::Serializer {
|
||||
match *self {
|
||||
RefValue::Null => serializer.serialize_unit(),
|
||||
RefValue::Bool(b) => serializer.serialize_bool(b),
|
||||
RefValue::Number(ref n) => n.serialize(serializer),
|
||||
RefValue::String(ref s) => serializer.serialize_str(s),
|
||||
RefValue::Array(ref v) => {
|
||||
use std::ops::Deref;
|
||||
let v: Vec<&RefValue> = v.iter().map(|v| v.deref()).collect();
|
||||
v.serialize(serializer)
|
||||
},
|
||||
RefValue::Object(ref m) => {
|
||||
use serde::ser::SerializeMap;
|
||||
use std::ops::Deref;
|
||||
let mut map = serializer.serialize_map(Some(m.len()))?;
|
||||
for (k, v) in m {
|
||||
map.serialize_key(k)?;
|
||||
map.serialize_value(v.deref())?;
|
||||
}
|
||||
map.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for RefValueWrapper {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where
|
||||
S: serde::Serializer {
|
||||
use std::ops::Deref;
|
||||
|
||||
match *self.deref() {
|
||||
RefValue::Null => serializer.serialize_unit(),
|
||||
RefValue::Bool(b) => serializer.serialize_bool(b),
|
||||
RefValue::Number(ref n) => n.serialize(serializer),
|
||||
RefValue::String(ref s) => serializer.serialize_str(s),
|
||||
RefValue::Array(ref v) => {
|
||||
use std::ops::Deref;
|
||||
let v: Vec<&RefValue> = v.iter().map(|v| v.deref()).collect();
|
||||
v.serialize(serializer)
|
||||
},
|
||||
RefValue::Object(ref m) => {
|
||||
use serde::ser::SerializeMap;
|
||||
use std::ops::Deref;
|
||||
let mut map = serializer.serialize_map(Some(m.len()))?;
|
||||
for (k, v) in m {
|
||||
map.serialize_key(k)?;
|
||||
map.serialize_value(v.deref())?;
|
||||
}
|
||||
map.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
52
src/ref_value/utf8.rs
Normal file
52
src/ref_value/utf8.rs
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
const TAG_CONT: u8 = 0b1000_0000;
|
||||
const TAG_TWO_B: u8 = 0b1100_0000;
|
||||
const TAG_THREE_B: u8 = 0b1110_0000;
|
||||
const TAG_FOUR_B: u8 = 0b1111_0000;
|
||||
const MAX_ONE_B: u32 = 0x80;
|
||||
const MAX_TWO_B: u32 = 0x800;
|
||||
const MAX_THREE_B: u32 = 0x10000;
|
||||
|
||||
#[inline]
|
||||
pub fn encode(c: char) -> Encode {
|
||||
let code = c as u32;
|
||||
let mut buf = [0; 4];
|
||||
let pos = if code < MAX_ONE_B {
|
||||
buf[3] = code as u8;
|
||||
3
|
||||
} else if code < MAX_TWO_B {
|
||||
buf[2] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
2
|
||||
} else if code < MAX_THREE_B {
|
||||
buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
|
||||
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
1
|
||||
} else {
|
||||
buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
|
||||
buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
0
|
||||
};
|
||||
Encode { buf: buf, pos: pos }
|
||||
}
|
||||
|
||||
pub struct Encode {
|
||||
buf: [u8; 4],
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl Encode {
|
||||
pub fn as_str(&self) -> &str {
|
||||
std::str::from_utf8(&self.buf[self.pos..]).unwrap()
|
||||
}
|
||||
}
|
@ -64,7 +64,8 @@ fn step_in() {
|
||||
"Vincent Cannon",
|
||||
"Gray Berry"
|
||||
]);
|
||||
assert_eq!(friends, current.get_val().into_value());
|
||||
|
||||
assert_eq!(friends, current.into_value());
|
||||
}
|
||||
let mut jf = new_value_filter("./benches/data_obj.json");
|
||||
{
|
||||
@ -77,7 +78,7 @@ fn step_in() {
|
||||
"Vincent Cannon",
|
||||
"Gray Berry"
|
||||
]);
|
||||
assert_eq!(names, current.get_val().into_value());
|
||||
assert_eq!(names, current.into_value());
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,32 +92,32 @@ fn array() {
|
||||
]);
|
||||
|
||||
let jf = do_filter("$.school.friends[1, 2]", "./benches/data_obj.json");
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
|
||||
let jf = do_filter("$.school.friends[1:]", "./benches/data_obj.json");
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
|
||||
let jf = do_filter("$.school.friends[:-2]", "./benches/data_obj.json");
|
||||
let friends = json!([
|
||||
{"id": 0, "name": "Millicent Norman"}
|
||||
]);
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
|
||||
let jf = do_filter("$..friends[2].name", "./benches/data_obj.json");
|
||||
let friends = json!(["Gray Berry", "Gray Berry"]);
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
|
||||
let jf = do_filter("$..friends[*].name", "./benches/data_obj.json");
|
||||
let friends = json!(["Vincent Cannon","Gray Berry","Millicent Norman","Vincent Cannon","Gray Berry"]);
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
|
||||
let jf = do_filter("$['school']['friends'][*].['name']", "./benches/data_obj.json");
|
||||
let friends = json!(["Millicent Norman","Vincent Cannon","Gray Berry"]);
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
|
||||
let jf = do_filter("$['school']['friends'][0].['name']", "./benches/data_obj.json");
|
||||
let friends = json!("Millicent Norman");
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -132,16 +133,16 @@ fn return_type() {
|
||||
});
|
||||
|
||||
let jf = do_filter("$.school", "./benches/data_obj.json");
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
|
||||
let jf = do_filter("$.school[?(@.friends[0])]", "./benches/data_obj.json");
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
|
||||
let jf = do_filter("$.school[?(@.friends[10])]", "./benches/data_obj.json");
|
||||
assert_eq!(Value::Null, jf.current_value().into_value());
|
||||
assert_eq!(Value::Null, jf.into_value());
|
||||
|
||||
let jf = do_filter("$.school[?(1==1)]", "./benches/data_obj.json");
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
|
||||
let jf = do_filter("$.school.friends[?(1==1)]", "./benches/data_obj.json");
|
||||
let friends = json!([
|
||||
@ -149,7 +150,7 @@ fn return_type() {
|
||||
{"id": 1, "name": "Vincent Cannon" },
|
||||
{"id": 2, "name": "Gray Berry"}
|
||||
]);
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -164,42 +165,42 @@ fn op() {
|
||||
{"id": 2, "name": "Gray Berry"}
|
||||
]
|
||||
});
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
|
||||
let jf = do_filter("$.friends[?(@.name)]", "./benches/data_obj.json");
|
||||
let friends = json!([
|
||||
{ "id" : 1, "name" : "Vincent Cannon" },
|
||||
{ "id" : 2, "name" : "Gray Berry" }
|
||||
]);
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
|
||||
let jf = do_filter("$.friends[?(@.id >= 2)]", "./benches/data_obj.json");
|
||||
let friends = json!([
|
||||
{ "id" : 2, "name" : "Gray Berry" }
|
||||
]);
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
|
||||
let jf = do_filter("$.friends[?(@.id >= 2 || @.id == 1)]", "./benches/data_obj.json");
|
||||
let friends = json!([
|
||||
{ "id" : 2, "name" : "Gray Berry" },
|
||||
{ "id" : 1, "name" : "Vincent Cannon" }
|
||||
]);
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
|
||||
let jf = do_filter("$.friends[?( (@.id >= 2 || @.id == 1) && @.id == 0)]", "./benches/data_obj.json");
|
||||
assert_eq!(Value::Null, jf.current_value().into_value());
|
||||
assert_eq!(Value::Null, jf.into_value());
|
||||
|
||||
let jf = do_filter("$..friends[?(@.id == $.index)].id", "./benches/data_obj.json");
|
||||
let friends = json!([0, 0]);
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
|
||||
let jf = do_filter("$..book[?($.store.bicycle.price < @.price)].price", "./benches/example.json");
|
||||
let friends = json!([22.99]);
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
|
||||
let jf = do_filter("$..book[?( (@.price == 12.99 || @.category == 'reference') && @.price > 10)].price", "./benches/example.json");
|
||||
let friends = json!([12.99]);
|
||||
assert_eq!(friends, jf.current_value().into_value());
|
||||
assert_eq!(friends, jf.into_value());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -208,10 +209,10 @@ fn example() {
|
||||
|
||||
let jf = do_filter("$.store.book[*].author", "./benches/example.json");
|
||||
let ret = json!(["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]);
|
||||
assert_eq!(ret, jf.current_value().into_value());
|
||||
assert_eq!(ret, jf.into_value());
|
||||
|
||||
let jf = do_filter("$..author", "./benches/example.json");
|
||||
assert_eq!(ret, jf.current_value().into_value());
|
||||
assert_eq!(ret, jf.into_value());
|
||||
|
||||
let jf = do_filter("$.store.*", "./benches/example.json");
|
||||
let ret = json!([
|
||||
@ -223,11 +224,11 @@ fn example() {
|
||||
],
|
||||
{"color" : "red","price" : 19.95},
|
||||
]);
|
||||
assert_eq!(ret, jf.current_value().into_value());
|
||||
assert_eq!(ret, jf.into_value());
|
||||
|
||||
let jf = do_filter("$.store..price", "./benches/example.json");
|
||||
let ret = json!([8.95, 12.99, 8.99, 22.99, 19.95]);
|
||||
assert_eq!(ret, jf.current_value().into_value());
|
||||
assert_eq!(ret, jf.into_value());
|
||||
|
||||
let jf = do_filter("$..book[2]", "./benches/example.json");
|
||||
let ret = json!([{
|
||||
@ -237,7 +238,7 @@ fn example() {
|
||||
"isbn" : "0-553-21311-3",
|
||||
"price" : 8.99
|
||||
}]);
|
||||
assert_eq!(ret, jf.current_value().into_value());
|
||||
assert_eq!(ret, jf.into_value());
|
||||
|
||||
let jf = do_filter("$..book[-2]", "./benches/example.json");
|
||||
let ret = json!([{
|
||||
@ -247,7 +248,7 @@ fn example() {
|
||||
"isbn" : "0-553-21311-3",
|
||||
"price" : 8.99
|
||||
}]);
|
||||
assert_eq!(ret, jf.current_value().into_value());
|
||||
assert_eq!(ret, jf.into_value());
|
||||
|
||||
let jf = do_filter("$..book[0,1]", "./benches/example.json");
|
||||
let ret = json!([
|
||||
@ -264,7 +265,7 @@ fn example() {
|
||||
"price" : 12.99
|
||||
}
|
||||
]);
|
||||
assert_eq!(ret, jf.current_value().into_value());
|
||||
assert_eq!(ret, jf.into_value());
|
||||
|
||||
let jf = do_filter("$..book[:2]", "./benches/example.json");
|
||||
let ret = json!([
|
||||
@ -281,7 +282,7 @@ fn example() {
|
||||
"price" : 12.99
|
||||
}
|
||||
]);
|
||||
assert_eq!(ret, jf.current_value().into_value());
|
||||
assert_eq!(ret, jf.into_value());
|
||||
|
||||
let jf = do_filter("$..book[2:]", "./benches/example.json");
|
||||
let ret = json!([
|
||||
@ -300,7 +301,7 @@ fn example() {
|
||||
"price" : 22.99
|
||||
}
|
||||
]);
|
||||
assert_eq!(ret, jf.current_value().into_value());
|
||||
assert_eq!(ret, jf.into_value());
|
||||
|
||||
let jf = do_filter("$..book[?(@.isbn)]", "./benches/example.json");
|
||||
let ret = json!([
|
||||
@ -319,7 +320,7 @@ fn example() {
|
||||
"price" : 22.99
|
||||
}
|
||||
]);
|
||||
assert_eq!(ret, jf.current_value().into_value());
|
||||
assert_eq!(ret, jf.into_value());
|
||||
|
||||
let jf = do_filter("$.store.book[?(@.price < 10)]", "./benches/example.json");
|
||||
let ret = json!([
|
||||
@ -337,9 +338,9 @@ fn example() {
|
||||
"price" : 8.99
|
||||
}
|
||||
]);
|
||||
assert_eq!(ret, jf.current_value().into_value());
|
||||
assert_eq!(ret, jf.into_value());
|
||||
|
||||
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();
|
||||
assert_eq!(json, jf.current_value().into_value());
|
||||
assert_eq!(json, jf.into_value());
|
||||
}
|
22
tests/lib.rs
22
tests/lib.rs
@ -15,6 +15,13 @@ fn read_json(path: &str) -> Value {
|
||||
serde_json::from_str(contents.as_str()).unwrap()
|
||||
}
|
||||
|
||||
fn read_contents(path: &str) -> String {
|
||||
let mut f = std::fs::File::open(path).unwrap();
|
||||
let mut contents = String::new();
|
||||
f.read_to_string(&mut contents).unwrap();
|
||||
contents
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compile() {
|
||||
let mut template = jsonpath::compile("$..friends[2]");
|
||||
@ -66,4 +73,19 @@ fn select() {
|
||||
"price" : 8.99
|
||||
}]);
|
||||
assert_eq!(json, ret);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_str() {
|
||||
let json_str = read_contents("./benches/example.json");
|
||||
let result_str = jsonpath::select_str(&json_str, "$..book[2]").unwrap();
|
||||
let ret = json!([{
|
||||
"category" : "fiction",
|
||||
"author" : "Herman Melville",
|
||||
"title" : "Moby Dick",
|
||||
"isbn" : "0-553-21311-3",
|
||||
"price" : 8.99
|
||||
}]);
|
||||
let json: Value = serde_json::from_str(&result_str).unwrap();
|
||||
assert_eq!(json, ret);
|
||||
}
|
39
tests/serde.rs
Normal file
39
tests/serde.rs
Normal file
@ -0,0 +1,39 @@
|
||||
extern crate jsonpath_lib as jsonpath;
|
||||
extern crate serde_json;
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use jsonpath::prelude::*;
|
||||
|
||||
fn read_json(path: &str) -> String {
|
||||
let mut f = std::fs::File::open(path).unwrap();
|
||||
let mut contents = String::new();
|
||||
f.read_to_string(&mut contents).unwrap();
|
||||
contents
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn de() {
|
||||
let json_str = read_json("./benches/example.json");
|
||||
// RefValue -> Value
|
||||
let ref_value: RefValue = serde_json::from_str(json_str.as_str()).unwrap();
|
||||
let value_wrapper: RefValueWrapper = ref_value.into();
|
||||
let value: Value = value_wrapper.into();
|
||||
|
||||
// Value
|
||||
let json: Value = serde_json::from_str(json_str.as_str()).unwrap();
|
||||
assert_eq!(value, json);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ser() {
|
||||
let json_str = read_json("./benches/example.json");
|
||||
let ref_value: RefValue = serde_json::from_str(json_str.as_str()).unwrap();
|
||||
let ref_value_str = serde_json::to_string(&ref_value).unwrap();
|
||||
|
||||
let json: Value = serde_json::from_str(json_str.as_str()).unwrap();
|
||||
let json_str = serde_json::to_string(&json).unwrap();
|
||||
assert_eq!(ref_value_str, json_str);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "jsonpath-wasm"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
authors = ["Changseok Han <freestrings@gmail.com>"]
|
||||
description = "JsonPath Webassembly version compiled by Rust - Demo: https://freestrings.github.io/jsonpath"
|
||||
keywords = ["library", "jsonpath", "json", "webassembly"]
|
||||
|
@ -29,14 +29,14 @@ cfg_if! {
|
||||
fn filter_ref_value(json: RefValueWrapper, node: Node) -> JsValue {
|
||||
let mut jf = JsonValueFilter::new_from_value(json);
|
||||
jf.visit(node);
|
||||
let taken = jf.take_value().into_value();
|
||||
let taken: Value = jf.take_value().into();
|
||||
match JsValue::from_serde(&taken) {
|
||||
Ok(js_value) => js_value,
|
||||
Err(e) => JsValue::from_str(&format!("Json deserialize error: {:?}", e))
|
||||
}
|
||||
}
|
||||
|
||||
fn into_serde_json(js_value: &JsValue) -> Result<Value, String> {
|
||||
fn into_serde_json(js_value: &JsValue) -> Result<RefValue, String> {
|
||||
if js_value.is_string() {
|
||||
match serde_json::from_str(js_value.as_string().unwrap().as_str()) {
|
||||
Ok(json) => Ok(json),
|
||||
@ -52,7 +52,7 @@ fn into_serde_json(js_value: &JsValue) -> Result<Value, String> {
|
||||
|
||||
fn into_ref_value(js_value: &JsValue, node: Node) -> JsValue {
|
||||
match into_serde_json(js_value) {
|
||||
Ok(json) => filter_ref_value((&json).into(), node),
|
||||
Ok(json) => filter_ref_value(json.into(), node),
|
||||
Err(e) => JsValue::from_str(&format!("Json serialize error: {}", e))
|
||||
}
|
||||
}
|
||||
@ -85,7 +85,7 @@ pub fn alloc_json(js_value: JsValue) -> usize {
|
||||
|
||||
let mut idx = CACHE_JSON_IDX.lock().unwrap();
|
||||
*idx += 1;
|
||||
map.insert(*idx, (&json).into());
|
||||
map.insert(*idx, json.into());
|
||||
*idx
|
||||
}
|
||||
Err(e) => {
|
||||
@ -136,7 +136,7 @@ pub fn selector(js_value: JsValue) -> JsValue {
|
||||
}
|
||||
_ => {
|
||||
match into_serde_json(&js_value) {
|
||||
Ok(json) => (&json).into(),
|
||||
Ok(json) => json.into(),
|
||||
Err(e) => return JsValue::from_str(e.as_str())
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user