alox_48_derive/lib.rs
1#![warn(rust_2018_idioms, clippy::all, clippy::pedantic)]
2use proc_macro::TokenStream;
3
4use syn::DeriveInput;
5
6mod de;
7mod ser;
8mod util;
9
10use darling::{
11 util::{Flag, Override},
12 FromDeriveInput,
13};
14use syn::{Ident, LitStr, Path, Type};
15
16#[derive(Debug, FromDeriveInput)]
17#[darling(attributes(marshal))]
18#[darling(supports(struct_any, enum_any))]
19struct TypeReciever {
20 ident: Ident,
21 data: darling::ast::Data<VariantReciever, FieldReciever>,
22
23 generics: syn::Generics,
24
25 alox_crate_path: Option<Path>,
26
27 class: Option<String>,
28
29 deny_unknown_fields: Flag,
30 enforce_class: Flag,
31
32 #[darling(rename = "default")]
33 default_fn: Option<Override<Path>>,
34 #[darling(rename = "from")]
35 from_type: Option<Type>,
36 #[darling(rename = "into")]
37 into_type: Option<Type>,
38 #[darling(rename = "try_from")]
39 try_from_type: Option<Type>,
40 #[darling(rename = "try_into")]
41 try_into_type: Option<Type>,
42
43 expecting: Option<String>,
44}
45
46#[derive(Debug, darling::FromField)]
47#[darling(attributes(marshal))]
48struct FieldReciever {
49 ident: Option<Ident>,
50 ty: Type,
51
52 rename: Option<LitStr>,
53
54 #[darling(rename = "default")]
55 default_fn: Option<Override<Path>>,
56
57 skip: Flag,
58 skip_serializing: Flag,
59 skip_deserializing: Flag,
60 byte_string: Flag,
61
62 #[darling(rename = "deserialize_with")]
63 deserialize_with_fn: Option<Path>,
64 #[darling(rename = "serialize_with")]
65 serialize_with_fn: Option<Path>,
66 #[darling(rename = "with")]
67 with_module: Option<Path>,
68}
69
70#[allow(dead_code)]
71#[derive(Debug, darling::FromVariant)]
72struct VariantReciever {
73 ident: Ident,
74 fields: darling::ast::Fields<FieldReciever>,
75
76 transparent: Flag,
77 class: Option<String>,
78}
79
80/// Derive `Deserialize` for a struct.
81///
82/// Does not currently support enums.
83///
84/// Type attributes:
85/// - `alox_crate_path`: The path to the alox-48 crate.
86/// - `class`: Override the class that the class enforcer checks for. By default, the class of structs is the struct name.
87/// - `deny_unknown_fields`: If set, the deserializer will error if it encounters a field not in the struct.
88/// - `enforce_class`: If set, the deserializer will enforce that the class matches.
89/// - `default`: The default function to use for a field. Leave empty to use `Default::default`.
90/// - `from`: Deserialize from a different type. That type must implement `Deserialize`.
91/// - `try_from`: Deserialize from a different type. That type must implement `TryFrom`, and its error type must implement `Display`.
92/// - `expecting`: The error message to use if deserialization fails.
93///
94/// Field attributes:
95/// - `rename`: Rename the field.
96/// - `default`: The default function to use for a field. Leave empty to use `Default::default`.
97/// - `skip` or `skip_deserializing`: Skip deserializing the field.
98/// - `deserialize_with`: Use a custom function to deserialize the field. That function must have the signature `fn(impl Deserializer<'de>) -> Result<T, DeError>`.
99/// - `with`: Like `deserialize_with`, but the function is in a module.
100#[proc_macro_derive(Deserialize, attributes(marshal))]
101pub fn derive_deserialize(item: TokenStream) -> TokenStream {
102 let input = syn::parse_macro_input!(item as DeriveInput);
103
104 de::derive_inner(&input).into()
105}
106
107/// Derive `Serialize` for a struct.
108///
109/// Does not currently support enums.
110///
111/// Type attributes:
112/// - `alox_crate_path`: The path to the alox-48 crate.
113/// - `class`: Override the class that this type is serialized as. By default, the class is the struct name.
114/// - `into`: Serialize to a different type. That type must implement `Serialize`, and `Self` must impl `Into<T> + Clone`.
115/// - `try_into`: Serialize to a different type. That type must implement `Serialize`, and Self must impl `TryInto<T> + Clone`.
116///
117/// Field attributes:
118/// - `rename`: Rename the field.
119/// - `skip` or `skip_serializing`: Skip serializing the field.
120/// - `serialize_with`: Use a custom function to serialize the field. That function must have the signature `fn(&T, impl Serializer) -> Result<S::Ok, SerError>`.
121/// - `with`: Like `serialize_with`, but the function is in a module.
122#[proc_macro_derive(Serialize, attributes(marshal))]
123pub fn derive_serialize(item: TokenStream) -> TokenStream {
124 let input = syn::parse_macro_input!(item as DeriveInput);
125
126 ser::derive_inner(&input).into()
127}
128
129// TODO tests