1use serde_json::Value;
6
7#[derive(Debug, Clone, PartialEq)]
9pub enum JsonPointerError {
10 InvalidFormat(String),
12 PathNotFound(String),
14 InvalidArrayIndex(String),
16}
17
18impl std::fmt::Display for JsonPointerError {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 match self {
21 Self::InvalidFormat(msg) => write!(f, "无效的 JSON Pointer 格式: {}", msg),
22 Self::PathNotFound(path) => write!(f, "路径不存在: {}", path),
23 Self::InvalidArrayIndex(idx) => write!(f, "无效的数组索引: {}", idx),
24 }
25 }
26}
27
28impl std::error::Error for JsonPointerError {}
29
30pub fn resolve_pointer<'a>(data: &'a Value, pointer: &str) -> Result<&'a Value, JsonPointerError> {
34 if pointer.is_empty() || pointer == "/" {
35 return Ok(data);
36 }
37
38 let normalized = if pointer.starts_with('/') {
40 pointer.to_string()
41 } else {
42 format!("/{}", pointer)
43 };
44
45 data.pointer(&normalized)
46 .ok_or_else(|| JsonPointerError::PathNotFound(pointer.to_string()))
47}
48
49pub fn resolve_pointer_mut<'a>(
51 data: &'a mut Value,
52 pointer: &str,
53) -> Result<&'a mut Value, JsonPointerError> {
54 if pointer.is_empty() || pointer == "/" {
55 return Ok(data);
56 }
57
58 let normalized = if pointer.starts_with('/') {
59 pointer.to_string()
60 } else {
61 format!("/{}", pointer)
62 };
63
64 data.pointer_mut(&normalized)
65 .ok_or_else(|| JsonPointerError::PathNotFound(pointer.to_string()))
66}
67
68pub fn set_at_pointer(
70 data: &mut Value,
71 pointer: &str,
72 value: Value,
73) -> Result<(), JsonPointerError> {
74 if pointer.is_empty() || pointer == "/" {
75 *data = value;
76 return Ok(());
77 }
78
79 let normalized = if let Some(stripped) = pointer.strip_prefix('/') {
80 stripped
81 } else {
82 pointer
83 };
84
85 let parts: Vec<&str> = normalized.split('/').collect();
86 let mut current = data;
87
88 for (i, part) in parts.iter().enumerate() {
89 let is_last = i == parts.len() - 1;
90
91 if is_last {
92 if let Ok(idx) = part.parse::<usize>() {
94 if let Value::Array(arr) = current {
95 while arr.len() <= idx {
96 arr.push(Value::Null);
97 }
98 arr[idx] = value;
99 return Ok(());
100 }
101 }
102 if let Value::Object(obj) = current {
103 obj.insert(part.to_string(), value);
104 return Ok(());
105 }
106 return Err(JsonPointerError::InvalidFormat(
107 "父节点不是对象或数组".to_string(),
108 ));
109 }
110
111 if let Ok(idx) = part.parse::<usize>() {
113 if let Value::Array(arr) = current {
114 while arr.len() <= idx {
115 arr.push(Value::Null);
116 }
117 if arr[idx].is_null() {
118 let next_is_array = parts
120 .get(i + 1)
121 .map(|p| p.parse::<usize>().is_ok())
122 .unwrap_or(false);
123 arr[idx] = if next_is_array {
124 Value::Array(vec![])
125 } else {
126 Value::Object(serde_json::Map::new())
127 };
128 }
129 current = &mut arr[idx];
130 continue;
131 }
132 }
133
134 if let Value::Object(obj) = current {
135 if !obj.contains_key(*part) {
136 let next_is_array = parts
137 .get(i + 1)
138 .map(|p| p.parse::<usize>().is_ok())
139 .unwrap_or(false);
140 obj.insert(
141 part.to_string(),
142 if next_is_array {
143 Value::Array(vec![])
144 } else {
145 Value::Object(serde_json::Map::new())
146 },
147 );
148 }
149 current = obj.get_mut(*part).unwrap();
150 continue;
151 }
152
153 return Err(JsonPointerError::InvalidFormat(format!(
154 "无法在路径 {} 处导航",
155 part
156 )));
157 }
158
159 Ok(())
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165 use serde_json::json;
166
167 #[test]
168 fn test_resolve_pointer() {
169 let data = json!({
170 "user": {
171 "name": "张三",
172 "age": 25
173 },
174 "items": ["a", "b", "c"]
175 });
176
177 assert_eq!(resolve_pointer(&data, "/user/name").unwrap(), "张三");
178 assert_eq!(resolve_pointer(&data, "/user/age").unwrap(), 25);
179 assert_eq!(resolve_pointer(&data, "/items/0").unwrap(), "a");
180 assert!(resolve_pointer(&data, "/nonexistent").is_err());
181 }
182
183 #[test]
184 fn test_set_at_pointer() {
185 let mut data = json!({});
186
187 set_at_pointer(&mut data, "/user/name", json!("李四")).unwrap();
188 assert_eq!(data["user"]["name"], "李四");
189
190 set_at_pointer(&mut data, "/items/0", json!("first")).unwrap();
191 assert_eq!(data["items"][0], "first");
192 }
193}