afastdata_macro/lib.rs
1//! # afastdata-macro
2//!
3//! afastdata 序列化框架的 derive 宏,为结构体和枚举自动生成
4//! [`AFastSerialize`] 和 [`AFastDeserialize`] trait 的实现。
5//!
6//! Derive macros for the afastdata serialization framework, automatically generating
7//! implementations of [`AFastSerialize`]` and [`AFastDeserialize`] traits for
8//! structs and enums.
9//!
10//! ## 支持的类型 / Supported Types
11//!
12//! - **命名字段结构体 (Named-field struct)**:逐字段序列化/反序列化
13//! / Field-by-field serialization/deserialization
14//! - **元组结构体 (Tuple struct)**:按索引逐字段序列化/反序列化
15//! / Index-based field serialization/deserialization
16//! - **单元结构体 (Unit struct)**:生成空实现(不产生任何字节)
17//! / Generates an empty implementation (no bytes produced)
18//! - **枚举 (Enum)**:写入 `u32` 变体索引 + 变体字段数据
19//! / Writes a `u32` variant index + variant field data
20//!
21//! ## 编码格式 / Encoding Format
22//!
23//! ### 结构体 / Struct
24//!
25//! 所有字段按声明顺序依次调用 `to_bytes()` / `from_bytes()`,无额外前缀。
26//!
27//! All fields call `to_bytes()` / `from_bytes()` in declaration order, with no
28//! additional prefix.
29//!
30//! ### 枚举 / Enum
31//!
32//! | 编码内容 / Content | 类型 / Type | 说明 / Description |
33//! |---|---|---|
34//! | 变体索引 / Variant index | `u32` little-endian | 从 0 开始递增 / Starts from 0, incrementing |
35//! | 变体字段 / Variant fields | 逐字段编码 / Field-wise encoding | 仅非 unit 变体 / Only for non-unit variants |
36//!
37//! ## 泛型支持 / Generic Support
38//!
39//! 泛型参数会自动添加 `AFastSerialize` 和(对于反序列化)`AFastDeserialize` trait 约束。
40//! 如果泛型参数仅用于某些字段,生成的约束可能过于严格,但这保证了实现的正确性。
41//!
42//! Generic parameters automatically receive `AFastSerialize` and (for deserialization)
43//! `AFastDeserialize` trait bounds. If a generic parameter is only used in certain fields,
44//! the generated bounds may be overly strict, but this ensures correctness.
45//!
46//! ## 示例 / Example
47//!
48//! ```
49//! extern crate afastdata;
50//! use afastdata::{AFastSerialize, AFastDeserialize};
51//!
52//! #[derive(AFastSerialize, AFastDeserialize, Debug, PartialEq)]
53//! struct Point {
54//! x: i32,
55//! y: i32,
56//! }
57//!
58//! #[derive(AFastSerialize, AFastDeserialize, Debug, PartialEq)]
59//! enum Shape {
60//! Circle(f64),
61//! Rectangle { width: f64, height: f64 },
62//! Empty,
63//! }
64//!
65//! // 序列化 / Serialize
66//! let point = Point { x: 10, y: 20 };
67//! let bytes = point.to_bytes();
68//!
69//! // 反序列化 / Deserialize
70//! let (decoded, _) = Point::from_bytes(&bytes).unwrap();
71//! assert_eq!(point, decoded);
72//! ```
73
74use proc_macro::TokenStream;
75use quote::quote;
76use syn::{
77 Attribute, Data, DeriveInput, Fields, Index, Lit, LitFloat, LitInt, LitStr, Meta, Path, Token, Type,
78 TypePath,
79 parse::{Parse, ParseStream},
80 parse_macro_input,
81 punctuated::Punctuated,
82};
83
84/// 返回枚举变体标签的类型和字节大小,基于编译时 feature 配置。
85///
86/// Returns the enum variant tag type and byte size based on compile-time feature config.
87fn tag_type() -> (proc_macro2::TokenStream, usize) {
88 if cfg!(feature = "tag-u16") {
89 (quote! { u16 }, 2)
90 } else if cfg!(feature = "tag-u32") {
91 (quote! { u32 }, 4)
92 } else {
93 (quote! { u8 }, 1)
94 }
95}
96
97/// 为结构体或枚举生成 [`AFastSerialize`] trait 实现。
98///
99/// Generates an [`AFastSerialize`] trait implementation for a struct or enum.
100///
101/// # 生成的代码 / Generated Code
102///
103/// ## 结构体 / Struct
104///
105/// 为每个字段调用 `to_bytes()`,并将结果依次追加到字节缓冲区中。
106///
107/// Calls `to_bytes()` on each field, appending the results to a byte buffer
108/// sequentially.
109///
110/// ```text
111/// // 以下为生成代码的示意(非实际代码)
112/// // The following is an illustration of generated code (not actual code)
113/// impl AFastSerialize for MyStruct {
114/// fn to_bytes(&self) -> Vec<u8> {
115/// let mut bytes = Vec::new();
116/// bytes.extend(AFastSerialize::to_bytes(&self.field1));
117/// bytes.extend(AFastSerialize::to_bytes(&self.field2));
118/// // ... 依次处理每个字段 / remaining fields processed similarly
119/// bytes
120/// }
121/// }
122/// ```
123///
124/// ## 枚举 / Enum
125///
126/// 先写入 `u8` 变体索引(从 0 开始),再写入变体的字段数据。
127/// Unit 变体只写入索引。可通过 feature 切换为 `u16` 或 `u32`。
128///
129/// Writes a `u8` variant index (starting from 0), then the variant's field data.
130/// Unit variants only write the index. Switchable to `u16` or `u32` via features.
131///
132/// ```text
133/// // 以下为生成代码的示意(非实际代码)
134/// // The following is an illustration of generated code (not actual code)
135/// impl AFastSerialize for MyEnum {
136/// fn to_bytes(&self) -> Vec<u8> {
137/// let mut bytes = Vec::new();
138/// match self {
139/// MyEnum::Variant1 => {
140/// bytes.extend(0u8.to_le_bytes());
141/// }
142/// MyEnum::Variant2(field) => {
143/// bytes.extend(1u8.to_le_bytes());
144/// bytes.extend(AFastSerialize::to_bytes(field));
145/// }
146/// // ...
147/// }
148/// bytes
149/// }
150/// }
151/// ```
152///
153/// # 泛型 / Generics
154///
155/// 如果目标类型包含泛型参数,生成的 `impl` 会自动为这些参数添加
156/// `AFastSerialize` 约束。
157///
158/// If the target type contains generic parameters, the generated `impl` automatically
159/// adds `AFastSerialize` bounds to those parameters.
160///
161/// # Panics
162///
163/// 对 union 类型使用此宏会触发编译 panic。
164///
165/// Using this macro on a union type will trigger a compile-time panic.
166#[proc_macro_derive(AFastSerialize, attributes(afast))]
167pub fn derive_serialize(input: TokenStream) -> TokenStream {
168 let input = parse_macro_input!(input as DeriveInput);
169 let name = &input.ident;
170 let generics = &input.generics;
171
172 // 为泛型参数添加 AFastSerialize trait 约束
173 // Add AFastSerialize trait bounds to generic parameters
174 let mut generics_with_bounds = generics.clone();
175 for param in &mut generics_with_bounds.params {
176 if let syn::GenericParam::Type(ref mut ty) = *param {
177 ty.bounds
178 .push(syn::parse_quote!(::afastdata::AFastSerialize));
179 }
180 }
181 let (impl_generics, _, _) = generics_with_bounds.split_for_impl();
182 let (_, ty_generics, _) = generics.split_for_impl();
183
184 let expanded = match &input.data {
185 Data::Struct(data) => {
186 let serialize_body = generate_serialize_fields(&data.fields, quote!(self));
187 quote! {
188 impl #impl_generics ::afastdata::AFastSerialize for #name #ty_generics {
189 fn to_bytes(&self) -> Vec<u8> {
190 let mut bytes = Vec::new();
191 #(#serialize_body)*
192 bytes
193 }
194 }
195 }
196 }
197 Data::Enum(data) => {
198 let (tag_ty, _) = tag_type();
199 let mut arms = Vec::new();
200 for (i, variant) in data.variants.iter().enumerate() {
201 let variant_name = &variant.ident;
202
203 match &variant.fields {
204 Fields::Unit => {
205 arms.push(quote! {
206 #name::#variant_name => {
207 bytes.extend((#i as #tag_ty).to_le_bytes());
208 }
209 });
210 }
211 Fields::Unnamed(fields) => {
212 let field_names: Vec<_> = (0..fields.unnamed.len())
213 .map(|i| {
214 syn::Ident::new(&format!("__f{}", i), variant_name.span())
215 })
216 .collect();
217 let field_patterns = &field_names;
218 let mut serialize_fields = Vec::new();
219 for (i, f) in fields.unnamed.iter().enumerate() {
220 if !has_skip_attr(&f.attrs).0 {
221 let fname = &field_names[i];
222 serialize_fields.push(quote! {
223 bytes.extend(::afastdata::AFastSerialize::to_bytes(#fname));
224 });
225 }
226 }
227 arms.push(quote! {
228 #name::#variant_name(#(#field_patterns),*) => {
229 bytes.extend((#i as #tag_ty).to_le_bytes());
230 #(#serialize_fields)*
231 }
232 });
233 }
234 Fields::Named(fields) => {
235 let all_field_names: Vec<_> = fields
236 .named
237 .iter()
238 .map(|f| f.ident.as_ref().unwrap())
239 .collect();
240 let non_skip_names: Vec<_> = fields
241 .named
242 .iter()
243 .filter(|f| !has_skip_attr(&f.attrs).0)
244 .map(|f| f.ident.as_ref().unwrap())
245 .collect();
246 let has_skip = non_skip_names.len() < all_field_names.len();
247 let mut serialize_fields = Vec::new();
248 for fname in &non_skip_names {
249 serialize_fields.push(quote! {
250 bytes.extend(::afastdata::AFastSerialize::to_bytes(#fname));
251 });
252 }
253 if has_skip {
254 arms.push(quote! {
255 #name::#variant_name { #(#non_skip_names),*, .. } => {
256 bytes.extend((#i as #tag_ty).to_le_bytes());
257 #(#serialize_fields)*
258 }
259 });
260 } else {
261 arms.push(quote! {
262 #name::#variant_name { #(#non_skip_names),* } => {
263 bytes.extend((#i as #tag_ty).to_le_bytes());
264 #(#serialize_fields)*
265 }
266 });
267 }
268 }
269 }
270 }
271
272 quote! {
273 impl #impl_generics ::afastdata::AFastSerialize for #name #ty_generics {
274 fn to_bytes(&self) -> Vec<u8> {
275 let mut bytes = Vec::new();
276 match self {
277 #(#arms)*
278 }
279 bytes
280 }
281 }
282 }
283 }
284 Data::Union(_) => panic!("AFastSerialize does not support unions"),
285 };
286
287 TokenStream::from(expanded)
288}
289
290/// 为结构体或枚举生成 [`AFastDeserialize`] trait 实现。
291///
292/// Generates an [`AFastDeserialize`] trait implementation for a struct or enum.
293///
294/// # 生成的代码 / Generated Code
295///
296/// ## 结构体 / Struct
297///
298/// 为每个字段依次调用 `from_bytes()`,并使用偏移量追踪已消耗的字节数,
299/// 最后构造结构体实例。
300///
301/// Calls `from_bytes()` on each field sequentially, using an offset to track
302/// consumed bytes, then constructs the struct instance.
303///
304/// ```text
305/// // 以下为生成代码的示意(非实际代码)
306/// // The following is an illustration of generated code (not actual code)
307/// impl AFastDeserialize for MyStruct {
308/// fn from_bytes(data: &[u8]) -> Result<(Self, usize), Error> {
309/// let mut offset: usize = 0;
310/// let (__val, __new_offset) = AFastDeserialize::from_bytes(&data[offset..])?;
311/// let field1 = __val;
312/// offset += __new_offset;
313/// // ... 更多字段 / more fields ...
314/// Ok((MyStruct { field1, ... }, offset))
315/// }
316/// }
317/// ```
318///
319/// ## 枚举 / Enum
320///
321/// 先读取 `u8` 变体索引,根据索引匹配对应变体,再反序列化该变体的字段。
322/// 可通过 feature 切换为 `u16` 或 `u32`。
323///
324/// First reads the `u8` variant index, matches the corresponding variant by index,
325/// then deserializes the variant's fields.
326/// Switchable to `u16` or `u32` via features.
327///
328/// ```text
329/// // 以下为生成代码的示意(非实际代码)
330/// // The following is an illustration of generated code (not actual code)
331/// impl AFastDeserialize for MyEnum {
332/// fn from_bytes(data: &[u8]) -> Result<(Self, usize), Error> {
333/// let mut offset: usize = 0;
334/// let (__tag, __new_offset) = <u8 as AFastDeserialize>::from_bytes(&data[offset..])?;
335/// offset += __new_offset;
336/// match __tag as usize {
337/// 0 => Ok((MyEnum::Variant1, offset)),
338/// 1 => {
339/// let (__val, __new_offset) = AFastDeserialize::from_bytes(&data[offset..])?;
340/// offset += __new_offset;
341/// Ok((MyEnum::Variant2(__val), offset))
342/// }
343/// v => Err(format!("Unknown variant tag: {} for MyEnum", v)),
344/// }
345/// }
346/// }
347/// ```
348///
349/// # 泛型 / Generics
350///
351/// 如果目标类型包含泛型参数,生成的 `impl` 会同时添加 `AFastSerialize` 和
352/// `AFastDeserialize` 约束。双重约束确保泛型类型在序列化和反序列化两个方向
353/// 上都可用。
354///
355/// If the target type contains generic parameters, the generated `impl` adds both
356/// `AFastSerialize` and `AFastDeserialize` bounds. The dual bounds ensure the generic
357/// type is available in both serialization and deserialization directions.
358///
359/// # Panics
360///
361/// 对 union 类型使用此宏会触发编译 panic。
362///
363/// Using this macro on a union type will trigger a compile-time panic.
364#[proc_macro_derive(AFastDeserialize, attributes(afast))]
365pub fn derive_deserialize(input: TokenStream) -> TokenStream {
366 let input = parse_macro_input!(input as DeriveInput);
367 let name = &input.ident;
368 let generics = &input.generics;
369
370 // 为泛型参数添加 AFastSerialize + AFastDeserialize trait 约束
371 // Add AFastSerialize + AFastDeserialize trait bounds to generic parameters
372 let mut generics_with_bounds = generics.clone();
373 for param in &mut generics_with_bounds.params {
374 if let syn::GenericParam::Type(ref mut ty) = *param {
375 ty.bounds
376 .push(syn::parse_quote!(::afastdata::AFastSerialize));
377 ty.bounds
378 .push(syn::parse_quote!(::afastdata::AFastDeserialize));
379 }
380 }
381 let (impl_generics, _, _) = generics_with_bounds.split_for_impl();
382 let (_, ty_generics, _) = generics.split_for_impl();
383
384 let expanded = match &input.data {
385 Data::Struct(data) => {
386 let (construct, field_desers) =
387 generate_deserialize_fields(&data.fields, name, &ty_generics);
388 quote! {
389 impl #impl_generics ::afastdata::AFastDeserialize for #name #ty_generics {
390 fn from_bytes(data: &[u8]) -> Result<(Self, usize), ::afastdata::Error> {
391 let mut offset: usize = 0;
392 #(#field_desers)*
393 Ok((#construct, offset))
394 }
395 }
396 }
397 }
398 Data::Enum(data) => {
399 let (tag_ty, _) = tag_type();
400 let mut arms = Vec::new();
401 for (i, variant) in data.variants.iter().enumerate() {
402 let variant_name = &variant.ident;
403
404 match &variant.fields {
405 Fields::Unit => {
406 arms.push(quote! {
407 #i => {
408 Ok((#name::#variant_name, offset))
409 }
410 });
411 }
412 Fields::Unnamed(fields) => {
413 let mut field_desers = Vec::new();
414 let mut field_names = Vec::new();
415 for (i, f) in fields.unnamed.iter().enumerate() {
416 let fname = syn::Ident::new(
417 &format!("__f{}", i),
418 variant_name.span(),
419 );
420 let ftype = &f.ty;
421 let (skip, default_fn) = has_skip_attr(&f.attrs);
422 if skip {
423 if let Some(func_name) = default_fn {
424 match syn::parse_str::<syn::Ident>(&func_name) {
425 Ok(ident) => {
426 field_desers.push(quote! {
427 let #fname: #ftype = #ident();
428 });
429 }
430 Err(_) => {
431 field_desers.push(quote! {
432 compile_error!(concat!("invalid function name in skip: ", #func_name));
433 });
434 }
435 }
436 } else {
437 field_desers.push(quote! {
438 let #fname: #ftype = <#ftype as ::std::default::Default>::default();
439 });
440 }
441 } else {
442 let validates = parse_validations(&fname, ftype, &f.attrs);
443 field_desers.push(quote! {
444 let (__val, __new_offset) = ::afastdata::AFastDeserialize::from_bytes(&data[offset..])?;
445 let #fname: #ftype = __val;
446 #(#validates)*
447 offset += __new_offset;
448 });
449 }
450 field_names.push(fname);
451 }
452 arms.push(quote! {
453 #i => {
454 #(#field_desers)*
455 Ok((#name::#variant_name(#(#field_names),*), offset))
456 }
457 });
458 }
459 Fields::Named(fields) => {
460 let mut field_desers = Vec::new();
461 let mut field_names = Vec::new();
462 for f in &fields.named {
463 let fname = f.ident.as_ref().unwrap();
464 let ftype = &f.ty;
465 let (skip, default_fn) = has_skip_attr(&f.attrs);
466 if skip {
467 if let Some(func_name) = default_fn {
468 match syn::parse_str::<syn::Ident>(&func_name) {
469 Ok(ident) => {
470 field_desers.push(quote! {
471 let #fname: #ftype = #ident();
472 });
473 }
474 Err(_) => {
475 field_desers.push(quote! {
476 compile_error!(concat!("invalid function name in skip: ", #func_name));
477 });
478 }
479 }
480 } else {
481 field_desers.push(quote! {
482 let #fname: #ftype = <#ftype as ::std::default::Default>::default();
483 });
484 }
485 } else {
486 let validates = parse_validations(fname, ftype, &f.attrs);
487 field_desers.push(quote! {
488 let (__val, __new_offset) = ::afastdata::AFastDeserialize::from_bytes(&data[offset..])?;
489 let #fname: #ftype = __val;
490 #(#validates)*
491 offset += __new_offset;
492 });
493 }
494 field_names.push(fname);
495 }
496 arms.push(quote! {
497 #i => {
498 #(#field_desers)*
499 Ok((#name::#variant_name { #(#field_names),* }, offset))
500 }
501 });
502 }
503 }
504 }
505
506 quote! {
507 impl #impl_generics ::afastdata::AFastDeserialize for #name #ty_generics {
508 fn from_bytes(data: &[u8]) -> Result<(Self, usize), ::afastdata::Error> {
509 let mut offset: usize = 0;
510 let (__tag_bytes, __new_offset) = <#tag_ty as ::afastdata::AFastDeserialize>::from_bytes(&data[offset..])?;
511 offset += __new_offset;
512 match __tag_bytes as usize {
513 #(#arms)*
514 v => Err(::afastdata::Error::deserialize(format!("Unknown variant tag: {} for {}", v, ::std::stringify!(#name)))),
515 }
516 }
517 }
518 }
519 }
520 Data::Union(_) => panic!("AFastDeserialize does not support unions"),
521 };
522
523 TokenStream::from(expanded)
524}
525
526/// 为结构体的字段生成序列化代码。内部辅助函数。
527///
528/// Generates serialization code for struct fields. Internal helper.
529///
530/// # 参数 / Parameters
531///
532/// - `fields`:结构体的字段定义 / The struct's field definitions
533/// - `self_prefix`:访问字段时使用的前缀(如 `self` 或变体解构变量)
534/// / The prefix used to access fields (e.g., `self` or a variant destructure variable)
535///
536/// # 返回值 / Returns
537///
538/// 返回一个 `TokenStream` 列表,每个元素对应一个字段的序列化语句。
539///
540/// Returns a list of `TokenStream`s, each corresponding to a serialization statement
541/// for one field.
542///
543/// # 生成格式 / Generated Format
544///
545/// - **命名字段 (Named)**:`bytes.extend(AFastSerialize::to_bytes(&self.field_name));`
546/// - **元组字段 (Unnamed)**:`bytes.extend(AFastSerialize::to_bytes(&self.0));`
547/// - **单元字段 (Unit)**:不生成任何代码 / Generates no code
548fn generate_serialize_fields(
549 fields: &Fields,
550 self_prefix: proc_macro2::TokenStream,
551) -> Vec<proc_macro2::TokenStream> {
552 match fields {
553 Fields::Named(named) => named
554 .named
555 .iter()
556 .filter(|f| !has_skip_attr(&f.attrs).0)
557 .map(|f| {
558 let fname = f.ident.as_ref().unwrap();
559 quote! {
560 bytes.extend(::afastdata::AFastSerialize::to_bytes(&#self_prefix.#fname));
561 }
562 })
563 .collect(),
564 Fields::Unnamed(unnamed) => unnamed
565 .unnamed
566 .iter()
567 .enumerate()
568 .filter(|(_, f)| !has_skip_attr(&f.attrs).0)
569 .map(|(i, _)| {
570 let idx = Index::from(i);
571 quote! {
572 bytes.extend(::afastdata::AFastSerialize::to_bytes(&#self_prefix.#idx));
573 }
574 })
575 .collect(),
576 Fields::Unit => vec![],
577 }
578}
579
580fn has_skip_attr(attrs: &[Attribute]) -> (bool, Option<String>) {
581 for attr in attrs {
582 if attr.path().is_ident("afast")
583 && let Ok(nested) =
584 attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)
585 {
586 for meta in nested {
587 match meta {
588 Meta::Path(path) if path.is_ident("skip") => {
589 return (true, None);
590 }
591 Meta::List(meta_list) if meta_list.path.is_ident("skip") => {
592 if let Ok(lit_str) = syn::parse2::<LitStr>(meta_list.tokens.clone()) {
593 return (true, Some(lit_str.value()));
594 } else {
595 return (true, None);
596 }
597 }
598 _ => {}
599 }
600 }
601 }
602 }
603 (false, None)
604}
605
606enum RangeValue {
607 Int(LitInt),
608 Float(LitFloat),
609}
610
611impl RangeValue {
612 fn to_token_stream(&self) -> proc_macro2::TokenStream {
613 match self {
614 RangeValue::Int(v) => quote! { #v },
615 RangeValue::Float(v) => quote! { #v },
616 }
617 }
618}
619
620struct Range {
621 value: RangeValue,
622 _comma1: Token![,],
623 code: LitInt,
624 _comma2: Token![,],
625 msg: LitStr,
626}
627
628impl Parse for Range {
629 fn parse(input: ParseStream) -> syn::Result<Self> {
630 // Try to parse as float first, then as int
631 let value = if input.peek(LitFloat) {
632 RangeValue::Float(input.parse()?)
633 } else {
634 RangeValue::Int(input.parse()?)
635 };
636 Ok(Range {
637 value,
638 _comma1: input.parse()?,
639 code: input.parse()?,
640 _comma2: input.parse()?,
641 msg: input.parse()?,
642 })
643 }
644}
645
646struct Length {
647 min: LitInt,
648 _comma1: Token![,],
649 max: LitInt,
650 _comma2: Token![,],
651 code: LitInt,
652 _comma3: Token![,],
653 msg: LitStr,
654}
655
656impl Parse for Length {
657 fn parse(input: ParseStream) -> syn::Result<Self> {
658 Ok(Length {
659 min: input.parse()?,
660 _comma1: input.parse()?,
661 max: input.parse()?,
662 _comma2: input.parse()?,
663 code: input.parse()?,
664 _comma3: input.parse()?,
665 msg: input.parse()?,
666 })
667 }
668}
669
670#[derive(Clone)]
671enum ValidateValue {
672 Int(i64),
673 Float(f64),
674 Bool(bool),
675 Str(String),
676}
677
678impl ValidateValue {
679 /// 将值转换为代码生成中使用的 TokenStream
680 ///
681 /// 例如:
682 /// ValidateValue::Int(42) → quote! { 42 }
683 /// ValidateValue::Str("hello") → quote! { "hello" }
684 fn to_token_stream(&self) -> proc_macro2::TokenStream {
685 match self {
686 ValidateValue::Int(v) => quote! { #v },
687
688 ValidateValue::Float(v) => {
689 // 浮点数通过字符串解析来保持精度
690 let v_str = v.to_string();
691 v_str.parse().unwrap_or_else(|_| {
692 // 如果字符串解析失败,使用直接值
693 quote! { #v }
694 })
695 }
696
697 ValidateValue::Bool(v) => quote! { #v },
698 ValidateValue::Str(v) => quote! { #v },
699 }
700 }
701}
702
703struct OfValidator {
704 allowed_values: Vec<ValidateValue>,
705 code: syn::LitInt,
706 msg: syn::LitStr,
707}
708
709impl Parse for OfValidator {
710 fn parse(input: ParseStream) -> syn::Result<Self> {
711 let content;
712 syn::bracketed!(content in input);
713
714 let mut values = Vec::new();
715
716 if !content.is_empty() {
717 loop {
718 let lit = content.parse::<Lit>()?;
719
720 let value = match lit {
721 Lit::Int(lit_int) => {
722 let int_value: i64 = lit_int.base10_parse()?;
723 ValidateValue::Int(int_value)
724 }
725
726 Lit::Float(lit_float) => {
727 let float_value: f64 = lit_float.base10_parse()?;
728 ValidateValue::Float(float_value)
729 }
730
731 Lit::Bool(lit_bool) => ValidateValue::Bool(lit_bool.value),
732
733 Lit::Str(lit_str) => ValidateValue::Str(lit_str.value()),
734
735 _ => {
736 return Err(syn::Error::new_spanned(
737 &lit,
738 "unsupported literal type in 'of' validator; \
739 only int, float, bool, and str literals are supported",
740 ));
741 }
742 };
743
744 values.push(value);
745
746 if !content.peek(Token![,]) {
747 break;
748 }
749
750 content.parse::<Token![,]>()?;
751
752 if content.is_empty() {
753 break;
754 }
755 }
756 }
757
758 input.parse::<Token![,]>()?;
759
760 let code = input.parse::<syn::LitInt>()?;
761
762 input.parse::<Token![,]>()?;
763
764 let msg = input.parse::<syn::LitStr>()?;
765
766 Ok(OfValidator {
767 allowed_values: values,
768 code,
769 msg,
770 })
771 }
772}
773
774/// 检测字段类型是否为数值类型(i8..i128, u8..u128, f32, f64)。
775///
776/// Checks whether the field type is a numeric type.
777fn is_numeric_type(ty: &Type) -> bool {
778 if let Type::Path(TypePath { path, .. }) = ty {
779 if let Some(segment) = path.segments.last() {
780 let name = segment.ident.to_string();
781 return matches!(
782 name.as_str(),
783 "i8" | "i16"
784 | "i32"
785 | "i64"
786 | "i128"
787 | "u8"
788 | "u16"
789 | "u32"
790 | "u64"
791 | "u128"
792 | "usize"
793 | "f32"
794 | "f64"
795 );
796 }
797 }
798 false
799}
800
801/// 检测字段类型是否为 Option<T>。
802///
803/// Checks whether the field type is `Option<T>`.
804fn is_option_type(ty: &Type) -> bool {
805 if let Type::Path(TypePath {
806 path: Path { segments, .. },
807 ..
808 }) = ty
809 {
810 segments.len() == 1 && segments[0].ident == "Option"
811 } else {
812 false
813 }
814}
815
816/// 提取 Option<T> 的内部类型 T。
817///
818/// Extracts the inner type `T` from `Option<T>`.
819fn extract_option_inner(ty: &Type) -> Option<&Type> {
820 if let Type::Path(TypePath {
821 path: Path { segments, .. },
822 ..
823 }) = ty
824 {
825 if segments.len() == 1 && segments[0].ident == "Option" {
826 if let syn::PathArguments::AngleBracketed(args) = &segments[0].arguments {
827 if let Some(syn::GenericArgument::Type(inner)) = args.args.first() {
828 return Some(inner);
829 }
830 }
831 }
832 }
833 None
834}
835
836/// 检测字段类型是否为可进行比较校验的类型(数值类型或 Option<数值类型>)。
837///
838/// Checks whether the field type supports comparison validation
839/// (numeric type or Option<numeric type>).
840fn is_comparable_type(ty: &Type) -> bool {
841 if is_numeric_type(ty) {
842 return true;
843 }
844 if let Some(inner) = extract_option_inner(ty) {
845 return is_numeric_type(inner);
846 }
847 false
848}
849
850/// 检测字段类型是否为字符串或集合类型(String, &str, Vec<T>, [T; N])。
851///
852/// Checks whether the field type is a string or collection type.
853fn is_collection_type(ty: &Type) -> bool {
854 if let Type::Path(TypePath { path, .. }) = ty {
855 if let Some(segment) = path.segments.last() {
856 let name = segment.ident.to_string();
857 return matches!(name.as_str(), "String" | "Vec" | "BTreeSet" | "BTreeMap" | "HashSet" | "HashMap");
858 }
859 }
860 // [T; N] arrays
861 if let Type::Array(_) = ty {
862 return true;
863 }
864 // &str
865 if let Type::Reference(r) = ty {
866 if let Type::Path(TypePath { path, .. }) = &*r.elem {
867 if let Some(segment) = path.segments.last() {
868 return segment.ident == "str";
869 }
870 }
871 }
872 false
873}
874
875/// 解析字段上的 `#[afast(...)]` 校验属性,生成校验代码。
876///
877/// Parses `#[afast(...)]` validation attributes on a field and generates
878/// validation code blocks.
879///
880/// # 参数 / Parameters
881///
882/// - `field_name`:字段名 / Field name
883/// - `field_type`:字段类型 / Field type
884/// - `attrs`:字段的属性列表 / Field attributes
885///
886/// # 返回值 / Returns
887///
888/// 返回校验语句的 `TokenStream` 列表。
889///
890/// Returns a list of validation `TokenStream` blocks.
891fn parse_validations(
892 field_name: &syn::Ident,
893 field_type: &Type,
894 attrs: &[Attribute],
895) -> Vec<proc_macro2::TokenStream> {
896 let mut validates = Vec::new();
897 for attr in attrs {
898 if attr.path().is_ident("afast") {
899 let nested = match attr
900 .parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)
901 {
902 Ok(n) => n,
903 Err(e) => {
904 validates.push(e.to_compile_error());
905 continue;
906 }
907 };
908 for meta in nested {
909 if let Meta::List(meta) = meta {
910 if meta.path.is_ident("gt") {
911 if !is_comparable_type(field_type) {
912 validates.push(
913 syn::Error::new_spanned(
914 &meta.path,
915 format!(
916 "validation `gt` is only supported on numeric types or Option<numeric>, but field `{}` is not",
917 field_name
918 ),
919 )
920 .to_compile_error(),
921 );
922 continue;
923 }
924 let inner = match meta.parse_args::<Range>() {
925 Ok(v) => v,
926 Err(e) => {
927 validates.push(e.to_compile_error());
928 continue;
929 }
930 };
931 let cmp_value = inner.value.to_token_stream();
932 let code = match inner.code.base10_parse::<i64>() {
933 Ok(v) => v,
934 Err(e) => {
935 validates.push(
936 syn::Error::new_spanned(&inner.code, format!("invalid error code: {}", e))
937 .to_compile_error(),
938 );
939 continue;
940 }
941 };
942 let err_msg = inner
943 .msg
944 .value()
945 .replace("${field}", &field_name.to_string());
946 if is_option_type(field_type) {
947 validates.push(quote! {
948 if let Some(ref __val) = #field_name {
949 if *__val <= #cmp_value {
950 return Err(::afastdata::Error::validate(#code, #err_msg.to_string()));
951 }
952 }
953 });
954 } else {
955 validates.push(quote! {
956 if #field_name <= #cmp_value {
957 return Err(::afastdata::Error::validate(#code, #err_msg.to_string()));
958 }
959 });
960 }
961 } else if meta.path.is_ident("gte") {
962 if !is_comparable_type(field_type) {
963 validates.push(
964 syn::Error::new_spanned(
965 &meta.path,
966 format!(
967 "validation `gte` is only supported on numeric types (or Option<numeric>), but field `{}` is not",
968 field_name
969 ),
970 )
971 .to_compile_error(),
972 );
973 continue;
974 }
975 let inner = match meta.parse_args::<Range>() {
976 Ok(v) => v,
977 Err(e) => {
978 validates.push(e.to_compile_error());
979 continue;
980 }
981 };
982 let cmp_value = inner.value.to_token_stream();
983 let code = match inner.code.base10_parse::<i64>() {
984 Ok(v) => v,
985 Err(e) => {
986 validates.push(
987 syn::Error::new_spanned(&inner.code, format!("invalid error code: {}", e))
988 .to_compile_error(),
989 );
990 continue;
991 }
992 };
993 let err_msg = inner
994 .msg
995 .value()
996 .replace("${field}", &field_name.to_string());
997 if is_option_type(field_type) {
998 validates.push(quote! {
999 if let Some(ref __val) = #field_name {
1000 if *__val < #cmp_value {
1001 return Err(::afastdata::Error::validate(#code, #err_msg.to_string()));
1002 }
1003 }
1004 });
1005 } else {
1006 validates.push(quote! {
1007 if #field_name < #cmp_value {
1008 return Err(::afastdata::Error::validate(#code, #err_msg.to_string()));
1009 }
1010 });
1011 }
1012 } else if meta.path.is_ident("lt") {
1013 if !is_comparable_type(field_type) {
1014 validates.push(
1015 syn::Error::new_spanned(
1016 &meta.path,
1017 format!(
1018 "validation `lt` is only supported on numeric types (or Option<numeric>), but field `{}` is not",
1019 field_name
1020 ),
1021 )
1022 .to_compile_error(),
1023 );
1024 continue;
1025 }
1026 let inner = match meta.parse_args::<Range>() {
1027 Ok(v) => v,
1028 Err(e) => {
1029 validates.push(e.to_compile_error());
1030 continue;
1031 }
1032 };
1033 let cmp_value = inner.value.to_token_stream();
1034 let code = match inner.code.base10_parse::<i64>() {
1035 Ok(v) => v,
1036 Err(e) => {
1037 validates.push(
1038 syn::Error::new_spanned(&inner.code, format!("invalid error code: {}", e))
1039 .to_compile_error(),
1040 );
1041 continue;
1042 }
1043 };
1044 let err_msg = inner
1045 .msg
1046 .value()
1047 .replace("${field}", &field_name.to_string());
1048 if is_option_type(field_type) {
1049 validates.push(quote! {
1050 if let Some(ref __val) = #field_name {
1051 if *__val >= #cmp_value {
1052 return Err(::afastdata::Error::validate(#code, #err_msg.to_string()));
1053 }
1054 }
1055 });
1056 } else {
1057 validates.push(quote! {
1058 if #field_name >= #cmp_value {
1059 return Err(::afastdata::Error::validate(#code, #err_msg.to_string()));
1060 }
1061 });
1062 }
1063 } else if meta.path.is_ident("lte") {
1064 if !is_comparable_type(field_type) {
1065 validates.push(
1066 syn::Error::new_spanned(
1067 &meta.path,
1068 format!(
1069 "validation `lte` is only supported on numeric types (or Option<numeric>), but field `{}` is not",
1070 field_name
1071 ),
1072 )
1073 .to_compile_error(),
1074 );
1075 continue;
1076 }
1077 let inner = match meta.parse_args::<Range>() {
1078 Ok(v) => v,
1079 Err(e) => {
1080 validates.push(e.to_compile_error());
1081 continue;
1082 }
1083 };
1084 let cmp_value = inner.value.to_token_stream();
1085 let code = match inner.code.base10_parse::<i64>() {
1086 Ok(v) => v,
1087 Err(e) => {
1088 validates.push(
1089 syn::Error::new_spanned(&inner.code, format!("invalid error code: {}", e))
1090 .to_compile_error(),
1091 );
1092 continue;
1093 }
1094 };
1095 let err_msg = inner
1096 .msg
1097 .value()
1098 .replace("${field}", &field_name.to_string());
1099 if is_option_type(field_type) {
1100 validates.push(quote! {
1101 if let Some(ref __val) = #field_name {
1102 if *__val > #cmp_value {
1103 return Err(::afastdata::Error::validate(#code, #err_msg.to_string()));
1104 }
1105 }
1106 });
1107 } else {
1108 validates.push(quote! {
1109 if #field_name > #cmp_value {
1110 return Err(::afastdata::Error::validate(#code, #err_msg.to_string()));
1111 }
1112 });
1113 }
1114 } else if meta.path.is_ident("len") {
1115 let field_is_option = is_option_type(field_type);
1116 // For Option<T>, check if inner type is a collection
1117 // For non-Option, check directly
1118 if field_is_option {
1119 // Option<T> is allowed - inner type check is deferred to runtime
1120 } else if !is_collection_type(field_type) {
1121 validates.push(
1122 syn::Error::new_spanned(
1123 &meta.path,
1124 format!(
1125 "validation `len` is only supported on String, &[u8], Vec<T>, [T; N], or Option<T> wrapping these types, but field `{}` is not",
1126 field_name
1127 ),
1128 )
1129 .to_compile_error(),
1130 );
1131 continue;
1132 }
1133
1134 let inner = match meta.parse_args::<Length>() {
1135 Ok(v) => v,
1136 Err(e) => {
1137 validates.push(e.to_compile_error());
1138 continue;
1139 }
1140 };
1141 let min_value = match inner.min.base10_parse::<i64>() {
1142 Ok(v) => v,
1143 Err(e) => {
1144 validates.push(
1145 syn::Error::new_spanned(&inner.min, format!("invalid min value: {}", e))
1146 .to_compile_error(),
1147 );
1148 continue;
1149 }
1150 };
1151 let max_value = match inner.max.base10_parse::<i64>() {
1152 Ok(v) => v,
1153 Err(e) => {
1154 validates.push(
1155 syn::Error::new_spanned(&inner.max, format!("invalid max value: {}", e))
1156 .to_compile_error(),
1157 );
1158 continue;
1159 }
1160 };
1161 let code = match inner.code.base10_parse::<i64>() {
1162 Ok(v) => v,
1163 Err(e) => {
1164 validates.push(
1165 syn::Error::new_spanned(&inner.code, format!("invalid error code: {}", e))
1166 .to_compile_error(),
1167 );
1168 continue;
1169 }
1170 };
1171 let err_msg = inner
1172 .msg
1173 .value()
1174 .replace("${field}", &field_name.to_string());
1175 // -1 is a sentinel meaning "no limit", so skip range check when either is -1
1176 if min_value >= 0 && max_value >= 0 && min_value > max_value {
1177 validates.push(
1178 syn::Error::new_spanned(
1179 &meta.path,
1180 format!(
1181 "invalid len validation: min ({}) > max ({}) for field `{}`",
1182 min_value, max_value, field_name
1183 ),
1184 )
1185 .to_compile_error(),
1186 );
1187 continue;
1188 }
1189 if min_value < 0 && max_value < 0 {
1190 validates.push(
1191 syn::Error::new_spanned(
1192 &meta.path,
1193 format!(
1194 "invalid len validation: both min and max are negative for field `{}`",
1195 field_name
1196 ),
1197 )
1198 .to_compile_error(),
1199 );
1200 continue;
1201 } else if min_value < 0 {
1202 let max: usize = match max_value.try_into() {
1203 Ok(v) => v,
1204 Err(_) => {
1205 validates.push(
1206 syn::Error::new_spanned(&inner.max, "value too large for usize")
1207 .to_compile_error(),
1208 );
1209 continue;
1210 }
1211 };
1212 if field_is_option {
1213 validates.push(quote! {
1214 if let Some(ref __val) = #field_name {
1215 if __val.len() > #max {
1216 return Err(::afastdata::Error::validate(#code, #err_msg.to_string()));
1217 }
1218 }
1219 });
1220 } else {
1221 validates.push(quote! {
1222 if #field_name.len() > #max {
1223 return Err(::afastdata::Error::validate(#code, #err_msg.to_string()));
1224 }
1225 });
1226 }
1227 } else if max_value < 0 {
1228 let min: usize = match min_value.try_into() {
1229 Ok(v) => v,
1230 Err(_) => {
1231 validates.push(
1232 syn::Error::new_spanned(&inner.min, "value too large for usize")
1233 .to_compile_error(),
1234 );
1235 continue;
1236 }
1237 };
1238 if field_is_option {
1239 validates.push(quote! {
1240 if let Some(ref __val) = #field_name {
1241 if __val.len() < #min {
1242 return Err(::afastdata::Error::validate(#code, #err_msg.to_string()));
1243 }
1244 }
1245 });
1246 } else {
1247 validates.push(quote! {
1248 if #field_name.len() < #min {
1249 return Err(::afastdata::Error::validate(#code, #err_msg.to_string()));
1250 }
1251 });
1252 }
1253 } else {
1254 let min: usize = match min_value.try_into() {
1255 Ok(v) => v,
1256 Err(_) => {
1257 validates.push(
1258 syn::Error::new_spanned(&inner.min, "value too large for usize")
1259 .to_compile_error(),
1260 );
1261 continue;
1262 }
1263 };
1264 let max: usize = match max_value.try_into() {
1265 Ok(v) => v,
1266 Err(_) => {
1267 validates.push(
1268 syn::Error::new_spanned(&inner.max, "value too large for usize")
1269 .to_compile_error(),
1270 );
1271 continue;
1272 }
1273 };
1274 if field_is_option {
1275 validates.push(quote! {
1276 let length = match &#field_name {
1277 Some(s) => {
1278 let __length = s.len();
1279 if __length < #min || __length > #max {
1280 return Err(::afastdata::Error::validate(#code, #err_msg.to_string()));
1281 }
1282 },
1283 None => {},
1284 };
1285 });
1286 } else {
1287 validates.push(quote! {
1288 if #field_name.len() < #min || #field_name.len() > #max {
1289 return Err(::afastdata::Error::validate(#code, #err_msg.to_string()));
1290 }
1291 });
1292 }
1293 }
1294 } else if meta.path.is_ident("of") {
1295 let inner = match meta.parse_args::<OfValidator>() {
1296 Ok(v) => v,
1297 Err(e) => {
1298 validates.push(e.to_compile_error());
1299 continue;
1300 }
1301 };
1302 let allowed_values = inner.allowed_values.clone();
1303 let code = match inner.code.base10_parse::<i64>() {
1304 Ok(v) => v,
1305 Err(e) => {
1306 validates.push(
1307 syn::Error::new_spanned(&inner.code, format!("invalid error code: {}", e))
1308 .to_compile_error(),
1309 );
1310 continue;
1311 }
1312 };
1313 let err_msg = inner
1314 .msg
1315 .value()
1316 .replace("${field}", &field_name.to_string());
1317 let values_tokens: Vec<_> = allowed_values
1318 .iter()
1319 .map(|v| v.to_token_stream())
1320 .collect();
1321 validates.push(quote! {
1322 if !matches!(#field_name, #(#values_tokens)|*) {
1323 return Err(::afastdata::Error::validate(#code, #err_msg.to_string()));
1324 }
1325 });
1326 } else if meta.path.is_ident("func") {
1327 let inner = match meta.parse_args::<LitStr>() {
1328 Ok(v) => v,
1329 Err(e) => {
1330 validates.push(e.to_compile_error());
1331 continue;
1332 }
1333 };
1334 let ident = match syn::parse_str::<syn::Ident>(&inner.value()) {
1335 Ok(v) => v,
1336 Err(e) => {
1337 validates.push(
1338 syn::Error::new_spanned(
1339 &inner,
1340 format!("invalid function name `{}`: {}", inner.value(), e),
1341 )
1342 .to_compile_error(),
1343 );
1344 continue;
1345 }
1346 };
1347 let field = field_name.to_string();
1348 validates.push(quote! {
1349 match #ident(&#field_name, #field) {
1350 Ok(()) => {},
1351 Err(e) => return Err(e.to_afastdata_error()),
1352 }
1353 });
1354 }
1355 }
1356 }
1357 }
1358 }
1359 validates
1360}
1361
1362/// 为结构体的字段生成反序列化代码以及构造表达式。内部辅助函数。
1363///
1364/// Generates deserialization code for struct fields along with the construction
1365/// expression. Internal helper.
1366///
1367/// # 参数 / Parameters
1368///
1369/// - `fields`:结构体的字段定义 / The struct's field definitions
1370/// - `name`:结构体类型的标识符 / The struct type's identifier
1371/// - `ty_generics`:类型的泛型参数(用于构造时的 turbofish 语法)
1372/// / The type's generic parameters (used for turbofish syntax during construction)
1373///
1374/// # 返回值 / Returns
1375///
1376/// 返回 `(构造表达式, 反序列化语句列表)`:
1377/// - 构造表达式:用于创建结构体实例的 `TokenStream`
1378/// - 反序列化语句:每个字段的 `from_bytes()` 调用和偏移量更新
1379///
1380/// Returns `(construction_expression, deserialization_statements)`:
1381/// - Construction expression: A `TokenStream` for creating the struct instance
1382/// - Deserialization statements: `from_bytes()` calls and offset updates for each field
1383///
1384/// # 泛型构造 / Generic Construction
1385///
1386/// 使用 `as_turbofish()` 生成正确的泛型语法。例如 `MyStruct::<T>` 而非
1387/// `MyStruct <T>`(后者会被解析为比较操作)。
1388///
1389/// Uses `as_turbofish()` to generate correct generic syntax. For example,
1390/// `MyStruct::<T>` instead of `MyStruct <T>` (which would be parsed as a
1391/// comparison operation).
1392fn generate_deserialize_fields(
1393 fields: &Fields,
1394 name: &syn::Ident,
1395 ty_generics: &syn::TypeGenerics,
1396) -> (proc_macro2::TokenStream, Vec<proc_macro2::TokenStream>) {
1397 // 在表达式上下文中使用 turbofish 语法:Name::<T>
1398 // In expression context, use turbofish syntax: Name::<T>
1399 let ty_params = ty_generics.as_turbofish();
1400 match fields {
1401 Fields::Named(named) => {
1402 let mut desers = Vec::new();
1403 let mut field_names = Vec::new();
1404 for f in &named.named {
1405 let fname = f.ident.as_ref().unwrap();
1406 let ftype = &f.ty;
1407 field_names.push(fname.clone());
1408
1409 let validates = parse_validations(fname, ftype, &f.attrs);
1410 let (skip, default) = has_skip_attr(&f.attrs);
1411 if skip {
1412 if let Some(default) = default {
1413 match syn::parse_str::<syn::Ident>(&default) {
1414 Ok(ident) => {
1415 desers.push(quote! {
1416 let #fname: #ftype = #ident();
1417 });
1418 }
1419 Err(_) => {
1420 desers.push(quote! {
1421 compile_error!(concat!("invalid function name in skip: ", #default));
1422 });
1423 }
1424 }
1425 } else {
1426 desers.push(quote! {
1427 let #fname: #ftype = #ftype::default();
1428 });
1429 }
1430 } else {
1431 desers.push(quote! {
1432 let (__val, __new_offset) = ::afastdata::AFastDeserialize::from_bytes(&data[offset..])?;
1433 let #fname: #ftype = __val;
1434 #(#validates)*
1435 offset += __new_offset;
1436 });
1437 }
1438 }
1439 let construct = quote! {
1440 #name #ty_params { #(#field_names),* }
1441 };
1442 (construct, desers)
1443 }
1444 Fields::Unnamed(unnamed) => {
1445 let mut desers = Vec::new();
1446 let mut field_names = Vec::new();
1447 for (i, f) in unnamed.unnamed.iter().enumerate() {
1448 let fname = syn::Ident::new(&format!("__f{}", i), name.span());
1449 let ftype = &f.ty;
1450 let (skip, default_fn) = has_skip_attr(&f.attrs);
1451 if skip {
1452 if let Some(func_name) = default_fn {
1453 match syn::parse_str::<syn::Ident>(&func_name) {
1454 Ok(ident) => {
1455 desers.push(quote! {
1456 let #fname: #ftype = #ident();
1457 });
1458 }
1459 Err(_) => {
1460 desers.push(quote! {
1461 compile_error!(concat!("invalid function name in skip: ", #func_name));
1462 });
1463 }
1464 }
1465 } else {
1466 desers.push(quote! {
1467 let #fname: #ftype = <#ftype as ::std::default::Default>::default();
1468 });
1469 }
1470 } else {
1471 let validates = parse_validations(&fname, ftype, &f.attrs);
1472 desers.push(quote! {
1473 let (__val, __new_offset) = ::afastdata::AFastDeserialize::from_bytes(&data[offset..])?;
1474 let #fname: #ftype = __val;
1475 #(#validates)*
1476 offset += __new_offset;
1477 });
1478 }
1479 field_names.push(fname);
1480 }
1481 let construct = quote! {
1482 #name #ty_params ( #(#field_names),* )
1483 };
1484 (construct, desers)
1485 }
1486 Fields::Unit => {
1487 let construct = quote! { #name #ty_params };
1488 (construct, vec![])
1489 }
1490 }
1491}