From 2e9e0ac6fcc90f95f9a821dcbdfe6fde84926aca Mon Sep 17 00:00:00 2001 From: freestrings Date: Tue, 11 Jun 2019 16:12:40 +0900 Subject: [PATCH] =?UTF-8?q?compiled=5Fpath=20=EC=9D=B8=EC=9E=90=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EB=B3=80=EA=B2=BD,=20compute=5Fpath=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- benches/bench.rs | 7 +-- nodejs/native/Cargo.toml | 4 +- nodejs/native/src/lib.rs | 4 +- src/lib.rs | 7 +-- src/select/mod.rs | 101 +++++++++++++++++++++++++-------------- tests/mutable.rs | 25 ---------- wasm/src/lib.rs | 4 +- 7 files changed, 78 insertions(+), 74 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index 3cc6b1c..27b1a37 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -125,12 +125,13 @@ fn bench_select_to_compare_with_delete(b: &mut Bencher) { let mut selector = Selector::new(); let _ = selector.str_path(get_path()); - let _ = selector.value(json); b.iter(move || { for _ in 1..100 { - let _ = json.clone(); - let _ = selector.reset_value().select(); + let json = json.clone(); + let mut s = Selector::new(); + let _ = s.compiled_path(selector.node_ref().unwrap()).value(&json); + let _ = s.select(); } }); } \ No newline at end of file diff --git a/nodejs/native/Cargo.toml b/nodejs/native/Cargo.toml index 071e68d..2c52d00 100644 --- a/nodejs/native/Cargo.toml +++ b/nodejs/native/Cargo.toml @@ -14,8 +14,8 @@ exclude = ["artifacts.json", "index.node"] neon-build = "0.2.0" [dependencies] -#jsonpath_lib = "0.2.0" -jsonpath_lib = {path="../../"} +jsonpath_lib = "0.2.0" +#jsonpath_lib = { path = "../../" } neon = "0.2.0" neon-serde = "0.1.1" serde_json = { version = "1.0", features = ["preserve_order"] } diff --git a/nodejs/native/src/lib.rs b/nodejs/native/src/lib.rs index befb227..eb77863 100644 --- a/nodejs/native/src/lib.rs +++ b/nodejs/native/src/lib.rs @@ -110,7 +110,7 @@ impl SelectorCls { fn select(&self) -> String { let node = match &self.node { - Some(node) => node.clone(), + Some(node) => node, None => panic!("{:?}", JsonPathError::EmptyPath) }; @@ -120,7 +120,7 @@ impl SelectorCls { }; let mut selector = Selector::new(); - selector.compiled_path(node.clone()); + selector.compiled_path(node); selector.value(&value); match selector.select_as_str() { Ok(ret) => ret, diff --git a/src/lib.rs b/src/lib.rs index cc9c12d..7b5c5b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -175,12 +175,9 @@ pub fn compile(path: &str) -> impl FnMut(&Value) -> Result, JsonPath match &node { Ok(node) => { let mut selector = Selector::new(); - // - // TODO remove node.clone() - // - selector.compiled_path(node.clone()).value(json).select() + selector.compiled_path(node).value(json).select() } - Err(e) => Err(JsonPathError::Path(e.clone())) + Err(e) => Err(JsonPathError::Path(e.to_string())) } } } diff --git a/src/select/mod.rs b/src/select/mod.rs index e1581bd..ab4ec93 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use array_tool::vec::{Intersect, Union}; -use indexmap::IndexSet; +use indexmap::IndexMap; use serde_json::{Number, Value}; use parser::parser::*; @@ -487,19 +487,21 @@ pub enum JsonPathError { } #[derive(Debug)] -pub struct Selector<'a> { +pub struct Selector<'a, 'b> { node: Option, + node_ref: Option<&'b Node>, value: Option<&'a Value>, tokens: Vec, terms: Vec>>, current: Option>, - selectors: Vec>, + selectors: Vec>, } -impl<'a> Selector<'a> { +impl<'a, 'b> Selector<'a, 'b> { pub fn new() -> Self { Selector { node: None, + node_ref: None, value: None, tokens: Vec::new(), terms: Vec::new(), @@ -510,12 +512,29 @@ impl<'a> Selector<'a> { pub fn str_path(&mut self, path: &str) -> Result<&mut Self, JsonPathError> { debug!("path : {}", path); + + if self.node_ref.is_some() { + self.node_ref.take(); + } + self.node = Some(Parser::compile(path).map_err(|e| JsonPathError::Path(e))?); Ok(self) } - pub fn compiled_path(&mut self, node: Node) -> &mut Self { - self.node = Some(node); + pub fn node_ref(&self) -> Option<&Node> { + if let Some(node) = &self.node { + Some(node) + } else { + None + } + } + + pub fn compiled_path(&mut self, node: &'b Node) -> &mut Self { + if self.node.is_some() { + self.node.take(); + } + + self.node_ref = Some(node); self } @@ -530,14 +549,21 @@ impl<'a> Selector<'a> { } fn _select(&mut self) -> Result<(), JsonPathError> { - match self.node.take() { - Some(node) => { - self.visit(&node); - self.node = Some(node); - Ok(()) - } - _ => Err(JsonPathError::EmptyPath) + if self.node_ref.is_some() { + let node_ref = self.node_ref.take().unwrap(); + self.visit(node_ref); + return Ok(()); } + + if self.node.is_none() { + return Err(JsonPathError::EmptyPath); + } + + let node = self.node.take().unwrap(); + self.visit(&node); + self.node = Some(node); + + Ok(()) } pub fn select_as(&mut self) -> Result, JsonPathError> { @@ -743,7 +769,7 @@ impl<'a> Selector<'a> { } } -impl<'a> NodeVisitor for Selector<'a> { +impl<'a, 'b> NodeVisitor for Selector<'a, 'b> { fn visit_token(&mut self, token: &ParseToken) { debug!("token: {:?}, stack: {:?}", token, self.tokens); @@ -1002,17 +1028,23 @@ impl SelectorMut { self.value.take() } - fn compute_paths(&self, result: &Vec<&Value>) -> Vec> { - fn _walk(origin: &Value, target: &Value, tokens: &mut Vec, visited: &mut IndexSet>) -> bool { - if visited.contains(tokens) { - return false; - } + fn compute_paths(&self, mut result: Vec<&Value>) -> Vec> { + fn _walk(origin: &Value, target: &mut Vec<&Value>, tokens: &mut Vec, visited: &mut IndexMap<*const Value, Vec>) -> bool { + trace!("{:?}, {:?}", target, tokens); - if std::ptr::eq(origin, target) { - debug!("tokens: {:?}", tokens); + if target.is_empty() { return true; } + target.retain(|t| { + if std::ptr::eq(origin, *t) { + visited.insert(*t, tokens.to_vec()); + false + } else { + true + } + }); + match origin { Value::Array(vec) => for (i, v) in vec.iter().enumerate() { tokens.push(i.to_string()); @@ -1034,18 +1066,14 @@ impl SelectorMut { return false; } - let mut visited = IndexSet::new(); + let mut visited = IndexMap::new(); if let Some(origin) = &self.value { - for v in result { - let mut tokens = Vec::new(); - if _walk(origin, v, &mut tokens, &mut visited) { - visited.insert(tokens); - } - } + let mut tokens = Vec::new(); + _walk(origin, &mut result, &mut tokens, &mut visited); } - visited.iter().map(|v| v.to_vec()).collect() + visited.iter().map(|(_, v)| v.to_vec()).collect() } pub fn delete(&mut self) -> Result<&mut Self, JsonPathError> { @@ -1053,21 +1081,24 @@ impl SelectorMut { } pub fn replace_with Value>(&mut self, fun: &mut F) -> Result<&mut Self, JsonPathError> { - let mut selector = Selector::new(); - - if let Some(path) = self.path.take() { - selector.compiled_path(path); + if self.path.is_none() { + return Err(JsonPathError::EmptyPath); } + let node = self.path.take().unwrap(); + + let mut selector = Selector::new(); + selector.compiled_path(&node); + if let Some(value) = &self.value { selector.value(value); } let result = selector.select(); - self.path = Some(selector.node.unwrap()); + self.path = Some(node); - let paths = self.compute_paths(&result?); + let paths = self.compute_paths(result?); if let Some(mut value) = self.value.take() { for tokens in paths { diff --git a/tests/mutable.rs b/tests/mutable.rs index d67e424..b61fa07 100644 --- a/tests/mutable.rs +++ b/tests/mutable.rs @@ -37,29 +37,4 @@ fn selector_mut() { .select().unwrap(); assert_eq!(vec![&json!("a"), &json!("a"), &json!("a"), &json!("a"), &json!("a")], result); -} - -#[test] -fn selector_mut_delete_array() { - setup(); - - let json = serde_json::from_str(r#"{ - "school": { - "friends": [ - {"name": "친구1", "age": 20}, - {"name": "친구2", "age": 20} - ] - }, - "friends": [ - {"name": "친구3", "age": 30}, - {"name": "친구4"} - ] - }"#).unwrap(); - - let json1 = jsonpath::delete(json, "$..friends[0]").unwrap(); - - println!("{:?}", json1); - - let mut json2 = jsonpath::delete(json1, "$..friends[1]").unwrap(); - } \ No newline at end of file diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index 530827e..f21c7ea 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -88,7 +88,7 @@ pub fn compile(path: &str) -> JsValue { let cb = Closure::wrap(Box::new(move |js_value: JsValue| { let mut selector = _Selector::new(); match &node { - Ok(node) => selector.compiled_path(node.clone()), + Ok(node) => selector.compiled_path(node), Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Path(e.clone()))) }; let json = match into_serde_json(&js_value) { @@ -120,7 +120,7 @@ pub fn selector(js_value: JsValue) -> JsValue { match Parser::compile(path.as_str()) { Ok(node) => { let mut selector = _Selector::new(); - let _ = selector.compiled_path(node); + let _ = selector.compiled_path(&node); match selector.value(&json).select() { Ok(ret) => match JsValue::from_serde(&ret) { Ok(ret) => ret,