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 = "schemars", derive(schemars::JsonSchema))]
133#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
134pub struct Patch(pub Vec<PatchOperation>);
135
136impl_display!(Patch);
137
138impl std::ops::Deref for Patch {
139 type Target = [PatchOperation];
140
141 fn deref(&self) -> &[PatchOperation] {
142 &self.0
143 }
144}
145
146#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
148#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
149#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
150pub struct AddOperation {
151 #[cfg_attr(feature = "schemars", schemars(schema_with = "String::json_schema"))]
154 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
155 pub path: PointerBuf,
156 pub value: Value,
158}
159
160impl_display!(AddOperation);
161
162#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
164#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
165#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
166pub struct RemoveOperation {
167 #[cfg_attr(feature = "schemars", schemars(schema_with = "String::json_schema"))]
170 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
171 pub path: PointerBuf,
172}
173
174impl_display!(RemoveOperation);
175
176#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
178#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
179#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
180pub struct ReplaceOperation {
181 #[cfg_attr(feature = "schemars", schemars(schema_with = "String::json_schema"))]
184 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
185 pub path: PointerBuf,
186 pub value: Value,
188}
189
190impl_display!(ReplaceOperation);
191
192#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
194#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
195#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
196pub struct MoveOperation {
197 #[cfg_attr(feature = "schemars", schemars(schema_with = "String::json_schema"))]
200 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
201 pub from: PointerBuf,
202 #[cfg_attr(feature = "schemars", schemars(schema_with = "String::json_schema"))]
205 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
206 pub path: PointerBuf,
207}
208
209impl_display!(MoveOperation);
210
211#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
213#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
214#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
215pub struct CopyOperation {
216 #[cfg_attr(feature = "schemars", schemars(schema_with = "String::json_schema"))]
219 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
220 pub from: PointerBuf,
221 #[cfg_attr(feature = "schemars", schemars(schema_with = "String::json_schema"))]
224 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
225 pub path: PointerBuf,
226}
227
228impl_display!(CopyOperation);
229
230#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
232#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
233#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
234pub struct TestOperation {
235 #[cfg_attr(feature = "schemars", schemars(schema_with = "String::json_schema"))]
238 #[cfg_attr(feature = "utoipa", schema(value_type = String))]
239 pub path: PointerBuf,
240 pub value: Value,
242}
243
244impl_display!(TestOperation);
245
246#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
248#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
249#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
250#[serde(tag = "op")]
251#[serde(rename_all = "lowercase")]
252pub enum PatchOperation {
253 Add(AddOperation),
255 Remove(RemoveOperation),
257 Replace(ReplaceOperation),
259 Move(MoveOperation),
261 Copy(CopyOperation),
263 Test(TestOperation),
265}
266
267impl_display!(PatchOperation);
268
269impl PatchOperation {
270 pub fn path(&self) -> &Pointer {
272 match self {
273 Self::Add(op) => &op.path,
274 Self::Remove(op) => &op.path,
275 Self::Replace(op) => &op.path,
276 Self::Move(op) => &op.path,
277 Self::Copy(op) => &op.path,
278 Self::Test(op) => &op.path,
279 }
280 }
281}
282
283impl Default for PatchOperation {
284 fn default() -> Self {
285 PatchOperation::Test(TestOperation::default())
286 }
287}
288
289#[derive(Debug, Error)]
291#[non_exhaustive]
292pub enum PatchErrorKind {
293 #[error("value did not match")]
295 TestFailed,
296 #[error("\"from\" path is invalid")]
298 InvalidFromPointer,
299 #[error("path is invalid")]
301 InvalidPointer,
302 #[error("cannot move the value inside itself")]
304 CannotMoveInsideItself,
305}
306
307impl From<jsonptr::index::ParseIndexError> for PatchErrorKind {
308 fn from(_: jsonptr::index::ParseIndexError) -> Self {
309 Self::InvalidPointer
310 }
311}
312
313impl From<jsonptr::index::OutOfBoundsError> for PatchErrorKind {
314 fn from(_: jsonptr::index::OutOfBoundsError) -> Self {
315 Self::InvalidPointer
316 }
317}
318
319#[derive(Debug, Error)]
321#[error("operation '/{operation}' failed at path '{path}': {kind}")]
322#[non_exhaustive]
323pub struct PatchError {
324 pub operation: usize,
326 pub path: PointerBuf,
328 pub kind: PatchErrorKind,
330}
331
332fn translate_error(kind: PatchErrorKind, operation: usize, path: &Pointer) -> PatchError {
333 PatchError {
334 operation,
335 path: path.to_owned(),
336 kind,
337 }
338}
339
340fn add(doc: &mut Value, path: &Pointer, value: Value) -> Result<Option<Value>, PatchErrorKind> {
341 let Some((parent, last)) = path.split_back() else {
342 return Ok(Some(std::mem::replace(doc, value)));
344 };
345
346 let mut parent = doc
347 .pointer_mut(parent.as_str())
348 .ok_or(PatchErrorKind::InvalidPointer)?;
349
350 match &mut parent {
351 Value::Object(obj) => Ok(obj.insert(last.decoded().into_owned(), value)),
352 Value::Array(arr) => {
353 let idx = last.to_index()?.for_len_incl(arr.len())?;
354 arr.insert(idx, value);
355 Ok(None)
356 }
357 _ => Err(PatchErrorKind::InvalidPointer),
358 }
359}
360
361fn remove(doc: &mut Value, path: &Pointer, allow_last: bool) -> Result<Value, PatchErrorKind> {
362 let Some((parent, last)) = path.split_back() else {
363 return Err(PatchErrorKind::InvalidPointer);
364 };
365 let mut parent = doc
366 .pointer_mut(parent.as_str())
367 .ok_or(PatchErrorKind::InvalidPointer)?;
368
369 match &mut parent {
370 Value::Object(obj) => match obj.remove(last.decoded().as_ref()) {
371 None => Err(PatchErrorKind::InvalidPointer),
372 Some(val) => Ok(val),
373 },
374 Value::Array(arr) if allow_last && matches!(last.to_index(), Ok(Index::Next)) => {
376 Ok(arr.pop().unwrap())
377 }
378 Value::Array(arr) => {
379 let idx = last.to_index()?.for_len(arr.len())?;
380 Ok(arr.remove(idx))
381 }
382 _ => Err(PatchErrorKind::InvalidPointer),
383 }
384}
385
386fn replace(doc: &mut Value, path: &Pointer, value: Value) -> Result<Value, PatchErrorKind> {
387 let target = doc
388 .pointer_mut(path.as_str())
389 .ok_or(PatchErrorKind::InvalidPointer)?;
390 Ok(std::mem::replace(target, value))
391}
392
393fn mov(
394 doc: &mut Value,
395 from: &Pointer,
396 path: &Pointer,
397 allow_last: bool,
398) -> Result<Option<Value>, PatchErrorKind> {
399 if path.starts_with(from) && path.len() != from.len() {
401 return Err(PatchErrorKind::CannotMoveInsideItself);
402 }
403 let val = remove(doc, from, allow_last).map_err(|err| match err {
404 PatchErrorKind::InvalidPointer => PatchErrorKind::InvalidFromPointer,
405 err => err,
406 })?;
407 add(doc, path, val)
408}
409
410fn copy(doc: &mut Value, from: &Pointer, path: &Pointer) -> Result<Option<Value>, PatchErrorKind> {
411 let source = doc
412 .pointer(from.as_str())
413 .ok_or(PatchErrorKind::InvalidFromPointer)?
414 .clone();
415 add(doc, path, source)
416}
417
418fn test(doc: &Value, path: &Pointer, expected: &Value) -> Result<(), PatchErrorKind> {
419 let target = doc
420 .pointer(path.as_str())
421 .ok_or(PatchErrorKind::InvalidPointer)?;
422 if *target == *expected {
423 Ok(())
424 } else {
425 Err(PatchErrorKind::TestFailed)
426 }
427}
428
429pub fn patch(doc: &mut Value, patch: &[PatchOperation]) -> Result<(), PatchError> {
461 let mut undo_stack = Vec::with_capacity(patch.len());
462 if let Err(e) = apply_patches(doc, patch, Some(&mut undo_stack)) {
463 if let Err(e) = undo_patches(doc, &undo_stack) {
464 unreachable!("unable to undo applied patches: {e}")
465 }
466 return Err(e);
467 }
468 Ok(())
469}
470
471pub fn patch_unsafe(doc: &mut Value, patch: &[PatchOperation]) -> Result<(), PatchError> {
503 apply_patches(doc, patch, None)
504}
505
506fn undo_patches(doc: &mut Value, undo_patches: &[PatchOperation]) -> Result<(), PatchError> {
509 for (operation, patch) in undo_patches.iter().enumerate().rev() {
510 match patch {
511 PatchOperation::Add(op) => {
512 add(doc, &op.path, op.value.clone())
513 .map_err(|e| translate_error(e, operation, &op.path))?;
514 }
515 PatchOperation::Remove(op) => {
516 remove(doc, &op.path, true).map_err(|e| translate_error(e, operation, &op.path))?;
517 }
518 PatchOperation::Replace(op) => {
519 replace(doc, &op.path, op.value.clone())
520 .map_err(|e| translate_error(e, operation, &op.path))?;
521 }
522 PatchOperation::Move(op) => {
523 mov(doc, &op.from, &op.path, true)
524 .map_err(|e| translate_error(e, operation, &op.path))?;
525 }
526 PatchOperation::Copy(op) => {
527 copy(doc, &op.from, &op.path)
528 .map_err(|e| translate_error(e, operation, &op.path))?;
529 }
530 _ => unreachable!(),
531 }
532 }
533
534 Ok(())
535}
536
537fn apply_patches(
541 doc: &mut Value,
542 patches: &[PatchOperation],
543 undo_stack: Option<&mut Vec<PatchOperation>>,
544) -> Result<(), PatchError> {
545 for (operation, patch) in patches.iter().enumerate() {
546 match patch {
547 PatchOperation::Add(ref op) => {
548 let prev = add(doc, &op.path, op.value.clone())
549 .map_err(|e| translate_error(e, operation, &op.path))?;
550 if let Some(&mut ref mut undo_stack) = undo_stack {
551 undo_stack.push(match prev {
552 None => PatchOperation::Remove(RemoveOperation {
553 path: op.path.clone(),
554 }),
555 Some(v) => PatchOperation::Add(AddOperation {
556 path: op.path.clone(),
557 value: v,
558 }),
559 })
560 }
561 }
562 PatchOperation::Remove(ref op) => {
563 let prev = remove(doc, &op.path, false)
564 .map_err(|e| translate_error(e, operation, &op.path))?;
565 if let Some(&mut ref mut undo_stack) = undo_stack {
566 undo_stack.push(PatchOperation::Add(AddOperation {
567 path: op.path.clone(),
568 value: prev,
569 }))
570 }
571 }
572 PatchOperation::Replace(ref op) => {
573 let prev = replace(doc, &op.path, op.value.clone())
574 .map_err(|e| translate_error(e, operation, &op.path))?;
575 if let Some(&mut ref mut undo_stack) = undo_stack {
576 undo_stack.push(PatchOperation::Replace(ReplaceOperation {
577 path: op.path.clone(),
578 value: prev,
579 }))
580 }
581 }
582 PatchOperation::Move(ref op) => {
583 let prev = mov(doc, &op.from, &op.path, false)
584 .map_err(|e| translate_error(e, operation, &op.path))?;
585 if let Some(&mut ref mut undo_stack) = undo_stack {
586 if let Some(prev) = prev {
587 undo_stack.push(PatchOperation::Add(AddOperation {
588 path: op.path.clone(),
589 value: prev,
590 }));
591 }
592 undo_stack.push(PatchOperation::Move(MoveOperation {
593 from: op.path.clone(),
594 path: op.from.clone(),
595 }));
596 }
597 }
598 PatchOperation::Copy(ref op) => {
599 let prev = copy(doc, &op.from, &op.path)
600 .map_err(|e| translate_error(e, operation, &op.path))?;
601 if let Some(&mut ref mut undo_stack) = undo_stack {
602 undo_stack.push(match prev {
603 None => PatchOperation::Remove(RemoveOperation {
604 path: op.path.clone(),
605 }),
606 Some(v) => PatchOperation::Add(AddOperation {
607 path: op.path.clone(),
608 value: v,
609 }),
610 })
611 }
612 }
613 PatchOperation::Test(ref op) => {
614 test(doc, &op.path, &op.value)
615 .map_err(|e| translate_error(e, operation, &op.path))?;
616 }
617 }
618 }
619
620 Ok(())
621}
622
623pub fn merge(doc: &mut Value, patch: &Value) {
667 if !patch.is_object() {
668 *doc = patch.clone();
669 return;
670 }
671
672 if !doc.is_object() {
673 *doc = Value::Object(Map::new());
674 }
675 let map = doc.as_object_mut().unwrap();
676 for (key, value) in patch.as_object().unwrap() {
677 if value.is_null() {
678 map.remove(key.as_str());
679 } else {
680 merge(map.entry(key.as_str()).or_insert(Value::Null), value);
681 }
682 }
683}