1#![warn(missing_docs)]
80
81use jsonptr::{Pointer, PointerBuf};
82use serde::{Deserialize, Serialize};
83use serde_json::{Map, Value};
84use std::{
85 borrow::Cow,
86 fmt::{self, Display, Formatter},
87};
88use thiserror::Error;
89
90#[cfg(feature = "diff")]
91mod diff;
92
93#[cfg(feature = "diff")]
94pub use self::diff::diff;
95
96struct WriteAdapter<'a>(&'a mut dyn fmt::Write);
97
98impl<'a> std::io::Write for WriteAdapter<'a> {
99 fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
100 let s = std::str::from_utf8(buf).unwrap();
101 self.0
102 .write_str(s)
103 .map_err(|_| std::io::Error::from(std::io::ErrorKind::Other))?;
104 Ok(buf.len())
105 }
106
107 fn flush(&mut self) -> Result<(), std::io::Error> {
108 Ok(())
109 }
110}
111
112macro_rules! impl_display {
113 ($name:ident) => {
114 impl Display for $name {
115 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
116 let alternate = f.alternate();
117 if alternate {
118 serde_json::to_writer_pretty(WriteAdapter(f), self)
119 .map_err(|_| std::fmt::Error)?;
120 } else {
121 serde_json::to_writer(WriteAdapter(f), self).map_err(|_| std::fmt::Error)?;
122 }
123 Ok(())
124 }
125 }
126 };
127}
128
129#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
131#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
132pub struct Patch(pub Vec<PatchOperation>);
133
134impl_display!(Patch);
135
136impl std::ops::Deref for Patch {
137 type Target = [PatchOperation];
138
139 fn deref(&self) -> &[PatchOperation] {
140 &self.0
141 }
142}
143
144#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
146#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
147pub struct AddOperation {
148 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
151 pub path: PointerBuf,
152 pub value: Value,
154}
155
156impl_display!(AddOperation);
157
158#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
160#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
161pub struct RemoveOperation {
162 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
165 pub path: PointerBuf,
166}
167
168impl_display!(RemoveOperation);
169
170#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
172#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
173pub struct ReplaceOperation {
174 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
177 pub path: PointerBuf,
178 pub value: Value,
180}
181
182impl_display!(ReplaceOperation);
183
184#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
186#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
187pub struct MoveOperation {
188 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
191 pub from: PointerBuf,
192 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
195 pub path: PointerBuf,
196}
197
198impl_display!(MoveOperation);
199
200#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
202#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
203pub struct CopyOperation {
204 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
207 pub from: PointerBuf,
208 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
211 pub path: PointerBuf,
212}
213
214impl_display!(CopyOperation);
215
216#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
218#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
219pub struct TestOperation {
220 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
223 pub path: PointerBuf,
224 pub value: Value,
226}
227
228impl_display!(TestOperation);
229
230#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
232#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
233#[serde(tag = "op")]
234#[serde(rename_all = "lowercase")]
235pub enum PatchOperation {
236 Add(AddOperation),
238 Remove(RemoveOperation),
240 Replace(ReplaceOperation),
242 Move(MoveOperation),
244 Copy(CopyOperation),
246 Test(TestOperation),
248}
249
250impl_display!(PatchOperation);
251
252impl PatchOperation {
253 pub fn path(&self) -> &Pointer {
255 match self {
256 Self::Add(op) => &op.path,
257 Self::Remove(op) => &op.path,
258 Self::Replace(op) => &op.path,
259 Self::Move(op) => &op.path,
260 Self::Copy(op) => &op.path,
261 Self::Test(op) => &op.path,
262 }
263 }
264}
265
266impl Default for PatchOperation {
267 fn default() -> Self {
268 PatchOperation::Test(TestOperation::default())
269 }
270}
271
272#[derive(Debug, Error)]
274#[non_exhaustive]
275pub enum PatchErrorKind {
276 #[error("value did not match")]
278 TestFailed,
279 #[error("\"from\" path is invalid")]
281 InvalidFromPointer,
282 #[error("path is invalid")]
284 InvalidPointer,
285 #[error("cannot move the value inside itself")]
287 CannotMoveInsideItself,
288}
289
290#[derive(Debug, Error)]
292#[error("operation '/{operation}' failed at path '{path}': {kind}")]
293#[non_exhaustive]
294pub struct PatchError {
295 pub operation: usize,
297 pub path: PointerBuf,
299 pub kind: PatchErrorKind,
301}
302
303fn translate_error(kind: PatchErrorKind, operation: usize, path: &Pointer) -> PatchError {
304 PatchError {
305 operation,
306 path: path.to_owned(),
307 kind,
308 }
309}
310
311fn unescape(s: &str) -> Cow<str> {
312 if s.contains('~') {
313 Cow::Owned(s.replace("~1", "/").replace("~0", "~"))
314 } else {
315 Cow::Borrowed(s)
316 }
317}
318
319fn parse_index(str: &str, len: usize) -> Result<usize, PatchErrorKind> {
320 if (str.starts_with('0') && str.len() != 1) || str.starts_with('+') {
322 return Err(PatchErrorKind::InvalidPointer);
323 }
324 match str.parse::<usize>() {
325 Ok(index) if index < len => Ok(index),
326 _ => Err(PatchErrorKind::InvalidPointer),
327 }
328}
329
330fn split_pointer(pointer: &str) -> Result<(&str, &str), PatchErrorKind> {
331 pointer
332 .rfind('/')
333 .ok_or(PatchErrorKind::InvalidPointer)
334 .map(|idx| (&pointer[0..idx], &pointer[idx + 1..]))
335}
336
337fn add(doc: &mut Value, path: &str, value: Value) -> Result<Option<Value>, PatchErrorKind> {
338 if path.is_empty() {
339 return Ok(Some(std::mem::replace(doc, value)));
340 }
341
342 let (parent, last_unescaped) = split_pointer(path)?;
343 let parent = doc
344 .pointer_mut(parent)
345 .ok_or(PatchErrorKind::InvalidPointer)?;
346
347 match *parent {
348 Value::Object(ref mut obj) => Ok(obj.insert(unescape(last_unescaped).into_owned(), value)),
349 Value::Array(ref mut arr) if last_unescaped == "-" => {
350 arr.push(value);
351 Ok(None)
352 }
353 Value::Array(ref mut arr) => {
354 let idx = parse_index(last_unescaped, arr.len() + 1)?;
355 arr.insert(idx, value);
356 Ok(None)
357 }
358 _ => Err(PatchErrorKind::InvalidPointer),
359 }
360}
361
362fn remove(doc: &mut Value, path: &str, allow_last: bool) -> Result<Value, PatchErrorKind> {
363 let (parent, last_unescaped) = split_pointer(path)?;
364 let parent = doc
365 .pointer_mut(parent)
366 .ok_or(PatchErrorKind::InvalidPointer)?;
367
368 match *parent {
369 Value::Object(ref mut obj) => match obj.remove(unescape(last_unescaped).as_ref()) {
370 None => Err(PatchErrorKind::InvalidPointer),
371 Some(val) => Ok(val),
372 },
373 Value::Array(ref mut arr) if allow_last && last_unescaped == "-" => Ok(arr.pop().unwrap()),
374 Value::Array(ref mut arr) => {
375 let idx = parse_index(last_unescaped, arr.len())?;
376 Ok(arr.remove(idx))
377 }
378 _ => Err(PatchErrorKind::InvalidPointer),
379 }
380}
381
382fn replace(doc: &mut Value, path: &str, value: Value) -> Result<Value, PatchErrorKind> {
383 let target = doc
384 .pointer_mut(path)
385 .ok_or(PatchErrorKind::InvalidPointer)?;
386 Ok(std::mem::replace(target, value))
387}
388
389fn mov(
390 doc: &mut Value,
391 from: &str,
392 path: &str,
393 allow_last: bool,
394) -> Result<Option<Value>, PatchErrorKind> {
395 if path.starts_with(from) && path[from.len()..].starts_with('/') {
397 return Err(PatchErrorKind::CannotMoveInsideItself);
398 }
399 let val = remove(doc, from, allow_last).map_err(|err| match err {
400 PatchErrorKind::InvalidPointer => PatchErrorKind::InvalidFromPointer,
401 err => err,
402 })?;
403 add(doc, path, val)
404}
405
406fn copy(doc: &mut Value, from: &str, path: &str) -> Result<Option<Value>, PatchErrorKind> {
407 let source = doc
408 .pointer(from)
409 .ok_or(PatchErrorKind::InvalidFromPointer)?
410 .clone();
411 add(doc, path, source)
412}
413
414fn test(doc: &Value, path: &str, expected: &Value) -> Result<(), PatchErrorKind> {
415 let target = doc.pointer(path).ok_or(PatchErrorKind::InvalidPointer)?;
416 if *target == *expected {
417 Ok(())
418 } else {
419 Err(PatchErrorKind::TestFailed)
420 }
421}
422
423pub fn patch(doc: &mut Value, patch: &[PatchOperation]) -> Result<(), PatchError> {
455 let mut undo_stack = Vec::with_capacity(patch.len());
456 if let Err(e) = apply_patches(doc, patch, Some(&mut undo_stack)) {
457 if let Err(e) = undo_patches(doc, &undo_stack) {
458 unreachable!("unable to undo applied patches: {e}")
459 }
460 return Err(e);
461 }
462 Ok(())
463}
464
465pub fn patch_unsafe(doc: &mut Value, patch: &[PatchOperation]) -> Result<(), PatchError> {
497 apply_patches(doc, patch, None)
498}
499
500fn undo_patches(doc: &mut Value, undo_patches: &[PatchOperation]) -> Result<(), PatchError> {
503 for (operation, patch) in undo_patches.iter().enumerate().rev() {
504 match patch {
505 PatchOperation::Add(op) => {
506 add(doc, op.path.as_str(), op.value.clone())
507 .map_err(|e| translate_error(e, operation, &op.path))?;
508 }
509 PatchOperation::Remove(op) => {
510 remove(doc, op.path.as_str(), true)
511 .map_err(|e| translate_error(e, operation, &op.path))?;
512 }
513 PatchOperation::Replace(op) => {
514 replace(doc, op.path.as_str(), op.value.clone())
515 .map_err(|e| translate_error(e, operation, &op.path))?;
516 }
517 PatchOperation::Move(op) => {
518 mov(doc, op.from.as_str(), op.path.as_str(), true)
519 .map_err(|e| translate_error(e, operation, &op.path))?;
520 }
521 PatchOperation::Copy(op) => {
522 copy(doc, op.from.as_str(), op.path.as_str())
523 .map_err(|e| translate_error(e, operation, &op.path))?;
524 }
525 _ => unreachable!(),
526 }
527 }
528
529 Ok(())
530}
531
532fn apply_patches(
536 doc: &mut Value,
537 patches: &[PatchOperation],
538 undo_stack: Option<&mut Vec<PatchOperation>>,
539) -> Result<(), PatchError> {
540 for (operation, patch) in patches.iter().enumerate() {
541 match patch {
542 PatchOperation::Add(ref op) => {
543 let prev = add(doc, op.path.as_str(), op.value.clone())
544 .map_err(|e| translate_error(e, operation, &op.path))?;
545 if let Some(&mut ref mut undo_stack) = undo_stack {
546 undo_stack.push(match prev {
547 None => PatchOperation::Remove(RemoveOperation {
548 path: op.path.clone(),
549 }),
550 Some(v) => PatchOperation::Add(AddOperation {
551 path: op.path.clone(),
552 value: v,
553 }),
554 })
555 }
556 }
557 PatchOperation::Remove(ref op) => {
558 let prev = remove(doc, op.path.as_str(), false)
559 .map_err(|e| translate_error(e, operation, &op.path))?;
560 if let Some(&mut ref mut undo_stack) = undo_stack {
561 undo_stack.push(PatchOperation::Add(AddOperation {
562 path: op.path.clone(),
563 value: prev,
564 }))
565 }
566 }
567 PatchOperation::Replace(ref op) => {
568 let prev = replace(doc, op.path.as_str(), op.value.clone())
569 .map_err(|e| translate_error(e, operation, &op.path))?;
570 if let Some(&mut ref mut undo_stack) = undo_stack {
571 undo_stack.push(PatchOperation::Replace(ReplaceOperation {
572 path: op.path.clone(),
573 value: prev,
574 }))
575 }
576 }
577 PatchOperation::Move(ref op) => {
578 let prev = mov(doc, op.from.as_str(), op.path.as_str(), false)
579 .map_err(|e| translate_error(e, operation, &op.path))?;
580 if let Some(&mut ref mut undo_stack) = undo_stack {
581 if let Some(prev) = prev {
582 undo_stack.push(PatchOperation::Add(AddOperation {
583 path: op.path.clone(),
584 value: prev,
585 }));
586 }
587 undo_stack.push(PatchOperation::Move(MoveOperation {
588 from: op.path.clone(),
589 path: op.from.clone(),
590 }));
591 }
592 }
593 PatchOperation::Copy(ref op) => {
594 let prev = copy(doc, op.from.as_str(), op.path.as_str())
595 .map_err(|e| translate_error(e, operation, &op.path))?;
596 if let Some(&mut ref mut undo_stack) = undo_stack {
597 undo_stack.push(match prev {
598 None => PatchOperation::Remove(RemoveOperation {
599 path: op.path.clone(),
600 }),
601 Some(v) => PatchOperation::Add(AddOperation {
602 path: op.path.clone(),
603 value: v,
604 }),
605 })
606 }
607 }
608 PatchOperation::Test(ref op) => {
609 test(doc, op.path.as_str(), &op.value)
610 .map_err(|e| translate_error(e, operation, &op.path))?;
611 }
612 }
613 }
614
615 Ok(())
616}
617
618pub fn merge(doc: &mut Value, patch: &Value) {
662 if !patch.is_object() {
663 *doc = patch.clone();
664 return;
665 }
666
667 if !doc.is_object() {
668 *doc = Value::Object(Map::new());
669 }
670 let map = doc.as_object_mut().unwrap();
671 for (key, value) in patch.as_object().unwrap() {
672 if value.is_null() {
673 map.remove(key.as_str());
674 } else {
675 merge(map.entry(key.as_str()).or_insert(Value::Null), value);
676 }
677 }
678}