Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions examples/get_many.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,25 @@ fn main() {
let mut tree = sonic_rs::PointerTree::new();

tree.add_path(&["u"]);
tree.add_path(&["unknown_key"]);
tree.add_path(pointer!["a", "b", "c", 1]);

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

// the node order is as the order of `add_path`
for val in nodes.unwrap() {
println!("{}", val.as_raw_str());
// 123
// "found"
match nodes {
Ok(vals) => {
assert_eq!(vals[0].as_ref().unwrap().as_raw_str(), "123");
assert!(vals[1].is_none());
assert_eq!(vals[2].as_ref().unwrap().as_raw_str(), "\"found\"");
for val in vals {
match val {
Some(_) => println!("{}", val.as_ref().unwrap().as_raw_str()),
None => println!("None"),
};
}
}
Err(e) => {
println!("err: {:?}", e)
}
}
}
2 changes: 1 addition & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ impl Error {
pub(crate) fn syntax(code: ErrorCode, json: &[u8], index: usize) -> Self {
let position = Position::from_index(index, json);
// generate descript about 16 characters
let mut start = if index < 8 { 0 } else { index - 8 };
let mut start = index.saturating_sub(8);
let mut end = if index + 8 > json.len() {
json.len()
} else {
Expand Down
94 changes: 65 additions & 29 deletions src/lazyvalue/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,32 +185,47 @@ where

/// get_many returns multiple fields from the `PointerTree`.
///
/// The result is a `Result<Vec<LazyValue>>`. The order of the `Vec` is same as the order of the
/// tree.
/// The result is a `Result<Vec<Option<LazyValue>>>`. The order of the `Vec` is same as the order of
/// the tree.
///
/// If a key is unknown, the value at the corresponding position in `Vec` will be None.
/// If json is invalid, or the field not be found, it will return a err.
///
/// # Safety
/// The JSON must be valid and well-formed, otherwise it may return unexpected result.
///
/// # Examples
/// ```
/// use sonic_rs::pointer;
/// # use sonic_rs::pointer;
/// # use sonic_rs::PointerTree;
///
/// let json = r#"
/// {"u": 123, "a": {"b" : {"c": [null, "found"]}}}"#;
/// {"u": 123, "a": {"b" : {"c": [null, "found"]}}}"#;
///
/// // build a pointer tree, representing multiple json path
/// let mut tree = sonic_rs::PointerTree::new();
/// let mut tree = PointerTree::new();
///
/// tree.add_path(&["u"]);
/// tree.add_path(&["unknown_key"]);
/// tree.add_path(&pointer!["a", "b", "c", 1]);
/// let nodes = unsafe { sonic_rs::get_many_unchecked(json, &tree).unwrap() };
/// // the node order is as the order of `add_path`
/// assert_eq!(nodes[0].as_raw_str(), "123");
/// assert_eq!(nodes[1].as_raw_str(), "\"found\"");
///
/// let nodes = unsafe { sonic_rs::get_many_unchecked(json, &tree) };
///
/// match nodes {
/// Ok(vals) => {
/// assert_eq!(vals[0].as_ref().unwrap().as_raw_str(), "123");
/// assert!(vals[1].is_none());
/// assert_eq!(vals[2].as_ref().unwrap().as_raw_str(), "\"found\"");
/// }
/// Err(e) => {
/// panic!("err: {:?}", e)
/// }
/// }
/// ```
pub unsafe fn get_many_unchecked<'de, Input>(
json: Input,
tree: &PointerTree,
) -> Result<Vec<LazyValue<'de>>>
) -> Result<Vec<Option<LazyValue<'de>>>>
where
Input: JsonInput<'de>,
{
Expand Down Expand Up @@ -401,25 +416,41 @@ where

/// get_many returns multiple fields from the [`PointerTree`].
///
/// The result is a `Result<Vec<LazyValue>>`. The order of the `Vec` is same as the order of the
/// tree.
/// The result is a `Result<Vec<Option<LazyValue>>>`. The order of the `Vec` is same as the order of
/// the tree.
///
/// If a key is unknown, the value at the corresponding position in `Vec` will be None.
/// If json is invalid, or the field not be found, it will return a err.
///
/// # Examples
/// ```
/// use sonic_rs::pointer;
/// # use sonic_rs::pointer;
/// # use sonic_rs::PointerTree;
///
/// let json = r#"
/// {"u": 123, "a": {"b" : {"c": [null, "found"]}}}"#;
/// {"u": 123, "a": {"b" : {"c": [null, "found"]}}}"#;
///
/// // build a pointer tree, representing multiple json path
/// let mut tree = sonic_rs::PointerTree::new();
/// let mut tree = PointerTree::new();
///
/// tree.add_path(&["u"]);
/// tree.add_path(&["unknown_key"]);
/// tree.add_path(&pointer!["a", "b", "c", 1]);
/// let nodes = sonic_rs::get_many(json, &tree).unwrap();
/// // the node order is as the order of `add_path`
/// assert_eq!(nodes[0].as_raw_str(), "123");
/// assert_eq!(nodes[1].as_raw_str(), "\"found\"");
///
/// let nodes = unsafe { sonic_rs::get_many(json, &tree) };
///
/// match nodes {
/// Ok(vals) => {
/// assert_eq!(vals[0].as_ref().unwrap().as_raw_str(), "123");
/// assert!(vals[1].is_none());
/// assert_eq!(vals[2].as_ref().unwrap().as_raw_str(), "\"found\"");
/// }
/// Err(e) => {
/// panic!("err: {:?}", e)
/// }
/// }
/// ```
pub fn get_many<'de, Input>(json: Input, tree: &PointerTree) -> Result<Vec<LazyValue<'de>>>
pub fn get_many<'de, Input>(json: Input, tree: &PointerTree) -> Result<Vec<Option<LazyValue<'de>>>>
where
Input: JsonInput<'de>,
{
Expand Down Expand Up @@ -599,7 +630,8 @@ mod test {
tree.add_path(pointer!["a"].iter()); // 4
tree.add_path(pointer!["b", 2].iter()); // 5
tree.add_path(pointer![].iter()); // 6
assert_eq!(tree.size(), 7);
tree.add_path(pointer!["unknown_key"].iter()); // 7
assert_eq!(tree.size(), 8);
tree
}

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

fn test_many_ok(many: Vec<LazyValue<'_>>) {
assert_eq!(many[0].as_raw_str(), "\"hello, world!\"");
fn test_many_ok(many: Vec<Option<LazyValue<'_>>>) {
assert_eq!(many[0].as_ref().unwrap().as_raw_str(), "\"hello, world!\"");
assert_eq!(
many[1].as_raw_str(),
many[1].as_ref().unwrap().as_raw_str(),
"{\n \"a_b_c\":\"hello, world!\"\n }"
);
assert_eq!(many[2].as_raw_str(), "1");
assert_eq!(many[3].as_raw_str(), "{\n \"a_b\":{\n \"a_b_c\":\"hello, world!\"\n },\n \"a_a\": [0, 1, 2]\n }");
assert_eq!(many[4].as_raw_str(), many[3].as_raw_str());
assert_eq!(many[5].as_raw_str(), "true");
assert_eq!(many[2].as_ref().unwrap().as_raw_str(), "1");
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 }");
assert_eq!(
many[4].as_ref().unwrap().as_raw_str(),
many[3].as_ref().unwrap().as_raw_str()
);
assert_eq!(many[5].as_ref().unwrap().as_raw_str(), "true");
// we have strip the leading or trailing spaces
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 }");
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 }");
assert!(many[7].is_none())
}
}
}
36 changes: 11 additions & 25 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1848,7 +1848,7 @@ where
fn get_many_rec(
&mut self,
node: &PointerTreeNode,
out: &mut Vec<LazyValue<'de>>,
out: &mut Vec<Option<LazyValue<'de>>>,
strbuf: &mut Vec<u8>,
remain: &mut usize,
is_safe: bool,
Expand Down Expand Up @@ -1893,7 +1893,7 @@ where
slice = self.read.slice_unchecked(start, self.read.index());
let lv = LazyValue::new(slice.into(), status.into());
for p in &node.order {
out[*p] = lv.clone();
out[*p] = Some(lv.clone());
}
*remain -= node.order.len();
}
Expand All @@ -1905,7 +1905,7 @@ where
&mut self,
mkeys: &MultiKey,
strbuf: &mut Vec<u8>,
out: &mut Vec<LazyValue<'de>>,
out: &mut Vec<Option<LazyValue<'de>>>,
remain: &mut usize,
) -> Result<()> {
debug_assert!(strbuf.is_empty());
Expand All @@ -1923,13 +1923,11 @@ where
Some(_) => unreachable!(),
}

let mut visited = 0;
loop {
let key = self.parse_str_impl(strbuf)?;
self.parse_object_clo()?;
if let Some(val) = mkeys.get(key.deref()) {
self.get_many_rec(val, out, strbuf, remain, false)?;
visited += 1;
if *remain == 0 {
break;
}
Expand All @@ -1953,20 +1951,15 @@ where
}
}

// check whether remaining unknown keys
if visited < mkeys.len() {
perr!(self, GetUnknownKeyInObject)
} else {
Ok(())
}
Ok(())
}

#[allow(clippy::mutable_key_type)]
fn get_many_keys(
&mut self,
mkeys: &MultiKey,
strbuf: &mut Vec<u8>,
out: &mut Vec<LazyValue<'de>>,
out: &mut Vec<Option<LazyValue<'de>>>,
remain: &mut usize,
) -> Result<()> {
debug_assert!(strbuf.is_empty());
Expand All @@ -1985,14 +1978,12 @@ where
}
}

let mut visited = 0;
loop {
let key = self.parse_str_impl(strbuf)?;
self.parse_object_clo()?;
if let Some(val) = mkeys.get(key.deref()) {
// parse the child point tree
self.get_many_rec(val, out, strbuf, remain, true)?;
visited += 1;
if *remain == 0 {
break;
}
Expand All @@ -2009,12 +2000,7 @@ where
}
}

// check whether remaining unknown keys
if visited < mkeys.len() {
perr!(self, GetUnknownKeyInObject)
} else {
Ok(())
}
Ok(())
}

#[cfg(test)]
Expand All @@ -2035,7 +2021,7 @@ where
&mut self,
midx: &MultiIndex,
strbuf: &mut Vec<u8>,
out: &mut Vec<LazyValue<'de>>,
out: &mut Vec<Option<LazyValue<'de>>>,
remain: &mut usize,
) -> Result<()> {
match self.skip_space() {
Expand Down Expand Up @@ -2094,7 +2080,7 @@ where
&mut self,
midx: &MultiIndex,
strbuf: &mut Vec<u8>,
out: &mut Vec<LazyValue<'de>>,
out: &mut Vec<Option<LazyValue<'de>>>,
remain: &mut usize,
) -> Result<()> {
match self.skip_space() {
Expand Down Expand Up @@ -2146,11 +2132,11 @@ where
&mut self,
tree: &PointerTree,
is_safe: bool,
) -> Result<Vec<LazyValue<'de>>> {
) -> Result<Vec<Option<LazyValue<'de>>>> {
let mut strbuf = Vec::with_capacity(DEFAULT_KEY_BUF_CAPACITY);
let mut remain = tree.size();
let mut out: Vec<LazyValue<'de>> = Vec::with_capacity(tree.size());
out.resize(tree.size(), LazyValue::default());
let mut out: Vec<Option<LazyValue<'de>>> = Vec::with_capacity(tree.size());
out.resize(tree.size(), Option::default());
let cur = &tree.root;
self.get_many_rec(cur, &mut out, &mut strbuf, &mut remain, is_safe)?;
Ok(out)
Expand Down
21 changes: 16 additions & 5 deletions src/pointer/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,26 @@ use crate::index::Index;
/// let mut tree = PointerTree::new();
///
/// tree.add_path(&["u"]);
/// tree.add_path(&["unknown_key"]);
/// tree.add_path(&pointer!["a", "b", "c", 1]);
///
/// let nodes = unsafe { sonic_rs::get_many_unchecked(json, &tree) };
///
/// // the node order is as the order of `add_path`
/// for val in nodes.unwrap() {
/// println!("{}", val.as_raw_str());
/// // 123
/// // "found"
/// match nodes {
/// Ok(vals) => {
/// assert_eq!(vals[0].as_ref().unwrap().as_raw_str(), "123");
/// assert!(vals[1].is_none());
/// assert_eq!(vals[2].as_ref().unwrap().as_raw_str(), "\"found\"");
/// for val in vals {
/// match val {
/// Some(_) => println!("{}", val.as_ref().unwrap().as_raw_str()),
/// None => println!("None"),
/// };
/// }
/// }
/// Err(e) => {
/// println!("err: {:?}", e)
/// }
/// }
/// ```

Expand Down
Loading