1use std::cell::Cell;
8
9use serde_json::Value;
10
11use crate::errors;
12use crate::spec::field::FieldMeta;
13use crate::spec::scalar;
14use crate::spec::{JsonMap, XyzField};
15
16const MAX_DECODE_DEPTH: usize = 20;
19
20thread_local! {
21 static DECODE_DEPTH: Cell<usize> = const { Cell::new(0) };
22}
23
24pub struct DepthGuard;
25
26impl Drop for DepthGuard {
27 fn drop(&mut self) {
28 DECODE_DEPTH.with(|d| d.set(d.get() - 1));
29 }
30}
31
32pub fn object_arg(v: &Value) -> errors::Result<(&JsonMap, DepthGuard)> {
35 let map = v.as_object().ok_or_else(|| {
36 errors::Error::new(
37 errors::Kind::InvalidInput,
38 format!("expect object, got {}", scalar::type_name(v)),
39 )
40 })?;
41 DECODE_DEPTH.with(|d| {
42 let cur = d.get();
43 if cur >= MAX_DECODE_DEPTH {
44 return Err(errors::Error::new(
45 errors::Kind::InvalidInput,
46 format!(
47 "argument struct nesting exceeds {MAX_DECODE_DEPTH} levels (recursive type?)"
48 ),
49 ));
50 }
51 d.set(cur + 1);
52 Ok(())
53 })?;
54 Ok((map, DepthGuard))
55}
56
57pub fn expect_meta_len(meta: &[FieldMeta], expect: usize) -> errors::Result<()> {
60 if meta.len() != expect {
61 return Err(errors::Error::new(
62 errors::Kind::Internal,
63 format!("internal: field meta len {} != {}", meta.len(), expect),
64 ));
65 }
66 Ok(())
67}
68
69fn field_with_key<T: XyzField>(fi: &FieldMeta, map: &JsonMap, key: &str) -> errors::Result<T> {
70 match map.get(key) {
71 Some(v) if !v.is_null() => {
72 let t = T::xyz_from_value(v).map_err(|e| field_err(fi, e))?;
73 enum_check(fi, &t)?;
74 Ok(t)
75 }
76 _ => match &fi.default {
77 Some(d) => T::xyz_from_value(d).map_err(|e| {
78 errors::Error::new(
79 e.kind(),
80 format!("field {:?}: invalid default: {e}", fi.json_name),
81 )
82 }),
83 None if fi.required => Err(errors::Error::new(
84 errors::Kind::InvalidInput,
85 format!("field {:?} is required", fi.json_name),
86 )),
87 None if !T::xyz_has_zero() => Err(errors::Error::new(
88 errors::Kind::InvalidInput,
89 format!(
90 "field {:?} has no absent form (unions need a value; use Option<…> when optional)",
91 fi.json_name
92 ),
93 )),
94 None => Ok(T::xyz_zero()),
95 },
96 }
97}
98
99pub fn field<T: XyzField>(fi: &FieldMeta, map: &JsonMap) -> errors::Result<T> {
101 field_with_key(fi, map, fi.json_name.as_str())
102}
103
104pub fn field_skip<T: XyzField>(fi: &FieldMeta, map: &JsonMap) -> errors::Result<T> {
106 field_with_key(fi, map, fi.name.as_str())
107}
108
109pub fn field_opt<T: XyzField>(fi: &FieldMeta, map: &JsonMap) -> errors::Result<Option<T>> {
111 match map.get(fi.json_name.as_str()) {
112 Some(v) if !v.is_null() => {
113 let t = T::xyz_from_value(v).map_err(|e| field_err(fi, e))?;
114 enum_check(fi, &t)?;
115 Ok(Some(t))
116 }
117 _ => match &fi.default {
118 Some(d) => Ok(Some(T::xyz_from_value(d).map_err(|e| {
119 errors::Error::new(
120 e.kind(),
121 format!("field {:?}: invalid default: {e}", fi.json_name),
122 )
123 })?)),
124 None if fi.required => Err(errors::Error::new(
125 errors::Kind::InvalidInput,
126 format!("field {:?} is required", fi.json_name),
127 )),
128 None => Ok(None),
129 },
130 }
131}
132
133pub fn field_vec<T: XyzField>(fi: &FieldMeta, map: &JsonMap) -> errors::Result<Vec<T>> {
135 match map.get(fi.json_name.as_str()) {
136 Some(v) if !v.is_null() => {
137 let arr = v.as_array().ok_or_else(|| {
138 errors::Error::new(
139 errors::Kind::InvalidInput,
140 format!(
141 "field {:?}: expect array, got {}",
142 fi.json_name,
143 scalar::type_name(v)
144 ),
145 )
146 })?;
147 arr.iter()
148 .enumerate()
149 .map(|(i, it)| {
150 if it.is_null() {
151 if !T::xyz_has_zero() {
152 return Err(errors::Error::new(
153 errors::Kind::InvalidInput,
154 format!(
155 "field {:?}: index {i}: null element has no absent form (union)",
156 fi.json_name
157 ),
158 ));
159 }
160 return Ok(T::xyz_zero());
161 }
162 T::xyz_from_value(it).map_err(|e| {
163 errors::Error::new(
164 e.kind(),
165 format!("field {:?}: index {i}: {e}", fi.json_name),
166 )
167 })
168 })
169 .collect()
170 }
171 _ => match &fi.default {
172 Some(d) => match d.as_array() {
173 Some(items) => items
174 .iter()
175 .map(|it| T::xyz_from_value(it))
176 .collect::<errors::Result<Vec<_>>>()
177 .map_err(|e| {
178 errors::Error::new(
179 e.kind(),
180 format!("field {:?}: invalid default: {e}", fi.json_name),
181 )
182 }),
183 None => Err(errors::Error::new(
184 errors::Kind::InvalidInput,
185 format!("field {:?}: invalid default", fi.json_name),
186 )),
187 },
188 None if fi.required => Err(errors::Error::new(
189 errors::Kind::InvalidInput,
190 format!("field {:?} is required", fi.json_name),
191 )),
192 None => Ok(Vec::new()),
193 },
194 }
195}
196
197pub fn field_bytes(fi: &FieldMeta, map: &JsonMap) -> errors::Result<Vec<u8>> {
199 field::<Vec<u8>>(fi, map)
200}
201
202pub fn field_skip_vec<T: XyzField>(fi: &FieldMeta, map: &JsonMap) -> errors::Result<Vec<T>> {
204 match map.get(fi.name.as_str()) {
205 Some(v) if !v.is_null() => match v.as_array() {
206 Some(arr) => arr
207 .iter()
208 .enumerate()
209 .map(|(i, it)| {
210 if it.is_null() {
211 return Ok(T::xyz_zero());
212 }
213 T::xyz_from_value(it).map_err(|e| {
214 errors::Error::new(e.kind(), format!("field {:?}: index {i}: {e}", fi.name))
215 })
216 })
217 .collect(),
218 None => Err(errors::Error::new(
219 errors::Kind::InvalidInput,
220 format!(
221 "field {:?}: expect array, got {}",
222 fi.name,
223 scalar::type_name(v)
224 ),
225 )),
226 },
227 _ => match &fi.default {
228 Some(d) => match d.as_array() {
229 Some(items) => items.iter().map(T::xyz_from_value).collect(),
230 None => Err(errors::Error::new(
231 errors::Kind::InvalidInput,
232 format!("field {:?}: invalid default", fi.name),
233 )),
234 },
235 None if fi.required => Err(errors::Error::new(
236 errors::Kind::InvalidInput,
237 format!("field {:?} is required", fi.name),
238 )),
239 None => Ok(Vec::new()),
240 },
241 }
242}
243
244pub fn type_check_vec<T: XyzField>(fi: &FieldMeta, v: &Value) -> errors::Result<()> {
246 match v {
247 Value::Null => Ok(()),
248 Value::Array(items) => {
249 for it in items {
250 if it.is_null() {
251 continue;
252 }
253 T::xyz_from_value(it).map_err(|e| {
254 errors::Error::new(
255 e.kind(),
256 format!("field {:?}: bad default element {it}: {e}", fi.json_name),
257 )
258 })?;
259 }
260 Ok(())
261 }
262 Value::String(s) if s.is_empty() => Ok(()),
263 other => Err(errors::Error::new(
264 errors::Kind::InvalidInput,
265 format!(
266 "field {:?}: bad default {other}: expect array",
267 fi.json_name
268 ),
269 )),
270 }
271}
272
273pub fn type_check_opt<T: XyzField>(fi: &FieldMeta, v: &Value) -> errors::Result<()> {
275 if v.is_null() {
276 return Ok(());
277 }
278 T::xyz_from_value(v).map(|_| ()).map_err(|e| {
279 errors::Error::new(
280 e.kind(),
281 format!("field {:?}: bad default {v}: {e}", fi.json_name),
282 )
283 })
284}
285
286fn field_err(fi: &FieldMeta, e: errors::Error) -> errors::Error {
287 errors::Error::new(e.kind(), format!("field {:?}: {e}", fi.json_name))
288}
289
290fn enum_check<T: XyzField>(fi: &FieldMeta, t: &T) -> errors::Result<()> {
291 if fi.enum_values.is_empty() {
292 return Ok(());
293 }
294 let fmt = t.xyz_fmt();
296 let hit = fi
297 .enum_values
298 .iter()
299 .filter_map(|e| T::xyz_from_value(e).ok())
300 .any(|cand| cand.xyz_fmt() == fmt);
301 if !hit {
302 return Err(errors::Error::new(
303 errors::Kind::InvalidInput,
304 format!(
305 "field {:?}: value must be one of [{}]",
306 fi.json_name,
307 fi.enum_values
308 .iter()
309 .map(|v| match v {
310 Value::String(s) => s.clone(),
311 other => other.to_string(),
312 })
313 .collect::<Vec<_>>()
314 .join(" ")
315 ),
316 ));
317 }
318 Ok(())
319}
320
321pub fn type_check_of<T: XyzField>(fi: &FieldMeta, v: &Value) -> errors::Result<()> {
324 T::xyz_from_value(v).map(|_| ()).map_err(|e| {
325 errors::Error::new(
326 e.kind(),
327 format!("field {:?}: bad default {v}: {e}", fi.json_name),
328 )
329 })
330}