1use 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#[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
131fn 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 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
209fn 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 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
410fn 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}