Skip to main content

swsml_derive/
lib.rs

1// SPDX-License-Identifier: MulanPSL-2.0
2//! `swsml-derive` — SML (SNOWARE Markup Language) 的 derive 宏。
3//!
4//! 提供 [`SmlSerialize`] / [`SmlDeserialize`] 两个过程宏,把自定义结构体 /
5//! 枚举「自然地」映射为 SML 值:
6//!
7//! ```rust
8//! use sml::{SmlDeserialize, SmlSerialize};
9//!
10//! #[derive(SmlSerialize, SmlDeserialize, Debug, PartialEq)]
11//! struct Server {
12//!     host: String,
13//!     #[sml(default)]
14//!     port: i32,
15//!     #[sml(rename = "tls-enabled")]
16//!     tls_enabled: bool,
17//!     #[sml(skip)]
18//!     secret: String,
19//! }
20//!
21//! #[derive(SmlSerialize, SmlDeserialize, Debug, PartialEq)]
22//! enum Status {
23//!     Active,
24//!     #[sml(rename = "stand-by")]
25//!     StandBy,
26//! }
27//! ```
28//!
29//! 映射规则(“自然”形状,与 [`sml::to_sml`] 输出一致):
30//! - 结构体 → 块:字段名即键;`Option` 字段为 `None` 时省略;
31//!   `#[sml(skip)]` 跳过、`#[sml(default)]` 缺失时用 `Default`、
32//!   `#[sml(rename = "...")]` 改名、`#[sml(flatten)]` 并入子块;
33//! - 单元结构体 → 裸词;newtype 结构体 → 透明;tuple 结构体 → 数组;
34//! - 枚举单元变体 → 裸词(如 `status: active`);
35//! - 枚举带数据变体 → 带 `__type` 的块(如 `shape { __type: Circle _value: 3.0 }`)。
36//!
37//! 支持容器级 `#[sml(rename_all = "kebab-case")]` 批量改名。
38
39use proc_macro::TokenStream;
40use proc_macro2::Span;
41use quote::{format_ident, quote};
42use syn::parse_macro_input;
43use syn::{Data, DeriveInput, Fields, Ident, LitStr};
44
45#[proc_macro_derive(SmlSerialize, attributes(sml))]
46pub fn derive_sml_serialize(input: TokenStream) -> TokenStream {
47    let input = parse_macro_input!(input as DeriveInput);
48    expand_serialize(&input)
49        .unwrap_or_else(syn::Error::into_compile_error)
50        .into()
51}
52
53#[proc_macro_derive(SmlDeserialize, attributes(sml))]
54pub fn derive_sml_deserialize(input: TokenStream) -> TokenStream {
55    let input = parse_macro_input!(input as DeriveInput);
56    expand_deserialize(&input)
57        .unwrap_or_else(syn::Error::into_compile_error)
58        .into()
59}
60
61// ---------------------------------------------------------------------------
62// 属性解析
63// ---------------------------------------------------------------------------
64
65#[derive(Default)]
66struct FieldAttrs {
67    rename: Option<String>,
68    skip: bool,
69    default: bool,
70    flatten: bool,
71}
72
73fn parse_field_attrs(attrs: &[syn::Attribute]) -> syn::Result<FieldAttrs> {
74    let mut out = FieldAttrs::default();
75    for attr in attrs {
76        if !attr.path().is_ident("sml") {
77            continue;
78        }
79        attr.parse_nested_meta(|meta| {
80            if meta.path.is_ident("rename") {
81                let lit: LitStr = meta.value()?.parse()?;
82                out.rename = Some(lit.value());
83                Ok(())
84            } else if meta.path.is_ident("skip") {
85                out.skip = true;
86                Ok(())
87            } else if meta.path.is_ident("default") {
88                out.default = true;
89                Ok(())
90            } else if meta.path.is_ident("flatten") {
91                out.flatten = true;
92                Ok(())
93            } else {
94                Err(meta.error(
95                    "未知的 #[sml(...)] 属性;支持 rename / skip / default / flatten",
96                ))
97            }
98        })?;
99    }
100    Ok(out)
101}
102
103fn parse_rename_all(attrs: &[syn::Attribute]) -> syn::Result<Option<String>> {
104    let mut rename_all = None;
105    for attr in attrs {
106        if !attr.path().is_ident("sml") {
107            continue;
108        }
109        attr.parse_nested_meta(|meta| {
110            if meta.path.is_ident("rename_all") {
111                let lit: LitStr = meta.value()?.parse()?;
112                rename_all = Some(lit.value());
113                Ok(())
114            } else {
115                Err(meta.error("容器级只支持 #[sml(rename_all = \"...\")]"))
116            }
117        })?;
118    }
119    Ok(rename_all)
120}
121
122fn is_option(ty: &syn::Type) -> bool {
123    if let syn::Type::Path(p) = ty {
124        if let Some(last) = p.path.segments.last() {
125            return last.ident == "Option";
126        }
127    }
128    false
129}
130
131/// 把 snake_case / camelCase / PascalCase / kebab-case 名称拆成单词
132fn split_words(name: &str) -> Vec<String> {
133    let mut words = Vec::new();
134    let mut cur = String::new();
135    let mut chars = name.chars().peekable();
136    while let Some(c) = chars.next() {
137        if c == '_' || c == '-' {
138            if !cur.is_empty() {
139                words.push(std::mem::take(&mut cur));
140            }
141        } else if c.is_uppercase() {
142            if !cur.is_empty() {
143                let prev_is_upper = cur.chars().last().is_some_and(|p| p.is_uppercase());
144                let next = chars.peek().copied();
145                // 连续大写(如 URLValue)在最后一个大写前断开:URL -> Value
146                if prev_is_upper && next.is_some_and(|n| n.is_lowercase()) {
147                    words.push(std::mem::take(&mut cur));
148                }
149            }
150            cur.push(c.to_ascii_lowercase());
151        } else {
152            cur.push(c);
153        }
154    }
155    if !cur.is_empty() {
156        words.push(cur);
157    }
158    words
159}
160
161fn apply_case(name: &str, case: Option<&str>) -> String {
162    let Some(case) = case else {
163        return name.to_string();
164    };
165    let words = split_words(name);
166    match case {
167        "kebab-case" => words.join("-"),
168        "snake_case" => words.join("_"),
169        "SCREAMING_SNAKE_CASE" => words.iter().map(|w| w.to_uppercase()).collect::<Vec<_>>().join("_"),
170        "lowercase" => words.join("").to_lowercase(),
171        "UPPERCASE" => words.join("").to_uppercase(),
172        "camelCase" => {
173            let mut s = String::new();
174            for (i, w) in words.iter().enumerate() {
175                if i == 0 {
176                    s.push_str(&w.to_lowercase());
177                } else {
178                    let mut c = w.chars();
179                    if let Some(f) = c.next() {
180                        s.push(f.to_ascii_uppercase());
181                        s.push_str(&c.as_str().to_lowercase());
182                    }
183                }
184            }
185            s
186        }
187        "PascalCase" => {
188            let mut s = String::new();
189            for w in &words {
190                let mut c = w.chars();
191                if let Some(f) = c.next() {
192                    s.push(f.to_ascii_uppercase());
193                    s.push_str(&c.as_str().to_lowercase());
194                }
195            }
196            s
197        }
198        _ => name.to_string(),
199    }
200}
201
202fn field_key(attrs: &FieldAttrs, rename_all: Option<&str>, name: &Ident) -> String {
203    if let Some(r) = &attrs.rename {
204        return r.clone();
205    }
206    apply_case(&name.to_string(), rename_all)
207}
208
209// ---------------------------------------------------------------------------
210// SmlSerialize
211// ---------------------------------------------------------------------------
212
213fn expand_serialize(input: &DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
214    let name = &input.ident;
215    let rename_all = parse_rename_all(&input.attrs)?;
216    let mut where_clause: syn::WhereClause = input
217        .generics
218        .where_clause
219        .clone()
220        .unwrap_or_else(|| syn::parse_quote!(where));
221    for tp in input.generics.type_params() {
222        let ident = &tp.ident;
223        where_clause
224            .predicates
225            .push(syn::parse_quote!(#ident: ::sml::SmlSerialize));
226    }
227    let (impl_generics, ty_generics, _) = input.generics.split_for_impl();
228
229    let body = match &input.data {
230        Data::Struct(s) => gen_struct_serialize(s, name, rename_all.as_deref())?,
231        Data::Enum(e) => gen_enum_serialize(e, rename_all.as_deref())?,
232        Data::Union(u) => {
233            return Err(syn::Error::new_spanned(
234                u.union_token,
235                "SmlSerialize 不支持 union 类型",
236            ))
237        }
238    };
239
240    Ok(quote! {
241        impl #impl_generics ::sml::SmlSerialize for #name #ty_generics #where_clause {
242            fn to_sml_value(&self) -> ::sml::Value {
243                #body
244            }
245        }
246    })
247}
248
249fn gen_struct_serialize(
250    s: &syn::DataStruct,
251    name: &Ident,
252    rename_all: Option<&str>,
253) -> syn::Result<proc_macro2::TokenStream> {
254    match &s.fields {
255        Fields::Named(named) => {
256            let mut stmts = Vec::new();
257            for f in &named.named {
258                let attrs = parse_field_attrs(&f.attrs)?;
259                let fid = f.ident.as_ref().unwrap();
260                if attrs.skip {
261                    continue;
262                }
263                let key = field_key(&attrs, rename_all, fid);
264                let key_lit = LitStr::new(&key, Span::call_site());
265                if attrs.flatten {
266                    stmts.push(quote! {
267                        match ::sml::SmlSerialize::to_sml_value(&self.#fid) {
268                            ::sml::Value::Object(__inner) => {
269                                for (__k, __v) in __inner {
270                                    __m.insert(__k, __v);
271                                }
272                            }
273                            __other => {
274                                ::std::panic!(
275                                    "字段 `{}` (flatten) 序列化结果必须是块,实际为 {}",
276                                    #key_lit,
277                                    ::sml::__private::describe_value(&__other)
278                                )
279                            }
280                        }
281                    });
282                    continue;
283                }
284                if is_option(&f.ty) {
285                    stmts.push(quote! {
286                        if let ::core::option::Option::Some(__v) = &self.#fid {
287                            __m.insert(#key_lit.into(), ::sml::SmlSerialize::to_sml_value(__v));
288                        }
289                    });
290                } else {
291                    stmts.push(quote! {
292                        __m.insert(#key_lit.into(), ::sml::SmlSerialize::to_sml_value(&self.#fid));
293                    });
294                }
295            }
296            Ok(quote! {
297                let mut __m = ::std::collections::BTreeMap::new();
298                #(#stmts)*
299                ::sml::Value::Object(__m)
300            })
301        }
302        Fields::Unnamed(unnamed) if unnamed.unnamed.len() == 1 => {
303            // newtype 结构体:透明包装
304            Ok(quote! {
305                ::sml::SmlSerialize::to_sml_value(&self.0)
306            })
307        }
308        Fields::Unnamed(unnamed) => {
309            let idx: Vec<_> = (0..unnamed.unnamed.len()).map(syn::Index::from).collect();
310            Ok(quote! {
311                ::sml::Value::Array(::std::vec![
312                    #(::sml::SmlSerialize::to_sml_value(&self.#idx)),*
313                ])
314            })
315        }
316        Fields::Unit => {
317            let n = LitStr::new(&name.to_string(), Span::call_site());
318            Ok(quote! { ::sml::Value::Str(#n.into()) })
319        }
320    }
321}
322
323fn gen_enum_serialize(
324    e: &syn::DataEnum,
325    rename_all: Option<&str>,
326) -> syn::Result<proc_macro2::TokenStream> {
327    let mut arms = Vec::new();
328    for v in &e.variants {
329        let attrs = parse_field_attrs(&v.attrs)?;
330        let vname = attrs
331            .rename
332            .clone()
333            .unwrap_or_else(|| apply_case(&v.ident.to_string(), rename_all));
334        let vname_lit = LitStr::new(&vname, Span::call_site());
335        let ident = &v.ident;
336        match &v.fields {
337            Fields::Unit => {
338                arms.push(quote! {
339                    Self::#ident => ::sml::Value::Str(#vname_lit.into()),
340                });
341            }
342            Fields::Unnamed(unnamed) if unnamed.unnamed.len() == 1 => {
343                arms.push(quote! {
344                    Self::#ident(__f0) => {
345                        let mut __m = ::std::collections::BTreeMap::new();
346                        __m.insert("__type".into(), ::sml::Value::Str(#vname_lit.into()));
347                        __m.insert("_value".into(), ::sml::SmlSerialize::to_sml_value(__f0));
348                        ::sml::Value::Object(__m)
349                    },
350                });
351            }
352            Fields::Unnamed(unnamed) => {
353                let pats: Vec<Ident> = (0..unnamed.unnamed.len())
354                    .map(|i| format_ident!("__f{i}"))
355                    .collect();
356                let vals = pats
357                    .iter()
358                    .map(|p| quote! { ::sml::SmlSerialize::to_sml_value(#p) });
359                arms.push(quote! {
360                    Self::#ident(#(#pats),*) => {
361                        let mut __m = ::std::collections::BTreeMap::new();
362                        __m.insert("__type".into(), ::sml::Value::Str(#vname_lit.into()));
363                        __m.insert("_value".into(), ::sml::Value::Array(::std::vec![#(#vals),*]));
364                        ::sml::Value::Object(__m)
365                    },
366                });
367            }
368            Fields::Named(named) => {
369                let fnames: Vec<&Ident> =
370                    named.named.iter().map(|f| f.ident.as_ref().unwrap()).collect();
371                let mut stmts = Vec::new();
372                for f in &named.named {
373                    let fattrs = parse_field_attrs(&f.attrs)?;
374                    let fid = f.ident.as_ref().unwrap();
375                    if fattrs.skip {
376                        continue;
377                    }
378                    let key = field_key(&fattrs, rename_all, fid);
379                    let key_lit = LitStr::new(&key, Span::call_site());
380                    if is_option(&f.ty) {
381                        stmts.push(quote! {
382                            if let ::core::option::Option::Some(__v) = #fid {
383                                __m.insert(#key_lit.into(), ::sml::SmlSerialize::to_sml_value(__v));
384                            }
385                        });
386                    } else {
387                        stmts.push(quote! {
388                            __m.insert(#key_lit.into(), ::sml::SmlSerialize::to_sml_value(#fid));
389                        });
390                    }
391                }
392                arms.push(quote! {
393                    Self::#ident { #(#fnames),* } => {
394                        let mut __m = ::std::collections::BTreeMap::new();
395                        __m.insert("__type".into(), ::sml::Value::Str(#vname_lit.into()));
396                        #(#stmts)*
397                        ::sml::Value::Object(__m)
398                    },
399                });
400            }
401        }
402    }
403    Ok(quote! {
404        match self {
405            #(#arms)*
406        }
407    })
408}
409
410// ---------------------------------------------------------------------------
411// SmlDeserialize
412// ---------------------------------------------------------------------------
413
414fn expand_deserialize(input: &DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
415    let name = &input.ident;
416    let rename_all = parse_rename_all(&input.attrs)?;
417    let mut where_clause: syn::WhereClause = input
418        .generics
419        .where_clause
420        .clone()
421        .unwrap_or_else(|| syn::parse_quote!(where));
422    for tp in input.generics.type_params() {
423        let ident = &tp.ident;
424        where_clause
425            .predicates
426            .push(syn::parse_quote!(#ident: ::sml::SmlDeserialize));
427    }
428    let (impl_generics, ty_generics, _) = input.generics.split_for_impl();
429
430    let body = match &input.data {
431        Data::Struct(s) => gen_struct_deserialize(s, name, rename_all.as_deref())?,
432        Data::Enum(e) => gen_enum_deserialize(e, rename_all.as_deref())?,
433        Data::Union(u) => {
434            return Err(syn::Error::new_spanned(
435                u.union_token,
436                "SmlDeserialize 不支持 union 类型",
437            ))
438        }
439    };
440
441    Ok(quote! {
442        impl #impl_generics ::sml::SmlDeserialize for #name #ty_generics #where_clause {
443            fn from_sml_value(__v: &::sml::Value) -> ::core::result::Result<Self, ::std::string::String> {
444                #body
445            }
446        }
447    })
448}
449
450fn gen_struct_deserialize(
451    s: &syn::DataStruct,
452    name: &Ident,
453    rename_all: Option<&str>,
454) -> syn::Result<proc_macro2::TokenStream> {
455    match &s.fields {
456        Fields::Named(named) => {
457            let mut inits = Vec::new();
458            for f in &named.named {
459                let attrs = parse_field_attrs(&f.attrs)?;
460                let fid = f.ident.as_ref().unwrap();
461                let key = field_key(&attrs, rename_all, fid);
462                let key_lit = LitStr::new(&key, Span::call_site());
463                if attrs.skip {
464                    inits.push(quote! { #fid: ::core::default::Default::default() });
465                    continue;
466                }
467                if attrs.flatten {
468                    inits.push(quote! {
469                        #fid: ::sml::__private::flatten_from(__m)
470                            .map_err(|__e| ::std::format!("字段 `{}` (flatten): {__e}", #key_lit))?
471                    });
472                    continue;
473                }
474                if is_option(&f.ty) {
475                    inits.push(quote! {
476                        #fid: match __m.get(#key_lit) {
477                            ::core::option::Option::Some(__x) => {
478                                ::sml::SmlDeserialize::from_sml_value(__x)
479                                    .map_err(|__e| ::std::format!("字段 `{}`: {__e}", #key_lit))?
480                            }
481                            ::core::option::Option::None => ::core::option::Option::None,
482                        }
483                    });
484                } else if attrs.default {
485                    inits.push(quote! {
486                        #fid: match __m.get(#key_lit) {
487                            ::core::option::Option::Some(__x) => {
488                                ::sml::SmlDeserialize::from_sml_value(__x)
489                                    .map_err(|__e| ::std::format!("字段 `{}`: {__e}", #key_lit))?
490                            }
491                            ::core::option::Option::None => ::core::default::Default::default(),
492                        }
493                    });
494                } else {
495                    inits.push(quote! {
496                        #fid: match __m.get(#key_lit) {
497                            ::core::option::Option::Some(__x) => {
498                                ::sml::SmlDeserialize::from_sml_value(__x)
499                                    .map_err(|__e| ::std::format!("字段 `{}`: {__e}", #key_lit))?
500                            }
501                            ::core::option::Option::None => {
502                                return ::core::result::Result::Err(
503                                    ::std::format!("字段 `{}` 缺失", #key_lit))
504                            }
505                        }
506                    });
507                }
508            }
509            Ok(quote! {
510                let __m = match __v {
511                    ::sml::Value::Object(__m) => __m,
512                    __other => {
513                        return ::core::result::Result::Err(::std::format!(
514                            "期望块(object),实际为 {}",
515                            ::sml::__private::describe_value(__other)
516                        ))
517                    }
518                };
519                ::core::result::Result::Ok(Self { #(#inits),* })
520            })
521        }
522        Fields::Unnamed(unnamed) if unnamed.unnamed.len() == 1 => {
523            Ok(quote! {
524                ::core::result::Result::Ok(Self(
525                    ::sml::SmlDeserialize::from_sml_value(__v)
526                        .map_err(|__e| ::std::format!("newtype 内容: {__e}"))?
527                ))
528            })
529        }
530        Fields::Unnamed(unnamed) => {
531            let n = unnamed.unnamed.len();
532            let idx: Vec<_> = (0..n).map(syn::Index::from).collect();
533            Ok(quote! {
534                let __a = match __v {
535                    ::sml::Value::Array(__a) => __a,
536                    __other => {
537                        return ::core::result::Result::Err(::std::format!(
538                            "期望数组({} 个元素),实际为 {}",
539                            #n, ::sml::__private::describe_value(__other)
540                        ))
541                    }
542                };
543                if __a.len() != #n {
544                    return ::core::result::Result::Err(
545                        ::std::format!("期望 {} 个元素的数组,实际 {} 个", #n, __a.len()));
546                }
547                let mut __it = __a.into_iter();
548                ::core::result::Result::Ok(Self(
549                    #(
550                        ::sml::SmlDeserialize::from_sml_value(&__it.next().unwrap())
551                            .map_err(|__e| ::std::format!("元素 {}: {__e}", #idx))?
552                    ),*
553                ))
554            })
555        }
556        Fields::Unit => {
557            let n = LitStr::new(&name.to_string(), Span::call_site());
558            Ok(quote! {
559                match __v {
560                    ::sml::Value::Str(__s) if __s == #n => ::core::result::Result::Ok(Self),
561                    __other => ::core::result::Result::Err(::std::format!(
562                        "期望裸词 `{}`,实际为 {}",
563                        #n, ::sml::__private::describe_value(__other)
564                    )),
565                }
566            })
567        }
568    }
569}
570
571fn gen_enum_deserialize(
572    e: &syn::DataEnum,
573    rename_all: Option<&str>,
574) -> syn::Result<proc_macro2::TokenStream> {
575    let mut str_arms = Vec::new();
576    let mut obj_arms = Vec::new();
577    for v in &e.variants {
578        let attrs = parse_field_attrs(&v.attrs)?;
579        let vname = attrs
580            .rename
581            .clone()
582            .unwrap_or_else(|| apply_case(&v.ident.to_string(), rename_all));
583        let vname_lit = LitStr::new(&vname, Span::call_site());
584        let ident = &v.ident;
585        match &v.fields {
586            Fields::Unit => {
587                str_arms.push(quote! {
588                    #vname_lit => ::core::result::Result::Ok(Self::#ident),
589                });
590                obj_arms.push(quote! {
591                    #vname_lit => ::core::result::Result::Ok(Self::#ident),
592                });
593            }
594            Fields::Unnamed(unnamed) => {
595                let n = unnamed.unnamed.len();
596                let pats: Vec<Ident> = (0..n).map(|i| format_ident!("__v{i}")).collect();
597                let bindings = if n == 1 {
598                    quote! {
599                        let #(#pats),* = ::sml::__private::take_value(__m)?;
600                    }
601                } else {
602                    quote! {
603                        let __arr = ::sml::__private::take_array(__m)?;
604                        if __arr.len() != #n {
605                            return ::core::result::Result::Err(::std::format!(
606                                "变体 `{}` 期望 {} 个元素,实际 {} 个",
607                                #vname_lit, #n, __arr.len()));
608                        }
609                        let mut __it = __arr.into_iter();
610                        #(let #pats = __it.next().unwrap();)*
611                    }
612                };
613                obj_arms.push(quote! {
614                    #vname_lit => {
615                        #bindings
616                        ::core::result::Result::Ok(Self::#ident(#(
617                            ::sml::SmlDeserialize::from_sml_value(&#pats)
618                                .map_err(|__e| ::std::format!("变体 `{}` 内容: {__e}", #vname_lit))?
619                        ),*))
620                    },
621                });
622            }
623            Fields::Named(named) => {
624                let mut inits = Vec::new();
625                for f in &named.named {
626                    let fattrs = parse_field_attrs(&f.attrs)?;
627                    let fid = f.ident.as_ref().unwrap();
628                    let key = field_key(&fattrs, rename_all, fid);
629                    let key_lit = LitStr::new(&key, Span::call_site());
630                    if fattrs.skip {
631                        inits.push(quote! { #fid: ::core::default::Default::default() });
632                        continue;
633                    }
634                    if is_option(&f.ty) {
635                        inits.push(quote! {
636                            #fid: match __m.get(#key_lit) {
637                                ::core::option::Option::Some(__x) => {
638                                    ::sml::SmlDeserialize::from_sml_value(__x)
639                                        .map_err(|__e| ::std::format!(
640                                            "变体 `{}` 字段 `{}`: {__e}", #vname_lit, #key_lit))?
641                                }
642                                ::core::option::Option::None => ::core::option::Option::None,
643                            }
644                        });
645                    } else if fattrs.default {
646                        inits.push(quote! {
647                            #fid: match __m.get(#key_lit) {
648                                ::core::option::Option::Some(__x) => {
649                                    ::sml::SmlDeserialize::from_sml_value(__x)
650                                        .map_err(|__e| ::std::format!(
651                                            "变体 `{}` 字段 `{}`: {__e}", #vname_lit, #key_lit))?
652                                }
653                                ::core::option::Option::None => ::core::default::Default::default(),
654                            }
655                        });
656                    } else {
657                        inits.push(quote! {
658                            #fid: match __m.get(#key_lit) {
659                                ::core::option::Option::Some(__x) => {
660                                    ::sml::SmlDeserialize::from_sml_value(__x)
661                                        .map_err(|__e| ::std::format!(
662                                            "变体 `{}` 字段 `{}`: {__e}", #vname_lit, #key_lit))?
663                                }
664                                ::core::option::Option::None => {
665                                    return ::core::result::Result::Err(::std::format!(
666                                        "变体 `{}` 字段 `{}` 缺失", #vname_lit, #key_lit))
667                                }
668                            }
669                        });
670                    }
671                }
672                obj_arms.push(quote! {
673                    #vname_lit => ::core::result::Result::Ok(Self::#ident { #(#inits),* }),
674                });
675            }
676        }
677    }
678    Ok(quote! {
679        match __v {
680            ::sml::Value::Str(__s) => match __s.as_str() {
681                #(#str_arms)*
682                __other => ::core::result::Result::Err(
683                    ::std::format!("未知的枚举值 `{__other}`")),
684            },
685            ::sml::Value::Object(__m) => {
686                let __t = match __m.get("__type") {
687                    ::core::option::Option::Some(::sml::Value::Str(__t)) => __t.as_str(),
688                    _ => {
689                        return ::core::result::Result::Err(
690                            ::std::string::String::from(
691                                "枚举需要带 __type 的块(如 `{ __type: Variant }`)"))
692                    }
693                };
694                match __t {
695                    #(#obj_arms)*
696                    __other => ::core::result::Result::Err(
697                        ::std::format!("未知的枚举变体 `{__other}`")),
698                }
699            }
700            __other => ::core::result::Result::Err(::std::format!(
701                "期望裸词或带 __type 的块,实际为 {}",
702                ::sml::__private::describe_value(__other))),
703        }
704    })
705}