json_predicate/predicate/first_order/
start.rs1use derive_builder::Builder;
2use serde_json::Value;
3use std::marker::PhantomData;
4
5use serde::de::{self, Deserialize, Deserializer, MapAccess, Visitor};
6use serde::{ser::SerializeStruct, Serialize};
7
8use crate::json_path::JSONPath;
9use crate::predicate::context::PredicateContext;
10use crate::predicate::error::PredicateError;
11use crate::predicate::PredicateImpl;
12
13use super::FirstOrder;
14
15#[derive(Debug, Clone, PartialEq, Eq, Builder)]
20#[builder(pattern = "owned", setter(into, strip_option))]
21pub struct Start {
22 pub path: Option<JSONPath>,
25 #[builder(default)]
26 pub ignore_case: bool,
27 pub value: serde_json::Value,
28}
29
30impl Serialize for Start {
31 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
32 where
33 S: serde::Serializer,
34 {
35 let mut state = serializer.serialize_struct("Start", 3)?;
36 if self.ignore_case {
37 state.serialize_field("op", "start-")?;
38 } else {
39 state.serialize_field("op", "start")?;
40 }
41 state.serialize_field("path", &self.path)?;
42 state.serialize_field("value", &self.value)?;
43 state.end()
44 }
45}
46
47impl<'de> Deserialize<'de> for Start {
48 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
49 where
50 D: Deserializer<'de>,
51 {
52 #[allow(non_camel_case_types)]
53 enum Field {
54 op,
55 path,
56 value,
57 __ignore,
58 }
59 struct FieldVisitor;
60
61 impl<'de> Visitor<'de> for FieldVisitor {
62 type Value = Field;
63 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
64 formatter.write_str("field identifier")
65 }
66
67 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
68 where
69 E: de::Error,
70 {
71 match value {
72 "op" => Ok(Field::op),
73 "path" => Ok(Field::path),
74 "value" => Ok(Field::value),
75 _ => Ok(Field::__ignore),
76 }
77 }
78 }
79
80 impl<'de> Deserialize<'de> for Field {
81 #[inline]
82 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
83 where
84 D: Deserializer<'de>,
85 {
86 Deserializer::deserialize_identifier(deserializer, FieldVisitor)
87 }
88 }
89
90 struct VisitorStart<'de> {
91 marker: PhantomData<Start>,
92 lifetime: PhantomData<&'de ()>,
93 }
94
95 impl<'de> Visitor<'de> for VisitorStart<'de> {
96 type Value = Start;
97 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
98 formatter.write_str("Start")
99 }
100
101 #[inline]
102 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
103 where
104 A: MapAccess<'de>,
105 {
106 let mut path: Option<Option<JSONPath>> = None;
107 let mut value: Option<serde_json::Value> = None;
108 let mut op: Option<String> = None;
109
110 while let Some(key) = MapAccess::next_key::<Field>(&mut map)? {
111 match key {
112 Field::op => {
113 if op.is_some() {
114 return Err(serde::de::Error::duplicate_field("op"));
115 }
116 op = Some(MapAccess::next_value::<String>(&mut map)?);
117 }
118 Field::path => {
119 if path.is_some() {
120 return Err(serde::de::Error::duplicate_field("path"));
121 }
122 path = Some(MapAccess::next_value::<Option<JSONPath>>(&mut map)?);
123 }
124 Field::value => {
125 if value.is_some() {
126 return Err(serde::de::Error::duplicate_field("value"));
127 }
128 value = Some(MapAccess::next_value::<serde_json::Value>(&mut map)?);
129 }
130 Field::__ignore => {}
131 }
132 }
133
134 let path = path.ok_or(serde::de::Error::missing_field("path"))?;
135 let value = value.ok_or(serde::de::Error::missing_field("value"))?;
136 let op = op.ok_or(serde::de::Error::missing_field("op"))?;
137
138 let ignore_case = match op.as_str() {
139 "start" => false,
140 "start-" => true,
141 _ => {
142 return Err(serde::de::Error::custom(
143 "`op` should be either `start` or `start-`",
144 ));
145 }
146 };
147
148 Ok(Start {
149 path,
150 ignore_case,
151 value,
152 })
153 }
154 }
155
156 const FIELDS: &[&str] = &["path", "op", "value"];
157 Deserializer::deserialize_struct(
158 deserializer,
159 "Start",
160 FIELDS,
161 VisitorStart {
162 marker: PhantomData::<Start>,
163 lifetime: PhantomData,
164 },
165 )
166 }
167}
168
169impl From<Start> for FirstOrder {
170 fn from(value: Start) -> Self {
171 FirstOrder::Start(value)
172 }
173}
174
175impl PredicateImpl for Start {
176 fn evaluate(&self, data: &Value, ctx: PredicateContext) -> Result<bool, PredicateError> {
177 let path = ctx.final_path(&self.path).unwrap_or(JSONPath::empty());
178 let ptr = path.take();
179
180 let value = &self.value;
181 let context_value = ptr.get(data)?;
182
183 match (context_value, value) {
184 (Value::String(context), Value::String(value)) => {
185 if self.ignore_case {
186 Ok(context.to_lowercase().starts_with(&value.to_lowercase()))
187 } else {
188 Ok(context.starts_with(value))
189 }
190 }
191 _ => Ok(false),
192 }
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use serde::Deserialize;
199
200 use crate::{json_path::JSONPath, predicate::first_order::start::Start};
201
202 #[test]
203 fn snapshot_test() {
204 let start_expect = serde_json::json!({
205 "op": "start",
206 "path": "/a/b",
207 "value": " is a "
208 });
209
210 let start = Start {
211 path: Some(JSONPath::new("/a/b").unwrap()),
212 ignore_case: false,
213 value: serde_json::Value::String(" is a ".to_string()),
214 };
215
216 assert_eq!(serde_json::to_value(start).unwrap(), start_expect);
217 }
218
219 #[test]
220 fn deser_test() {
221 let start_expect = serde_json::json!({
222 "op": "start",
223 "path": "/a/b",
224 "value": " is a "
225 });
226
227 let start = Start {
228 path: Some(JSONPath::new("/a/b").unwrap()),
229 ignore_case: false,
230 value: serde_json::Value::String(" is a ".to_string()),
231 };
232
233 let deser = Start::deserialize(start_expect).unwrap();
234
235 assert_eq!(start, deser);
236 }
237}