1pub use self::diff::diff;
70use crate::value_map::ValueMap;
71use crate::{Value, ValueMapHelper};
72use serde::{Deserialize, Serialize};
73use std::borrow::Cow;
74use thiserror::Error;
75mod diff;
76
77#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
79pub struct Patch(pub Vec<PatchOperation>);
80
81impl std::ops::Deref for Patch {
82 type Target = [PatchOperation];
83
84 fn deref(&self) -> &[PatchOperation] {
85 &self.0
86 }
87}
88
89#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
91pub struct AddOperation {
92 pub path: String,
93 pub value: Value,
95}
96
97#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
99pub struct RemoveOperation {
100 pub path: String,
101}
102
103#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
105pub struct ReplaceOperation {
106 pub path: String,
108 pub value: Value,
110}
111
112#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
114pub struct MoveOperation {
115 pub from: String,
117 pub path: String,
119}
120
121#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
123pub struct CopyOperation {
124 pub from: String,
126 pub path: String,
128}
129
130#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
132pub struct TestOperation {
133 pub path: String,
135 pub value: Value,
137}
138
139#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
141#[serde(tag = "op")]
142#[serde(rename_all = "lowercase")]
143pub enum PatchOperation {
144 Add(AddOperation),
146 Remove(RemoveOperation),
148 Replace(ReplaceOperation),
150 Move(MoveOperation),
152 Copy(CopyOperation),
154 Test(TestOperation),
156}
157
158#[derive(Debug, Error)]
160#[non_exhaustive]
161pub enum PatchErrorKind {
162 #[error("value did not match")]
164 TestFailed,
165 #[error("\"from\" path is invalid")]
167 InvalidFromPointer,
168 #[error("path is invalid")]
170 InvalidPointer,
171 #[error("cannot move the value inside itself")]
173 CannotMoveInsideItself,
174}
175
176#[derive(Debug, Error)]
178#[error("Operation '/{operation}' failed at path '{path}': {kind}")]
179#[non_exhaustive]
180pub struct PatchError {
181 pub operation: usize,
183 pub path: String,
185 pub kind: PatchErrorKind,
187}
188
189fn translate_error(kind: PatchErrorKind, operation: usize, path: &str) -> PatchError {
190 PatchError {
191 operation,
192 path: path.to_owned(),
193 kind,
194 }
195}
196
197fn unescape(s: &str) -> Cow<'_, str> {
198 if s.contains('~') {
199 Cow::Owned(s.replace("~1", "/").replace("~0", "~"))
200 } else {
201 Cow::Borrowed(s)
202 }
203}
204
205fn parse_index(str: &str, len: usize) -> Result<usize, PatchErrorKind> {
206 if (str.starts_with('0') && str.len() != 1) || str.starts_with('+') {
208 return Err(PatchErrorKind::InvalidPointer);
209 }
210 match str.parse::<usize>() {
211 Ok(index) if index < len => Ok(index),
212 _ => Err(PatchErrorKind::InvalidPointer),
213 }
214}
215
216fn split_pointer(pointer: &str) -> Result<(&str, &str), PatchErrorKind> {
217 pointer
218 .rfind('/')
219 .ok_or(PatchErrorKind::InvalidPointer)
220 .map(|idx| (&pointer[0..idx], &pointer[idx + 1..]))
221}
222
223fn add(doc: &mut Value, path: &str, value: Value) -> Result<Option<Value>, PatchErrorKind> {
224 if path.is_empty() {
225 return Ok(Some(std::mem::replace(doc, value)));
226 }
227
228 let (parent, last_unescaped) = split_pointer(path)?;
229 let parent = doc
230 .pointer_mut(parent)
231 .ok_or(PatchErrorKind::InvalidPointer)?;
232
233 match *parent {
234 Value::Map(ref mut obj) => {
235 obj.insert_string_key_value(unescape(last_unescaped).into_owned(), value.clone());
236 Ok(Some(value))
237 }
238 Value::Array(ref mut arr) if last_unescaped == "-" => {
239 arr.push(value);
240 Ok(None)
241 }
242 Value::Array(ref mut arr) => {
243 let idx = parse_index(last_unescaped, arr.len() + 1)?;
244 arr.insert(idx, value);
245 Ok(None)
246 }
247 _ => Err(PatchErrorKind::InvalidPointer),
248 }
249}
250
251fn remove(doc: &mut Value, path: &str, allow_last: bool) -> Result<Value, PatchErrorKind> {
252 let (parent, last_unescaped) = split_pointer(path)?;
253 let parent = doc
254 .pointer_mut(parent)
255 .ok_or(PatchErrorKind::InvalidPointer)?;
256
257 match *parent {
258 Value::Map(ref mut obj) => match obj.remove_optional_key(unescape(last_unescaped).as_ref())
259 {
260 None => Err(PatchErrorKind::InvalidPointer),
261 Some(val) => Ok(val),
262 },
263 Value::Array(ref mut arr) if allow_last && last_unescaped == "-" => Ok(arr.pop().unwrap()),
264 Value::Array(ref mut arr) => {
265 let idx = parse_index(last_unescaped, arr.len())?;
266 Ok(arr.remove(idx))
267 }
268 _ => Err(PatchErrorKind::InvalidPointer),
269 }
270}
271
272fn replace(doc: &mut Value, path: &str, value: Value) -> Result<Value, PatchErrorKind> {
273 let target = doc
274 .pointer_mut(path)
275 .ok_or(PatchErrorKind::InvalidPointer)?;
276 Ok(std::mem::replace(target, value))
277}
278
279fn mov(
280 doc: &mut Value,
281 from: &str,
282 path: &str,
283 allow_last: bool,
284) -> Result<Option<Value>, PatchErrorKind> {
285 if path.starts_with(from) && path[from.len()..].starts_with('/') {
287 return Err(PatchErrorKind::CannotMoveInsideItself);
288 }
289 let val = remove(doc, from, allow_last).map_err(|err| match err {
290 PatchErrorKind::InvalidPointer => PatchErrorKind::InvalidFromPointer,
291 err => err,
292 })?;
293 add(doc, path, val)
294}
295
296fn copy(doc: &mut Value, from: &str, path: &str) -> Result<Option<Value>, PatchErrorKind> {
297 let source = doc
298 .pointer(from)
299 .ok_or(PatchErrorKind::InvalidFromPointer)?
300 .clone();
301 add(doc, path, source)
302}
303
304fn test(doc: &Value, path: &str, expected: &Value) -> Result<(), PatchErrorKind> {
305 let target = doc.pointer(path).ok_or(PatchErrorKind::InvalidPointer)?;
306 if *target == *expected {
307 Ok(())
308 } else {
309 Err(PatchErrorKind::TestFailed)
310 }
311}
312
313pub fn patch(doc: &mut Value, patch: &[PatchOperation]) -> Result<(), PatchError> {
344 apply_patches(doc, 0, patch)
345}
346
347fn apply_patches(
350 doc: &mut Value,
351 operation: usize,
352 patches: &[PatchOperation],
353) -> Result<(), PatchError> {
354 let (patch, tail) = match patches.split_first() {
355 None => return Ok(()),
356 Some((patch, tail)) => (patch, tail),
357 };
358
359 match *patch {
360 PatchOperation::Add(ref op) => {
361 let prev = add(doc, &op.path, op.value.clone())
362 .map_err(|e| translate_error(e, operation, &op.path))?;
363 apply_patches(doc, operation + 1, tail).inspect_err(move |_| {
364 match prev {
365 None => remove(doc, &op.path, true).unwrap(),
366 Some(v) => add(doc, &op.path, v).unwrap().unwrap(),
367 };
368 })
369 }
370 PatchOperation::Remove(ref op) => {
371 let prev = remove(doc, &op.path, false)
372 .map_err(|e| translate_error(e, operation, &op.path))?;
373 apply_patches(doc, operation + 1, tail).inspect_err(move |_| {
374 assert!(add(doc, &op.path, prev).unwrap().is_none());
375 })
376 }
377 PatchOperation::Replace(ref op) => {
378 let prev = replace(doc, &op.path, op.value.clone())
379 .map_err(|e| translate_error(e, operation, &op.path))?;
380 apply_patches(doc, operation + 1, tail).inspect_err(move |_| {
381 replace(doc, &op.path, prev).unwrap();
382 })
383 }
384 PatchOperation::Move(ref op) => {
385 let prev = mov(doc, op.from.as_str(), &op.path, false)
386 .map_err(|e| translate_error(e, operation, &op.path))?;
387 apply_patches(doc, operation + 1, tail).inspect_err(move |_| {
388 mov(doc, &op.path, op.from.as_str(), true).unwrap();
389 if let Some(prev) = prev {
390 assert!(add(doc, &op.path, prev).unwrap().is_none());
391 }
392 })
393 }
394 PatchOperation::Copy(ref op) => {
395 let prev = copy(doc, op.from.as_str(), &op.path)
396 .map_err(|e| translate_error(e, operation, &op.path))?;
397 apply_patches(doc, operation + 1, tail).inspect_err(move |_| {
398 match prev {
399 None => remove(doc, &op.path, true).unwrap(),
400 Some(v) => add(doc, &op.path, v).unwrap().unwrap(),
401 };
402 })
403 }
404 PatchOperation::Test(ref op) => {
405 test(doc, &op.path, &op.value).map_err(|e| translate_error(e, operation, &op.path))?;
406 apply_patches(doc, operation + 1, tail)
407 }
408 }
409}
410
411pub fn merge(doc: &mut Value, patch: &Value) {
455 if !patch.is_map() {
456 *doc = patch.clone();
457 return;
458 }
459
460 if !doc.is_map() {
461 *doc = Value::Map(ValueMap::new());
462 }
463 let map = doc.as_map_mut().unwrap();
464 for (key, value) in patch.as_map().unwrap() {
465 if value.is_null() {
466 map.remove_optional_key_value(key);
467 } else {
468 merge(map.get_key_by_value_mut_or_insert(key, Value::Null), value);
469 }
470 }
471}