1#![deny(missing_docs)]
35
36use serde_json::Value;
37
38pub fn pluck<'a>(root: &'a Value, path: &str) -> Option<&'a Value> {
40 if let Some(name) = path.strip_prefix("**.") {
43 return bfs_first(root, name);
44 }
45 let mut cur = root;
46 for seg in split_path(path) {
47 cur = step(cur, &seg)?;
48 }
49 Some(cur)
50}
51
52pub fn pluck_mut<'a>(root: &'a mut Value, path: &str) -> Option<&'a mut Value> {
54 if path.starts_with("**.") {
55 return None;
59 }
60 let mut cur = root;
61 for seg in split_path(path) {
62 cur = step_mut(cur, &seg)?;
63 }
64 Some(cur)
65}
66
67#[derive(Debug, Clone, PartialEq)]
68enum Seg {
69 Key(String),
70 Index(i64),
71}
72
73fn split_path(path: &str) -> Vec<Seg> {
74 let mut out = Vec::new();
77 let mut buf = String::new();
78 let mut chars = path.chars().peekable();
79 while let Some(c) = chars.next() {
80 match c {
81 '.' => {
82 if !buf.is_empty() {
83 out.push(Seg::Key(std::mem::take(&mut buf)));
84 }
85 }
86 '[' => {
87 if !buf.is_empty() {
88 out.push(Seg::Key(std::mem::take(&mut buf)));
89 }
90 let mut num = String::new();
91 while let Some(&next) = chars.peek() {
92 if next == ']' {
93 chars.next();
94 break;
95 }
96 num.push(next);
97 chars.next();
98 }
99 if let Ok(n) = num.parse::<i64>() {
100 out.push(Seg::Index(n));
101 }
102 }
103 _ => buf.push(c),
104 }
105 }
106 if !buf.is_empty() {
107 out.push(Seg::Key(buf));
108 }
109 out
110}
111
112fn step<'a>(v: &'a Value, seg: &Seg) -> Option<&'a Value> {
113 match seg {
114 Seg::Key(k) => v.as_object()?.get(k),
115 Seg::Index(i) => {
116 let arr = v.as_array()?;
117 let idx = if *i < 0 {
118 (arr.len() as i64 + *i) as usize
119 } else {
120 *i as usize
121 };
122 arr.get(idx)
123 }
124 }
125}
126
127fn step_mut<'a>(v: &'a mut Value, seg: &Seg) -> Option<&'a mut Value> {
128 match seg {
129 Seg::Key(k) => v.as_object_mut()?.get_mut(k),
130 Seg::Index(i) => {
131 let arr = v.as_array_mut()?;
132 let idx = if *i < 0 {
133 (arr.len() as i64 + *i) as usize
134 } else {
135 *i as usize
136 };
137 arr.get_mut(idx)
138 }
139 }
140}
141
142fn bfs_first<'a>(root: &'a Value, name: &str) -> Option<&'a Value> {
143 let mut queue: std::collections::VecDeque<&Value> = std::collections::VecDeque::new();
144 queue.push_back(root);
145 while let Some(v) = queue.pop_front() {
146 match v {
147 Value::Object(map) => {
148 if let Some(hit) = map.get(name) {
149 return Some(hit);
150 }
151 for (_, child) in map {
152 queue.push_back(child);
153 }
154 }
155 Value::Array(arr) => {
156 for child in arr {
157 queue.push_back(child);
158 }
159 }
160 _ => {}
161 }
162 }
163 None
164}