Skip to content

Commit 1d9ff39

Browse files
ChopinXBPliuq19
authored andcommitted
feat: support get_many with unknown key
1 parent 88c3ce4 commit 1d9ff39

4 files changed

Lines changed: 108 additions & 64 deletions

File tree

examples/get_many.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,25 @@ fn main() {
88
let mut tree = sonic_rs::PointerTree::new();
99

1010
tree.add_path(&["u"]);
11+
tree.add_path(&["unknown_key"]);
1112
tree.add_path(pointer!["a", "b", "c", 1]);
1213

1314
let nodes = unsafe { sonic_rs::get_many_unchecked(json, &tree) };
1415

15-
// the node order is as the order of `add_path`
16-
for val in nodes.unwrap() {
17-
println!("{}", val.as_raw_str());
18-
// 123
19-
// "found"
16+
match nodes {
17+
Ok(vals) => {
18+
assert_eq!(vals[0].as_ref().unwrap().as_raw_str(), "123");
19+
assert!(vals[1].is_none());
20+
assert_eq!(vals[2].as_ref().unwrap().as_raw_str(), "\"found\"");
21+
for val in vals {
22+
match val {
23+
Some(_) => println!("{}", val.as_ref().unwrap().as_raw_str()),
24+
None => println!("None"),
25+
};
26+
}
27+
}
28+
Err(e) => {
29+
println!("err: {:?}", e)
30+
}
2031
}
2132
}

src/lazyvalue/get.rs

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -185,32 +185,47 @@ where
185185

186186
/// get_many returns multiple fields from the `PointerTree`.
187187
///
188-
/// The result is a `Result<Vec<LazyValue>>`. The order of the `Vec` is same as the order of the
189-
/// tree.
188+
/// The result is a `Result<Vec<Option<LazyValue>>>`. The order of the `Vec` is same as the order of
189+
/// the tree.
190190
///
191+
/// If a key is unknown, the value at the corresponding position in `Vec` will be None.
191192
/// If json is invalid, or the field not be found, it will return a err.
192193
///
193194
/// # Safety
194195
/// The JSON must be valid and well-formed, otherwise it may return unexpected result.
195196
///
196197
/// # Examples
197198
/// ```
198-
/// use sonic_rs::pointer;
199+
/// # use sonic_rs::pointer;
200+
/// # use sonic_rs::PointerTree;
201+
///
199202
/// let json = r#"
200-
/// {"u": 123, "a": {"b" : {"c": [null, "found"]}}}"#;
203+
/// {"u": 123, "a": {"b" : {"c": [null, "found"]}}}"#;
204+
///
201205
/// // build a pointer tree, representing multiple json path
202-
/// let mut tree = sonic_rs::PointerTree::new();
206+
/// let mut tree = PointerTree::new();
207+
///
203208
/// tree.add_path(&["u"]);
209+
/// tree.add_path(&["unknown_key"]);
204210
/// tree.add_path(&pointer!["a", "b", "c", 1]);
205-
/// let nodes = unsafe { sonic_rs::get_many_unchecked(json, &tree).unwrap() };
206-
/// // the node order is as the order of `add_path`
207-
/// assert_eq!(nodes[0].as_raw_str(), "123");
208-
/// assert_eq!(nodes[1].as_raw_str(), "\"found\"");
211+
///
212+
/// let nodes = unsafe { sonic_rs::get_many_unchecked(json, &tree) };
213+
///
214+
/// match nodes {
215+
/// Ok(vals) => {
216+
/// assert_eq!(vals[0].as_ref().unwrap().as_raw_str(), "123");
217+
/// assert!(vals[1].is_none());
218+
/// assert_eq!(vals[2].as_ref().unwrap().as_raw_str(), "\"found\"");
219+
/// }
220+
/// Err(e) => {
221+
/// panic!("err: {:?}", e)
222+
/// }
223+
/// }
209224
/// ```
210225
pub unsafe fn get_many_unchecked<'de, Input>(
211226
json: Input,
212227
tree: &PointerTree,
213-
) -> Result<Vec<LazyValue<'de>>>
228+
) -> Result<Vec<Option<LazyValue<'de>>>>
214229
where
215230
Input: JsonInput<'de>,
216231
{
@@ -401,25 +416,41 @@ where
401416

402417
/// get_many returns multiple fields from the [`PointerTree`].
403418
///
404-
/// The result is a `Result<Vec<LazyValue>>`. The order of the `Vec` is same as the order of the
405-
/// tree.
419+
/// The result is a `Result<Vec<Option<LazyValue>>>`. The order of the `Vec` is same as the order of
420+
/// the tree.
421+
///
422+
/// If a key is unknown, the value at the corresponding position in `Vec` will be None.
406423
/// If json is invalid, or the field not be found, it will return a err.
407424
///
408425
/// # Examples
409426
/// ```
410-
/// use sonic_rs::pointer;
427+
/// # use sonic_rs::pointer;
428+
/// # use sonic_rs::PointerTree;
429+
///
411430
/// let json = r#"
412-
/// {"u": 123, "a": {"b" : {"c": [null, "found"]}}}"#;
431+
/// {"u": 123, "a": {"b" : {"c": [null, "found"]}}}"#;
432+
///
413433
/// // build a pointer tree, representing multiple json path
414-
/// let mut tree = sonic_rs::PointerTree::new();
434+
/// let mut tree = PointerTree::new();
435+
///
415436
/// tree.add_path(&["u"]);
437+
/// tree.add_path(&["unknown_key"]);
416438
/// tree.add_path(&pointer!["a", "b", "c", 1]);
417-
/// let nodes = sonic_rs::get_many(json, &tree).unwrap();
418-
/// // the node order is as the order of `add_path`
419-
/// assert_eq!(nodes[0].as_raw_str(), "123");
420-
/// assert_eq!(nodes[1].as_raw_str(), "\"found\"");
439+
///
440+
/// let nodes = unsafe { sonic_rs::get_many(json, &tree) };
441+
///
442+
/// match nodes {
443+
/// Ok(vals) => {
444+
/// assert_eq!(vals[0].as_ref().unwrap().as_raw_str(), "123");
445+
/// assert!(vals[1].is_none());
446+
/// assert_eq!(vals[2].as_ref().unwrap().as_raw_str(), "\"found\"");
447+
/// }
448+
/// Err(e) => {
449+
/// panic!("err: {:?}", e)
450+
/// }
451+
/// }
421452
/// ```
422-
pub fn get_many<'de, Input>(json: Input, tree: &PointerTree) -> Result<Vec<LazyValue<'de>>>
453+
pub fn get_many<'de, Input>(json: Input, tree: &PointerTree) -> Result<Vec<Option<LazyValue<'de>>>>
423454
where
424455
Input: JsonInput<'de>,
425456
{
@@ -599,7 +630,8 @@ mod test {
599630
tree.add_path(pointer!["a"].iter()); // 4
600631
tree.add_path(pointer!["b", 2].iter()); // 5
601632
tree.add_path(pointer![].iter()); // 6
602-
assert_eq!(tree.size(), 7);
633+
tree.add_path(pointer!["unknown_key"].iter()); // 7
634+
assert_eq!(tree.size(), 8);
603635
tree
604636
}
605637

@@ -622,18 +654,22 @@ mod test {
622654
test_many_ok(unsafe { get_many_unchecked(&json, &tree).unwrap() });
623655
test_many_ok(get_many(&json, &tree).unwrap());
624656

625-
fn test_many_ok(many: Vec<LazyValue<'_>>) {
626-
assert_eq!(many[0].as_raw_str(), "\"hello, world!\"");
657+
fn test_many_ok(many: Vec<Option<LazyValue<'_>>>) {
658+
assert_eq!(many[0].as_ref().unwrap().as_raw_str(), "\"hello, world!\"");
627659
assert_eq!(
628-
many[1].as_raw_str(),
660+
many[1].as_ref().unwrap().as_raw_str(),
629661
"{\n \"a_b_c\":\"hello, world!\"\n }"
630662
);
631-
assert_eq!(many[2].as_raw_str(), "1");
632-
assert_eq!(many[3].as_raw_str(), "{\n \"a_b\":{\n \"a_b_c\":\"hello, world!\"\n },\n \"a_a\": [0, 1, 2]\n }");
633-
assert_eq!(many[4].as_raw_str(), many[3].as_raw_str());
634-
assert_eq!(many[5].as_raw_str(), "true");
663+
assert_eq!(many[2].as_ref().unwrap().as_raw_str(), "1");
664+
assert_eq!(many[3].as_ref().unwrap().as_raw_str(), "{\n \"a_b\":{\n \"a_b_c\":\"hello, world!\"\n },\n \"a_a\": [0, 1, 2]\n }");
665+
assert_eq!(
666+
many[4].as_ref().unwrap().as_raw_str(),
667+
many[3].as_ref().unwrap().as_raw_str()
668+
);
669+
assert_eq!(many[5].as_ref().unwrap().as_raw_str(), "true");
635670
// we have strip the leading or trailing spaces
636-
assert_eq!(many[6].as_raw_str(), "{\n \"b\": [0, 1, true],\n \"a\": {\n \"a_b\":{\n \"a_b_c\":\"hello, world!\"\n },\n \"a_a\": [0, 1, 2]\n }\n }");
671+
assert_eq!(many[6].as_ref().unwrap().as_raw_str(), "{\n \"b\": [0, 1, true],\n \"a\": {\n \"a_b\":{\n \"a_b_c\":\"hello, world!\"\n },\n \"a_a\": [0, 1, 2]\n }\n }");
672+
assert!(many[7].is_none())
637673
}
638674
}
639675
}

src/parser.rs

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1818,7 +1818,7 @@ where
18181818
fn get_many_rec(
18191819
&mut self,
18201820
node: &PointerTreeNode,
1821-
out: &mut Vec<LazyValue<'de>>,
1821+
out: &mut Vec<Option<LazyValue<'de>>>,
18221822
strbuf: &mut Vec<u8>,
18231823
remain: &mut usize,
18241824
is_safe: bool,
@@ -1863,7 +1863,7 @@ where
18631863
slice = self.read.slice_unchecked(start, self.read.index());
18641864
let lv = LazyValue::new(slice.into(), status.into());
18651865
for p in &node.order {
1866-
out[*p] = lv.clone();
1866+
out[*p] = Some(lv.clone());
18671867
}
18681868
*remain -= node.order.len();
18691869
}
@@ -1875,7 +1875,7 @@ where
18751875
&mut self,
18761876
mkeys: &MultiKey,
18771877
strbuf: &mut Vec<u8>,
1878-
out: &mut Vec<LazyValue<'de>>,
1878+
out: &mut Vec<Option<LazyValue<'de>>>,
18791879
remain: &mut usize,
18801880
) -> Result<()> {
18811881
debug_assert!(strbuf.is_empty());
@@ -1893,13 +1893,11 @@ where
18931893
Some(_) => unreachable!(),
18941894
}
18951895

1896-
let mut visited = 0;
18971896
loop {
18981897
let key = self.parse_str(strbuf)?;
18991898
self.parse_object_clo()?;
19001899
if let Some(val) = mkeys.get(key.deref()) {
19011900
self.get_many_rec(val, out, strbuf, remain, false)?;
1902-
visited += 1;
19031901
if *remain == 0 {
19041902
break;
19051903
}
@@ -1923,20 +1921,15 @@ where
19231921
}
19241922
}
19251923

1926-
// check whether remaining unknown keys
1927-
if visited < mkeys.len() {
1928-
perr!(self, GetUnknownKeyInObject)
1929-
} else {
1930-
Ok(())
1931-
}
1924+
Ok(())
19321925
}
19331926

19341927
#[allow(clippy::mutable_key_type)]
19351928
fn get_many_keys(
19361929
&mut self,
19371930
mkeys: &MultiKey,
19381931
strbuf: &mut Vec<u8>,
1939-
out: &mut Vec<LazyValue<'de>>,
1932+
out: &mut Vec<Option<LazyValue<'de>>>,
19401933
remain: &mut usize,
19411934
) -> Result<()> {
19421935
debug_assert!(strbuf.is_empty());
@@ -1955,14 +1948,12 @@ where
19551948
}
19561949
}
19571950

1958-
let mut visited = 0;
19591951
loop {
19601952
let key = self.parse_str(strbuf)?;
19611953
self.parse_object_clo()?;
19621954
if let Some(val) = mkeys.get(key.deref()) {
19631955
// parse the child point tree
19641956
self.get_many_rec(val, out, strbuf, remain, true)?;
1965-
visited += 1;
19661957
if *remain == 0 {
19671958
break;
19681959
}
@@ -1979,12 +1970,7 @@ where
19791970
}
19801971
}
19811972

1982-
// check whether remaining unknown keys
1983-
if visited < mkeys.len() {
1984-
perr!(self, GetUnknownKeyInObject)
1985-
} else {
1986-
Ok(())
1987-
}
1973+
Ok(())
19881974
}
19891975

19901976
#[cfg(test)]
@@ -2005,7 +1991,7 @@ where
20051991
&mut self,
20061992
midx: &MultiIndex,
20071993
strbuf: &mut Vec<u8>,
2008-
out: &mut Vec<LazyValue<'de>>,
1994+
out: &mut Vec<Option<LazyValue<'de>>>,
20091995
remain: &mut usize,
20101996
) -> Result<()> {
20111997
match self.skip_space() {
@@ -2064,7 +2050,7 @@ where
20642050
&mut self,
20652051
midx: &MultiIndex,
20662052
strbuf: &mut Vec<u8>,
2067-
out: &mut Vec<LazyValue<'de>>,
2053+
out: &mut Vec<Option<LazyValue<'de>>>,
20682054
remain: &mut usize,
20692055
) -> Result<()> {
20702056
match self.skip_space() {
@@ -2116,11 +2102,11 @@ where
21162102
&mut self,
21172103
tree: &PointerTree,
21182104
is_safe: bool,
2119-
) -> Result<Vec<LazyValue<'de>>> {
2105+
) -> Result<Vec<Option<LazyValue<'de>>>> {
21202106
let mut strbuf = Vec::with_capacity(DEFAULT_KEY_BUF_CAPACITY);
21212107
let mut remain = tree.size();
2122-
let mut out: Vec<LazyValue<'de>> = Vec::with_capacity(tree.size());
2123-
out.resize(tree.size(), LazyValue::default());
2108+
let mut out: Vec<Option<LazyValue<'de>>> = Vec::with_capacity(tree.size());
2109+
out.resize(tree.size(), Option::default());
21242110
let cur = &tree.root;
21252111
self.get_many_rec(cur, &mut out, &mut strbuf, &mut remain, is_safe)?;
21262112
Ok(out)

src/pointer/tree.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,26 @@ use crate::index::Index;
2323
/// let mut tree = PointerTree::new();
2424
///
2525
/// tree.add_path(&["u"]);
26+
/// tree.add_path(&["unknown_key"]);
2627
/// tree.add_path(&pointer!["a", "b", "c", 1]);
2728
///
2829
/// let nodes = unsafe { sonic_rs::get_many_unchecked(json, &tree) };
2930
///
30-
/// // the node order is as the order of `add_path`
31-
/// for val in nodes.unwrap() {
32-
/// println!("{}", val.as_raw_str());
33-
/// // 123
34-
/// // "found"
31+
/// match nodes {
32+
/// Ok(vals) => {
33+
/// assert_eq!(vals[0].as_ref().unwrap().as_raw_str(), "123");
34+
/// assert!(vals[1].is_none());
35+
/// assert_eq!(vals[2].as_ref().unwrap().as_raw_str(), "\"found\"");
36+
/// for val in vals {
37+
/// match val {
38+
/// Some(_) => println!("{}", val.as_ref().unwrap().as_raw_str()),
39+
/// None => println!("None"),
40+
/// };
41+
/// }
42+
/// }
43+
/// Err(e) => {
44+
/// println!("err: {:?}", e)
45+
/// }
3546
/// }
3647
/// ```
3748

0 commit comments

Comments
 (0)