Fix bug: eq, hash. Bump up 0.1.6

This commit is contained in:
freestrings 2019-03-22 12:17:45 +09:00
parent b24a8c18a9
commit 8e1a0f84e1
10 changed files with 231 additions and 171 deletions

View File

@ -1,6 +1,6 @@
[package]
name = "jsonpath_lib"
version = "0.1.5"
version = "0.1.6"
authors = ["Changseok Han <freestrings@gmail.com>"]
description = "JsonPath in Rust and Webassembly - Webassembly Demo: https://freestrings.github.io/jsonpath"

View File

@ -1,6 +1,6 @@
[package]
name = "jsonpath-rs"
version = "0.1.1"
version = "0.1.2"
authors = ["Changseok Han <freestrings@gmail.com>"]
description = "JsonPath engine for NodeJs with Rust native implementation."
keywords = ["library", "jsonpath", "json"]

View File

@ -14,9 +14,11 @@ impl TermContext {
TermContext::Constants(et) => {
match other {
TermContext::Constants(oet) => {
trace!("const-const");
TermContext::Constants(ExprTerm::Bool(et.cmp(oet, cmp_fn, default)))
}
TermContext::Json(key, v) => {
trace!("const-json");
TermContext::Json(None, v.take_with(key, et, cmp_fn, true))
}
}
@ -24,6 +26,7 @@ impl TermContext {
TermContext::Json(key, v) => {
match other {
TermContext::Json(key_other, ov) => {
trace!("json-json");
fn is_json(t: &TermContext) -> bool {
match t {
@ -32,18 +35,16 @@ impl TermContext {
}
}
let mut v = v.filter(key);
let mut ov = ov.filter(key_other);
let mut c = v.into_term(key);
let mut oc = ov.into_term(key_other);
if is_json(&c) && is_json(&oc) {
v.cmp(&mut ov, cmp_fn.into_type())
v.cmp(&ov, cmp_fn.into_type())
} else {
c.cmp(&mut oc, cmp_fn, default)
}
}
TermContext::Constants(et) => {
trace!("json-const");
TermContext::Json(None, v.take_with(key, et, cmp_fn, false))
}
}
@ -87,26 +88,32 @@ impl TermContext {
}
pub fn eq(&self, other: &TermContext) -> TermContext {
trace!("eq");
self.cmp(other, CmpEq, false)
}
pub fn ne(&self, other: &TermContext) -> TermContext {
trace!("ne");
self.cmp(other, CmpNe, true)
}
pub fn gt(&self, other: &TermContext) -> TermContext {
trace!("gt");
self.cmp(other, CmpGt, false)
}
pub fn ge(&self, other: &TermContext) -> TermContext {
trace!("ge");
self.cmp(other, CmpGe, false)
}
pub fn lt(&self, other: &TermContext) -> TermContext {
trace!("lt");
self.cmp(other, CmpLt, false)
}
pub fn le(&self, other: &TermContext) -> TermContext {
trace!("le");
self.cmp(other, CmpLe, false)
}

View File

@ -1,6 +1,6 @@
use std::error::Error;
use std::result::Result;
use std::ops::Deref;
use std::result::Result;
use serde_json::Value;
@ -324,6 +324,8 @@ impl JsonValueFilter {
vf.vw.set_leaves(is_leaves);
if v.is_null() {
vf.vw.replace(v);
} else if v.is_array() && v.as_array().unwrap().is_empty() {
vf.vw.replace(RefValue::Null.into());
} else if vf.vw.is_array() {
vf.vw.replace(v);
}
@ -480,6 +482,9 @@ impl JsonValueFilter {
_ => {}
}
}
Some(TermContext::Constants(ExprTerm::Bool(false))) => {
self.replace_filter_stack(RefValue::Null.into(), false);
}
Some(TermContext::Json(_, vw)) => {
self.replace_filter_stack(vw.get_val().clone(), vw.is_leaves());
}

View File

@ -155,6 +155,7 @@ impl ValueWrapper {
}
fn into_hashset(&self) -> IndexSet<RefValueWrapper> {
trace!("into_hashset");
let mut hashset = IndexSet::new();
match self.val.deref() {
RefValue::Array(ref v1) => {
@ -170,9 +171,10 @@ impl ValueWrapper {
}
pub fn except(&self, other: &Self) -> Self {
trace!("except");
let hashset = self.into_hashset();
let mut ret: IndexSet<RefValueWrapper> = IndexSet::new();
match &(*other.val) {
match other.val.deref() {
RefValue::Array(ref v1) => {
for v in v1 {
if !hashset.contains(v) {
@ -192,6 +194,7 @@ impl ValueWrapper {
}
pub fn intersect(&self, other: &Self) -> Self {
trace!("intersect");
let hashset = self.into_hashset();
let mut ret: IndexSet<RefValueWrapper> = IndexSet::new();
match other.val.deref() {
@ -214,6 +217,7 @@ impl ValueWrapper {
}
pub fn union(&self, other: &Self) -> Self {
trace!("union");
let mut hashset = self.into_hashset();
match other.val.deref() {
RefValue::Array(ref v1) => {
@ -249,6 +253,7 @@ impl ValueWrapper {
}
pub fn filter(&self, key: &Option<ValueFilterKey>) -> Self {
trace!("filter");
let v = match self.val.deref() {
RefValue::Array(ref vec) => {
let mut ret = Vec::new();

View File

@ -14,37 +14,38 @@ impl<'de> Deserialize<'de> for RefValue {
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(RefValueVisitor {})
}
}
struct RefValueVisitor {}
struct RefValueVisitor {}
impl<'de> Visitor<'de> for 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")
}
#[inline]
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where
E: Error, {
Ok(RefValue::Bool(v))
}
#[inline]
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: serde::de::Error, {
Ok(RefValue::Number(v.into()))
}
#[inline]
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: serde::de::Error, {
Ok(RefValue::Number(v.into()))
}
#[inline]
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where
E: serde::de::Error, {
@ -56,35 +57,41 @@ impl<'de> Visitor<'de> for RefValueVisitor {
}
}
#[inline]
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error, {
self.visit_string(String::from(v))
}
#[inline]
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error, {
Ok(RefValue::String(v))
}
#[inline]
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: serde::de::Error, {
Ok(RefValue::Null)
}
#[inline]
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error> where
D: Deserializer<'de>, {
Deserialize::deserialize(deserializer)
}
#[inline]
fn visit_unit<E>(self) -> Result<Self::Value, E>
where
E: serde::de::Error, {
Ok(RefValue::Null)
}
#[inline]
fn visit_seq<A>(self, mut visitor: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>, {
@ -99,6 +106,7 @@ impl<'de> Visitor<'de> for RefValueVisitor {
Ok(RefValue::Array(vec))
}
#[inline]
fn visit_map<A>(self, mut visitor: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>, {
@ -116,4 +124,8 @@ impl<'de> Visitor<'de> for RefValueVisitor {
_ => Ok(RefValue::Object(IndexMap::new())),
}
}
}
deserializer.deserialize_any(RefValueVisitor {})
}
}

View File

@ -124,11 +124,17 @@ pub enum RefValue {
Object(IndexMap<String, RefValueWrapper>),
}
static REF_VALUE_NULL: &'static str = "$jsonpath::ref_value::model::RefValue::Null";
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::Null => {
REF_VALUE_NULL.hash(state)
},
RefValue::Bool(b) => {
b.hash(state)
},
RefValue::Number(n) => {
if n.is_f64() {
n.as_f64().unwrap().to_string().hash(state)
@ -138,7 +144,9 @@ impl Hash for RefValue {
n.as_u64().unwrap().hash(state);
}
}
RefValue::String(s) => s.hash(state),
RefValue::String(s) => {
s.hash(state)
},
RefValue::Object(map) => {
for (_, v) in map {
v.hash(state);

View File

@ -1,52 +0,0 @@
// 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()
}
}

View File

@ -154,7 +154,7 @@ fn return_type() {
}
#[test]
fn op() {
fn op_default() {
setup();
let jf = do_filter("$.school[?(@.friends == @.friends)]", "./benches/data_obj.json");
@ -203,6 +203,81 @@ fn op() {
assert_eq!(friends, jf.into_value());
}
#[test]
fn op_number() {
setup();
let json = json!({ "a": 1 });
let ret = jsonpath::select(&json, "$.[?(@.a == 1)]").unwrap();
assert_eq!(json, ret);
let ret = jsonpath::select(&json, "$.[?(@.a != 2)]").unwrap();
assert_eq!(json, ret);
let ret = jsonpath::select(&json, "$.[?(@.a < 2)]").unwrap();
assert_eq!(json, ret);
let ret = jsonpath::select(&json, "$.[?(@.a <= 1)]").unwrap();
assert_eq!(json, ret);
let ret = jsonpath::select(&json, "$.[?(@.a > 0)]").unwrap();
assert_eq!(json, ret);
let ret = jsonpath::select(&json, "$.[?(@.a >= 0)]").unwrap();
assert_eq!(json, ret);
}
#[test]
fn op_string() {
setup();
let json = json!({ "a": "b" });
let ret = jsonpath::select(&json, r#"$.[?(@.a == "b")]"#).unwrap();
assert_eq!(json!({ "a": "b" }), ret);
let ret = jsonpath::select(&json, r#"$.[?(@.a != "c")]"#).unwrap();
assert_eq!(json!({ "a": "b" }), ret);
let ret = jsonpath::select(&json, r#"$.[?(@.a < "b")]"#).unwrap();
assert_eq!(Value::Null, ret);
let ret = jsonpath::select(&json, r#"$.[?(@.a <= "b")]"#).unwrap();
assert_eq!(json!({ "a": "b" }), ret);
let ret = jsonpath::select(&json, r#"$.[?(@.a > "b")]"#).unwrap();
assert_eq!(Value::Null, ret);
let ret = jsonpath::select(&json, r#"$.[?(@.a >= "b")]"#).unwrap();
assert_eq!(json!({ "a": "b" }), ret);
}
#[test]
fn op_object() {
setup();
let json = json!({
"a": { "1": 1 },
"b": { "2": 2 },
"c": { "1": 1 },
});
let ret = jsonpath::select(&json, r#"$.[?(@.a == @.c)]"#).unwrap();
assert_eq!(json, ret);
let ret = jsonpath::select(&json, r#"$.[?(@.a != @.c)]"#).unwrap();
assert_eq!(Value::Null, ret);
let ret = jsonpath::select(&json, r#"$.[?(@.a < @.c)]"#).unwrap();
assert_eq!(Value::Null, ret);
let ret = jsonpath::select(&json, r#"$.[?(@.a <= @.c)]"#).unwrap();
assert_eq!(Value::Null, ret);
let ret = jsonpath::select(&json, r#"$.[?(@.a > @.c)]"#).unwrap();
assert_eq!(Value::Null, ret);
let ret = jsonpath::select(&json, r#"$.[?(@.a >= @.c)]"#).unwrap();
assert_eq!(Value::Null, ret);
}
#[test]
fn op_complex() {
setup();
let json = json!({ "a": { "b": 1 } });
let ret = jsonpath::select(&json, r#"$.[?(1 == @.a)]"#).unwrap();
assert_eq!(Value::Null, ret);
let ret = jsonpath::select(&json, r#"$.[?("1" != @.a)]"#).unwrap();
assert_eq!(Value::Null, ret);
let ret = jsonpath::select(&json, r#"$.[?(@.a <= 1)]"#).unwrap();
assert_eq!(Value::Null, ret);
let ret = jsonpath::select(&json, r#"$.[?(@.a > "1")]"#).unwrap();
assert_eq!(Value::Null, ret);
}
#[test]
fn example() {
setup();

View File

@ -1,6 +1,6 @@
[package]
name = "jsonpath-wasm"
version = "0.1.5"
version = "0.1.6"
authors = ["Changseok Han <freestrings@gmail.com>"]
description = "JsonPath Webassembly version compiled by Rust - Demo: https://freestrings.github.io/jsonpath"
keywords = ["library", "jsonpath", "json", "webassembly"]