1use std::cmp::Ordering;
2use std::fmt;
3
4use super::patch::{AddOperation, PatchOperation, RemoveOperation, ReplaceOperation};
5use super::path::Path;
6use super::value::Value;
7
8use crate::serde::{ser::SerializeMap, Serialize, Serializer};
9
10#[derive(Debug, PartialEq, Eq, Clone)]
12pub enum Operation {
13 Create { path: Path, value: Value },
14 Update { path: Path, value: Value },
15 Delete { path: Path },
16}
17
18impl Serialize for Operation {
19 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
20 where
21 S: Serializer,
22 {
23 use Operation::*;
24 match self {
25 Create { path, value } => {
26 let mut map = serializer.serialize_map(Some(3))?;
27 map.serialize_entry("op", "create")?;
28 map.serialize_entry("path", path)?;
29 map.serialize_entry("value", value)?;
30 map.end()
31 }
32 Update { path, value } => {
33 let mut map = serializer.serialize_map(Some(3))?;
34 map.serialize_entry("op", "update")?;
35 map.serialize_entry("path", path)?;
36 map.serialize_entry("value", value)?;
37 map.end()
38 }
39 Delete { path } => {
40 let mut map = serializer.serialize_map(Some(2))?;
41 map.serialize_entry("op", "delete")?;
42 map.serialize_entry("path", path)?;
43 map.end()
44 }
45 }
46 }
47}
48
49impl Operation {
50 pub fn path(&self) -> &Path {
52 use Operation::*;
53 match *self {
54 Create { ref path, .. } => path,
55 Update { ref path, .. } => path,
56 Delete { ref path, .. } => path,
57 }
58 }
59}
60
61impl fmt::Display for Operation {
62 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
63 use Operation::*;
64
65 write!(fmt, "{{")?;
66 match *self {
67 Create {
68 ref path,
69 ref value,
70 } => {
71 write!(fmt, "\"op\": \"create\",")?;
72 write!(fmt, "\"path\": {path},")?;
73 write!(fmt, "\"value\": {value}")?;
74 }
75 Update {
76 ref path,
77 ref value,
78 } => {
79 write!(fmt, "\"op\": \"update\",")?;
80 write!(fmt, "\"path\": {path},")?;
81 write!(fmt, "\"value\": {value}")?;
82 }
83 Delete { ref path } => {
84 write!(fmt, "\"op\": \"delete\",")?;
85 write!(fmt, "\"path\": {path}")?;
86 }
87 }
88 write!(fmt, "}}")
89 }
90}
91
92impl From<PatchOperation> for Operation {
93 fn from(op: PatchOperation) -> Self {
94 match op {
95 PatchOperation::Add(AddOperation { path, value }) => Operation::Create {
96 path: Path::new(&path),
97 value,
98 },
99 PatchOperation::Replace(ReplaceOperation { path, value }) => Operation::Update {
100 path: Path::new(&path),
101 value,
102 },
103 PatchOperation::Remove(RemoveOperation { path }) => Operation::Delete {
104 path: Path::new(&path),
105 },
106 _ => unreachable!("unsuppported operation {op}"),
109 }
110 }
111}
112
113impl PartialOrd for Operation {
114 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
115 Some(self.cmp(other))
116 }
117}
118
119impl Ord for Operation {
120 fn cmp(&self, other: &Self) -> Ordering {
121 let thispath = self.path().as_ref();
122 let otherpath = other.path().as_ref();
123
124 thispath
126 .count()
127 .cmp(&otherpath.count())
128 .then(thispath.cmp(otherpath))
129 }
130}
131
132#[derive(PartialEq, PartialOrd, Eq, Ord, Debug, Clone)]
134pub enum OperationMatcher {
135 None,
137 Any,
139 Delete,
142 Create,
145 Update,
148}
149
150impl OperationMatcher {
151 pub fn matches(&self, operation: &Operation) -> bool {
153 use OperationMatcher::*;
154 match *self {
155 None => false,
156 Any => true,
157 Create => matches!(operation, Operation::Create { .. }),
158 Update => matches!(operation, Operation::Update { .. }),
159 Delete => matches!(operation, Operation::Delete { .. }),
160 }
161 }
162
163 pub(crate) fn as_str(&self) -> &'static str {
164 use OperationMatcher::*;
165 match *self {
166 None => "none",
167 Any => "any",
168 Update => "update",
169 Create => "create",
170 Delete => "delete",
171 }
172 }
173}
174
175impl fmt::Display for OperationMatcher {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 self.as_str().fmt(f)
178 }
179}