diff --git a/Cargo.toml b/Cargo.toml index 1dc052b..42b8af4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Glyn Normington "] edition = "2018" [dependencies] +by_address = "1.0.4" itertools = "0.9.0" json = "0.12.4" pest = "2.1.3" diff --git a/jsonpath-compliance-test-suite b/jsonpath-compliance-test-suite index 2e62f6f..374eae0 160000 --- a/jsonpath-compliance-test-suite +++ b/jsonpath-compliance-test-suite @@ -1 +1 @@ -Subproject commit 2e62f6fb06cdb36dd982a9f39fa3810f385f1ce4 +Subproject commit 374eae0b428a024c7f869da164981b23c57e8f06 diff --git a/src/ast.rs b/src/ast.rs index c2fd948..beae5f6 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -4,8 +4,10 @@ * SPDX-License-Identifier: BSD-2-Clause */ +use by_address::ByAddress; use serde_json::Value; use slyce::Slice; +use std::collections::HashSet; use std::iter; /// A path is a tree of selector nodes. @@ -77,7 +79,9 @@ impl Path { impl Selector { pub fn find<'a>(&'a self, input: &'a Value) -> Iter<'a> { match self { - Selector::Union(indices) => Box::new(indices.iter().flat_map(move |i| i.get(input))), + Selector::Union(indices) => { + unique_nodes(Box::new(indices.iter().flat_map(move |i| i.get(input)))) + } Selector::DotName(name) => Box::new(input.get(name).into_iter()), Selector::DotWildcard => match input { Value::Object(m) => Box::new(m.values()), @@ -88,6 +92,18 @@ impl Selector { } } +fn unique_nodes(i: Iter) -> Iter { + let mut seen: HashSet> = HashSet::new(); + let mut result = vec![]; + for j in i { + if !&seen.contains(&ByAddress(j)) { + seen.insert(ByAddress(j)); + result.push(j) + } + } + Box::new(result.into_iter()) +} + impl UnionElement { pub fn get<'a>(&self, v: &'a Value) -> Iter<'a> { match self {