1use crate::{JsonObject, Value};
17
18pub type JsonNodePath<'a> = [JsonNodePathSegment<'a>];
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26pub enum JsonNodePathSegment<'a> {
27 Key(&'a str),
29 Index(u32),
31}
32
33impl<'a> From<&'a str> for JsonNodePathSegment<'a> {
34 fn from(key: &'a str) -> Self {
35 Self::Key(key)
36 }
37}
38
39impl From<u32> for JsonNodePathSegment<'_> {
40 fn from(index: u32) -> Self {
41 Self::Index(index)
42 }
43}
44
45impl std::fmt::Display for JsonNodePathSegment<'_> {
46 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
47 match self {
48 JsonNodePathSegment::Key(key) => write!(f, "Key: {}", key),
49 JsonNodePathSegment::Index(ind) => write!(f, "Ind: {}", ind),
50 }
51 }
52}
53
54#[macro_export]
67macro_rules! path {
68 [ $( $segment:expr ),* ] => {
69 &[ $( $crate::JsonNodePathSegment::from($segment) ),* ]
70 };
71}
72
73pub struct DisplayWrapper<'a, T: ?Sized>(pub &'a T);
76
77impl std::fmt::Display for DisplayWrapper<'_, JsonNodePath<'_>> {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 write!(f, "$")?;
81 for segment in self.0 {
82 match segment {
83 JsonNodePathSegment::Key(key) => write!(f, ".{}", key)?,
86 JsonNodePathSegment::Index(index) => write!(f, "[{}]", index)?,
87 }
88 }
89 Ok(())
90 }
91}
92
93fn index_by_path<'v>(mut value: &'v Value, path: &JsonNodePath) -> Option<&'v Value> {
94 for segment in path {
95 match (value, segment) {
96 (Value::Array(array), JsonNodePathSegment::Index(index)) => {
97 value = array.get(*index as usize)?;
98 }
99 (Value::Object(object), JsonNodePathSegment::Key(key)) => {
100 value = object.get(*key)?;
101 }
102 _ => return None,
103 }
104 }
105 Some(value)
106}
107
108fn index_object_by_path<'o>(object: &'o JsonObject, path: &JsonNodePath) -> Option<&'o Value> {
110 let (head, tail) = path.split_first()?;
111 match head {
112 JsonNodePathSegment::Key(key) => index_by_path(object.get(*key)?, tail),
113 _ => None,
114 }
115}
116
117pub(crate) fn index_mut_object_by_path<'a>(
120 object: &'a mut JsonObject,
121 path: &JsonNodePath,
122) -> Option<&'a mut Value> {
123 let (head, tail) = path.split_first()?;
124 match head {
125 JsonNodePathSegment::Key(key) => index_mut_by_path(object.get_mut(*key)?, tail),
126 _ => None,
127 }
128}
129
130fn index_mut_by_path<'a>(mut value: &'a mut Value, path: &JsonNodePath) -> Option<&'a mut Value> {
131 for segment in path {
132 match (value, segment) {
133 (Value::Array(array), JsonNodePathSegment::Index(index)) => {
134 value = array.get_mut(*index as usize)?;
135 }
136 (Value::Object(object), JsonNodePathSegment::Key(key)) => {
137 value = object.get_mut(*key)?;
138 }
139 _ => return None,
140 }
141 }
142 Some(value)
143}
144
145pub(crate) fn paths_exist<'a, 'p>(
146 value: &'a JsonObject,
147 paths: &[&'p JsonNodePath<'a>],
148) -> Result<(), Vec<&'p JsonNodePath<'a>>> {
149 let mut nonexistent_paths = vec![];
150
151 for path in paths {
152 if !path.is_empty() && index_object_by_path(value, path).is_none() {
153 nonexistent_paths.push(*path);
154 }
155 }
156
157 if nonexistent_paths.is_empty() {
158 Ok(())
159 } else {
160 Err(nonexistent_paths)
161 }
162}
163
164impl<'a> From<&serde_json_path::PathElement<'a>> for JsonNodePathSegment<'a> {
165 fn from(value: &serde_json_path::PathElement<'a>) -> Self {
166 match *value {
167 serde_json_path::PathElement::Index(index) => Self::Index(index as u32),
168 serde_json_path::PathElement::Name(name) => Self::Key(name),
169 }
170 }
171}