1#![warn(missing_docs)]
80
81use jsonptr::{index::Index, Pointer, PointerBuf};
82use serde::{Deserialize, Serialize};
83use serde_json::{Map, Value};
84use std::fmt::{self, Display, Formatter};
85use thiserror::Error;
86
87pub use jsonptr;
90
91#[cfg(feature = "diff")]
92mod diff;
93
94#[cfg(feature = "diff")]
95pub use self::diff::diff;
96
97struct WriteAdapter<'a>(&'a mut dyn fmt::Write);
98
99impl std::io::Write for WriteAdapter<'_> {
100 fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
101 let s = std::str::from_utf8(buf).unwrap();
102 self.0
103 .write_str(s)
104 .map_err(|_| std::io::Error::from(std::io::ErrorKind::Other))?;
105 Ok(buf.len())
106 }
107
108 fn flush(&mut self) -> Result<(), std::io::Error> {
109 Ok(())
110 }
111}
112
113macro_rules! impl_display {
114 ($name:ident) => {
115 impl Display for $name {
116 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
117 let alternate = f.alternate();
118 if alternate {
119 serde_json::to_writer_pretty(WriteAdapter(f), self)
120 .map_err(|_| std::fmt::Error)?;
121 } else {
122 serde_json::to_writer(WriteAdapter(f), self).map_err(|_| std::fmt::Error)?;
123 }
124 Ok(())
125 }
126 }
127 };
128}
129
130#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
132#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
133pub struct Patch(pub Vec<PatchOperation>);
134
135impl_display!(Patch);
136
137impl std::ops::Deref for Patch {
138 type Target = [PatchOperation];
139
140 fn deref(&self) -> &[PatchOperation] {
141 &self.0
142 }
143}
144
145#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
147#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
148pub struct AddOperation {
149 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
152 pub path: PointerBuf,
153 pub value: Value,
155}
156
157impl_display!(AddOperation);
158
159#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
161#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
162pub struct RemoveOperation {
163 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
166 pub path: PointerBuf,
167}
168
169impl_display!(RemoveOperation);
170
171#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
173#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
174pub struct ReplaceOperation {
175 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
178 pub path: PointerBuf,
179 pub value: Value,
181}
182
183impl_display!(ReplaceOperation);
184
185#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
187#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
188pub struct MoveOperation {
189 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
192 pub from: PointerBuf,
193 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
196 pub path: PointerBuf,
197}
198
199impl_display!(MoveOperation);
200
201#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
203#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
204pub struct CopyOperation {
205 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
208 pub from: PointerBuf,
209 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
212 pub path: PointerBuf,
213}
214
215impl_display!(CopyOperation);
216
217#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
219#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
220pub struct TestOperation {
221 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
224 pub path: PointerBuf,
225 pub value: Value,
227}
228
229impl_display!(TestOperation);
230
231#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
233#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
234#[serde(tag = "op")]
235#[serde(rename_all = "lowercase")]
236pub enum PatchOperation {
237 Add(AddOperation),
239 Remove(RemoveOperation),
241 Replace(ReplaceOperation),
243 Move(MoveOperation),
245 Copy(CopyOperation),
247 Test(TestOperation),
249}
250
251impl_display!(PatchOperation);
252
253impl PatchOperation {
254 pub fn path(&self) -> &Pointer {
256 match self {
257 Self::Add(op) => &op.path,
258 Self::Remove(op) => &op.path,
259 Self::Replace(op) => &op.path,
260 Self::Move(op) => &op.path,
261 Self::Copy(op) => &op.path,
262 Self::Test(op) => &op.path,
263 }
264 }
265}
266
267impl Default for PatchOperation {
268 fn default() -> Self {
269 PatchOperation::Test(TestOperation::default())
270 }
271}
272
273#[derive(Debug, Error)]
275#[non_exhaustive]
276pub enum PatchErrorKind {
277 #[error("value did not match")]
279 TestFailed,
280 #[error("\"from\" path is invalid")]
282 InvalidFromPointer,
283 #[error("path is invalid")]
285 InvalidPointer,
286 #[error("cannot move the value inside itself")]
288 CannotMoveInsideItself,
289}
290
291impl From<jsonptr::index::ParseIndexError> for PatchErrorKind {
292 fn from(_: jsonptr::index::ParseIndexError) -> Self {
293 Self::InvalidPointer
294 }
295}
296
297impl From<jsonptr::index::OutOfBoundsError> for PatchErrorKind {
298 fn from(_: jsonptr::index::OutOfBoundsError) -> Self {
299 Self::InvalidPointer
300 }
301}
302
303#[derive(Debug, Error)]
305#[error("operation '/{operation}' failed at path '{path}': {kind}")]
306#[non_exhaustive]
307pub struct PatchError {
308 pub operation: usize,
310 pub path: PointerBuf,
312 pub kind: PatchErrorKind,
314}
315
316fn translate_error(kind: PatchErrorKind, operation: usize, path: &Pointer) -> PatchError {
317 PatchError {
318 operation,
319 path: path.to_owned(),
320 kind,
321 }
322}
323
324fn add(doc: &mut Value, path: &Pointer, value: Value) -> Result<Option<Value>, PatchErrorKind> {
325 let Some((parent, last)) = path.split_back() else {
326 return Ok(Some(std::mem::replace(doc, value)));
328 };
329
330 let mut parent = doc
331 .pointer_mut(parent.as_str())
332 .ok_or(PatchErrorKind::InvalidPointer)?;
333
334 match &mut parent {
335 Value::Object(obj) => Ok(obj.insert(last.decoded().into_owned(), value)),
336 Value::Array(arr) => {
337 let idx = last.to_index()?.for_len_incl(arr.len())?;
338 arr.insert(idx, value);
339 Ok(None)
340 }
341 _ => Err(PatchErrorKind::InvalidPointer),
342 }
343}
344
345fn remove(doc: &mut Value, path: &Pointer, allow_last: bool) -> Result<Value, PatchErrorKind> {
346 let Some((parent, last)) = path.split_back() else {
347 return Err(PatchErrorKind::InvalidPointer);
348 };
349 let mut parent = doc
350 .pointer_mut(parent.as_str())
351 .ok_or(PatchErrorKind::InvalidPointer)?;
352
353 match &mut parent {
354 Value::Object(obj) => match obj.remove(last.decoded().as_ref()) {
355 None => Err(PatchErrorKind::InvalidPointer),
356 Some(val) => Ok(val),
357 },
358 Value::Array(arr) if allow_last && matches!(last.to_index(), Ok(Index::Next)) => {
360 Ok(arr.pop().unwrap())
361 }
362 Value::Array(arr) => {
363 let idx = last.to_index()?.for_len(arr.len())?;
364 Ok(arr.remove(idx))
365 }
366 _ => Err(PatchErrorKind::InvalidPointer),
367 }
368}
369
370fn replace(doc: &mut Value, path: &Pointer, value: Value) -> Result<Value, PatchErrorKind> {
371 let target = doc
372 .pointer_mut(path.as_str())
373 .ok_or(PatchErrorKind::InvalidPointer)?;
374 Ok(std::mem::replace(target, value))
375}
376
377fn mov(
378 doc: &mut Value,
379 from: &Pointer,
380 path: &Pointer,
381 allow_last: bool,
382) -> Result<Option<Value>, PatchErrorKind> {
383 if path.starts_with(from) && path.len() != from.len() {
385 return Err(PatchErrorKind::CannotMoveInsideItself);
386 }
387 let val = remove(doc, from, allow_last).map_err(|err| match err {
388 PatchErrorKind::InvalidPointer => PatchErrorKind::InvalidFromPointer,
389 err => err,
390 })?;
391 add(doc, path, val)
392}
393
394fn copy(doc: &mut Value, from: &Pointer, path: &Pointer) -> Result<Option<Value>, PatchErrorKind> {
395 let source = doc
396 .pointer(from.as_str())
397 .ok_or(PatchErrorKind::InvalidFromPointer)?
398 .clone();
399 add(doc, path, source)
400}
401
402fn test(doc: &Value, path: &Pointer, expected: &Value) -> Result<(), PatchErrorKind> {
403 let target = doc
404 .pointer(path.as_str())
405 .ok_or(PatchErrorKind::InvalidPointer)?;
406 if *target == *expected {
407 Ok(())
408 } else {
409 Err(PatchErrorKind::TestFailed)
410 }
411}
412
413pub fn patch(doc: &mut Value, patch: &[PatchOperation]) -> Result<(), PatchError> {
445 let mut undo_stack = Vec::with_capacity(patch.len());
446 if let Err(e) = apply_patches(doc, patch, Some(&mut undo_stack)) {
447 if let Err(e) = undo_patches(doc, &undo_stack) {
448 unreachable!("unable to undo applied patches: {e}")
449 }
450 return Err(e);
451 }
452 Ok(())
453}
454
455pub fn patch_unsafe(doc: &mut Value, patch: &[PatchOperation]) -> Result<(), PatchError> {
487 apply_patches(doc, patch, None)
488}
489
490fn undo_patches(doc: &mut Value, undo_patches: &[PatchOperation]) -> Result<(), PatchError> {
493 for (operation, patch) in undo_patches.iter().enumerate().rev() {
494 match patch {
495 PatchOperation::Add(op) => {
496 add(doc, &op.path, op.value.clone())
497 .map_err(|e| translate_error(e, operation, &op.path))?;
498 }
499 PatchOperation::Remove(op) => {
500 remove(doc, &op.path, true).map_err(|e| translate_error(e, operation, &op.path))?;
501 }
502 PatchOperation::Replace(op) => {
503 replace(doc, &op.path, op.value.clone())
504 .map_err(|e| translate_error(e, operation, &op.path))?;
505 }
506 PatchOperation::Move(op) => {
507 mov(doc, &op.from, &op.path, true)
508 .map_err(|e| translate_error(e, operation, &op.path))?;
509 }
510 PatchOperation::Copy(op) => {
511 copy(doc, &op.from, &op.path)
512 .map_err(|e| translate_error(e, operation, &op.path))?;
513 }
514 _ => unreachable!(),
515 }
516 }
517
518 Ok(())
519}
520
521fn apply_patches(
525 doc: &mut Value,
526 patches: &[PatchOperation],
527 undo_stack: Option<&mut Vec<PatchOperation>>,
528) -> Result<(), PatchError> {
529 for (operation, patch) in patches.iter().enumerate() {
530 match patch {
531 PatchOperation::Add(ref op) => {
532 let prev = add(doc, &op.path, op.value.clone())
533 .map_err(|e| translate_error(e, operation, &op.path))?;
534 if let Some(&mut ref mut undo_stack) = undo_stack {
535 undo_stack.push(match prev {
536 None => PatchOperation::Remove(RemoveOperation {
537 path: op.path.clone(),
538 }),
539 Some(v) => PatchOperation::Add(AddOperation {
540 path: op.path.clone(),
541 value: v,
542 }),
543 })
544 }
545 }
546 PatchOperation::Remove(ref op) => {
547 let prev = remove(doc, &op.path, false)
548 .map_err(|e| translate_error(e, operation, &op.path))?;
549 if let Some(&mut ref mut undo_stack) = undo_stack {
550 undo_stack.push(PatchOperation::Add(AddOperation {
551 path: op.path.clone(),
552 value: prev,
553 }))
554 }
555 }
556 PatchOperation::Replace(ref op) => {
557 let prev = replace(doc, &op.path, op.value.clone())
558 .map_err(|e| translate_error(e, operation, &op.path))?;
559 if let Some(&mut ref mut undo_stack) = undo_stack {
560 undo_stack.push(PatchOperation::Replace(ReplaceOperation {
561 path: op.path.clone(),
562 value: prev,
563 }))
564 }
565 }
566 PatchOperation::Move(ref op) => {
567 let prev = mov(doc, &op.from, &op.path, false)
568 .map_err(|e| translate_error(e, operation, &op.path))?;
569 if let Some(&mut ref mut undo_stack) = undo_stack {
570 if let Some(prev) = prev {
571 undo_stack.push(PatchOperation::Add(AddOperation {
572 path: op.path.clone(),
573 value: prev,
574 }));
575 }
576 undo_stack.push(PatchOperation::Move(MoveOperation {
577 from: op.path.clone(),
578 path: op.from.clone(),
579 }));
580 }
581 }
582 PatchOperation::Copy(ref op) => {
583 let prev = copy(doc, &op.from, &op.path)
584 .map_err(|e| translate_error(e, operation, &op.path))?;
585 if let Some(&mut ref mut undo_stack) = undo_stack {
586 undo_stack.push(match prev {
587 None => PatchOperation::Remove(RemoveOperation {
588 path: op.path.clone(),
589 }),
590 Some(v) => PatchOperation::Add(AddOperation {
591 path: op.path.clone(),
592 value: v,
593 }),
594 })
595 }
596 }
597 PatchOperation::Test(ref op) => {
598 test(doc, &op.path, &op.value)
599 .map_err(|e| translate_error(e, operation, &op.path))?;
600 }
601 }
602 }
603
604 Ok(())
605}
606
607pub fn merge(doc: &mut Value, patch: &Value) {
651 if !patch.is_object() {
652 *doc = patch.clone();
653 return;
654 }
655
656 if !doc.is_object() {
657 *doc = Value::Object(Map::new());
658 }
659 let map = doc.as_object_mut().unwrap();
660 for (key, value) in patch.as_object().unwrap() {
661 if value.is_null() {
662 map.remove(key.as_str());
663 } else {
664 merge(map.entry(key.as_str()).or_insert(Value::Null), value);
665 }
666 }
667}