1use core::panic;
2use std::collections::HashMap;
3use std::hash::RandomState;
4
5use crate::{Event, EventVisitor, Path, PathSegment, ScannerError, Utf8Encoding};
6
7impl Event for serde_json::Value {
8 type Encoding = Utf8Encoding;
9
10 fn visit_event<'a>(
11 &'a mut self,
12 visitor: &mut impl EventVisitor<'a>,
13 ) -> Result<(), ScannerError> {
14 match self {
15 serde_json::Value::Null => Ok(()),
16 serde_json::Value::Bool(value) => {
17 visitor.visit_string(value.to_string().as_str()).map(|_| {})
18 }
19 serde_json::Value::Number(number) => visitor
20 .visit_string(number.to_string().as_str())
21 .map(|_| {}),
22 serde_json::Value::String(s) => visitor.visit_string(s).map(|_| {}),
23 serde_json::Value::Object(map) => {
24 for (k, child) in map.iter_mut() {
25 visitor.push_segment(k.as_str().into());
26 child.visit_event(visitor)?;
27 visitor.pop_segment();
28 }
29 Ok(())
30 }
31 serde_json::Value::Array(values) => {
32 for (i, value) in values.iter_mut().enumerate() {
33 visitor.push_segment(PathSegment::Index(i));
34 value.visit_event(visitor)?;
35 visitor.pop_segment();
36 }
37 Ok(())
38 }
39 }
40 }
41
42 fn visit_string_mut(&mut self, path: &Path, mut visit: impl FnMut(&mut String) -> bool) {
43 let mut value = self;
44 for segment in &path.segments {
45 match segment {
46 PathSegment::Field(key) => {
47 value = value
48 .as_object_mut()
49 .unwrap()
50 .get_mut(key.as_ref())
51 .unwrap();
52 }
53 PathSegment::Index(i) => {
54 value = value.as_array_mut().unwrap().get_mut(*i).unwrap();
55 }
56 }
57 }
58 match value {
59 serde_json::Value::String(s) => {
60 (visit)(s);
61 }
62 _ => panic!("unknown value"),
63 };
64 }
65}
66
67impl Event for HashMap<String, serde_json::Value, RandomState> {
68 type Encoding = Utf8Encoding;
69
70 fn visit_event<'a>(
71 &'a mut self,
72 visitor: &mut impl EventVisitor<'a>,
73 ) -> Result<(), ScannerError> {
74 for (k, v) in self.iter_mut() {
75 visitor.push_segment(PathSegment::Field(k.as_str().into()));
76 v.visit_event(visitor)?;
77 visitor.pop_segment();
78 }
79 Ok(())
80 }
81
82 fn visit_string_mut(&mut self, path: &Path, mut visit: impl FnMut(&mut String) -> bool) {
83 let first_segment = path.segments.first().unwrap();
84 let mut remaining_segments = path.segments.clone();
85 remaining_segments.remove(0);
86 if let PathSegment::Field(field) = first_segment {
87 let value = self.get_mut(&field.to_string()).unwrap();
88 value.visit_string_mut(&Path::from(remaining_segments), &mut visit);
89 }
90 }
91}
92
93#[cfg(test)]
94mod test {
95 use std::collections::HashMap;
96
97 use serde_json::{Map, Value, json};
98
99 use crate::VisitStringResult;
100
101 use super::*;
102
103 #[derive(Debug, PartialEq, Eq)]
104 enum VisitOp {
105 Push(PathSegment<'static>),
106 Pop,
107 Visit(String),
108 }
109
110 struct Visitor {
111 path: Path<'static>,
112 ops: Vec<VisitOp>,
113 }
114
115 impl<'path> EventVisitor<'path> for Visitor {
116 fn push_segment(&mut self, segment: PathSegment<'path>) {
117 self.ops.push(VisitOp::Push(segment.into_static()));
118 }
119
120 fn pop_segment(&mut self) {
121 self.ops.push(VisitOp::Pop);
122 }
123
124 fn visit_string<'s>(
125 &'s mut self,
126 value: &str,
127 ) -> Result<VisitStringResult<'s, 'path>, ScannerError> {
128 self.ops.push(VisitOp::Visit(value.to_string()));
129 Ok(VisitStringResult {
130 might_mutate: true,
131 path: &self.path,
132 })
133 }
134 }
135
136 #[test]
137 pub fn test_hashmap_event() {
138 let mut map = Map::new();
139 map.insert(
140 "key-a-1".to_string(),
141 Value::String("value-a-1".to_string()),
142 );
143 map.insert(
144 "key-a-2".to_string(),
145 Value::String("value-b-1".to_string()),
146 );
147 map.insert("key-a-3".to_string(), json!(["an", "array"]));
148 let mut event = HashMap::from([("key-a".to_string(), Value::Object(map))]);
149
150 let mut visitor = Visitor {
161 ops: vec![],
162 path: Path::root(),
163 };
164 event.visit_event(&mut visitor).unwrap();
165
166 assert_eq!(
167 visitor.ops,
168 vec![
169 VisitOp::Push(PathSegment::Field("key-a".into())),
170 VisitOp::Push(PathSegment::Field("key-a-1".into())),
171 VisitOp::Visit("value-a-1".into()),
172 VisitOp::Pop,
173 VisitOp::Push(PathSegment::Field("key-a-2".into())),
174 VisitOp::Visit("value-b-1".into()),
175 VisitOp::Pop,
176 VisitOp::Push(PathSegment::Field("key-a-3".into())),
177 VisitOp::Push(PathSegment::Index(0)),
178 VisitOp::Visit("an".into()),
179 VisitOp::Pop,
180 VisitOp::Push(PathSegment::Index(1)),
181 VisitOp::Visit("array".into()),
182 VisitOp::Pop,
183 VisitOp::Pop,
184 VisitOp::Pop,
185 ]
186 );
187
188 let mut leaf = String::new();
190 event.visit_string_mut(
191 &Path::from(vec![
192 PathSegment::Field("key-a".into()),
193 PathSegment::Field("key-a-3".into()),
194 PathSegment::Index(1),
195 ]),
196 |s| {
197 leaf = s.clone();
198 true
199 },
200 );
201 assert_eq!(leaf, "array".to_string())
205 }
206}