Skip to main content

xyz_rust/spec/
decode.rs

1// decode 是「传输 map → 强类型值」的运行时入口集合,由 #[derive(XyzArgs)]
2// 生成的 xyz_decode 按字段形状调用(__field_scalar/__field_opt/__field_vec/
3// __field_bytes)。语义与 Go 的 decodeTree + decodeValue 对齐:
4// 缺席 → 全局默认 → required 报错 → 零值;null 视同缺席;枚举在转换后
5// 按类型等值检查。
6
7use 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
16/// 递归类型护栏:嵌套 struct 的对象解码每层 +1(Go maxAnalyzeDepth 的
17/// 运行时对应物;静态自引用在宏期直接 compile_error)。
18const 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
32/// 宏生成的 XyzArgs::xyz_from_value(对象分支)先过这里:给出对象 map
33/// 并压深。返回的 guard 活在调用栈上,覆盖整段递归解码。
34pub 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
57/// 宏生成的 xyz_decode 开头:元数据长度与字段数一致性(防御宏/运行时
58/// 树漂移;debug 断言 + 发布内错误)。
59pub 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
99/// 标量/命名标量/嵌套 struct 字段(按 json 名绑定)。
100pub fn field<T: XyzField>(fi: &FieldMeta, map: &JsonMap) -> errors::Result<T> {
101    field_with_key(fi, map, fi.json_name.as_str())
102}
103
104/// json:"-" 注入字段(env/header 专用):按 Rust 字段名投递。
105pub fn field_skip<T: XyzField>(fi: &FieldMeta, map: &JsonMap) -> errors::Result<T> {
106    field_with_key(fi, map, fi.name.as_str())
107}
108
109/// Option<T> 字段(Go 指针):null 视同缺席;有值即 Some。
110pub 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
133/// Vec<T> 字段:数组逐元素转换;元素 null 落零值(Go decodeValue 同)。
134pub 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
197/// Vec<u8> 字段(Go []byte:字符串或字节数组直接进)。
198pub fn field_bytes(fi: &FieldMeta, map: &JsonMap) -> errors::Result<Vec<u8>> {
199    field::<Vec<u8>>(fi, map)
200}
201
202/// skip 字段上的 Vec<T>(json:"-" 注入:env 值形如数组时仍走数组语义)。
203pub 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
244/// 注册期验证 Vec<T> 形状的 hint 默认值(元素逐个可转换)。
245pub 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
273/// 注册期验证 Option<T> 形状的 hint 默认值。
274pub 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    // 值等价经 fmt 形态比较(枚举值与目标值同源转换,位级一致)。
295    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
321/// 宏生成的 xyz_type_check 逐索引派发到这里:注册期验证 hint 默认值可被
322/// 目标字段转换(Go normalizeHintDefault 的对应物)。
323pub 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}