1 use darling::{FromDeriveInput, FromField, FromMeta, FromVariant};
2 use proc_macro::TokenStream;
3 use proc_macro2::TokenStream as TokStr;
4 use quote::{quote, ToTokens};
5 use syn::{parse_macro_input, parse_quote};
7 #[derive(Debug, FromMeta, Copy, Clone, Eq, PartialEq)]
8 #[darling(rename_all = "snake_case")]
14 #[derive(Debug, FromMeta)]
17 repr: Option<syn::Type>,
19 content: Option<String>,
26 fn wrap_attr(attr: &mut syn::Attribute) {
27 match attr.path.get_ident().map(|i| i.to_string()).as_deref() {
29 let path = attr.path.clone();
30 let tokens = attr.tokens.clone();
32 *attr = parse_quote! {
33 #[cfg_attr(any(feature = "client", feature = "server"), #path #tokens)]
37 let path = attr.path.clone();
38 let tokens = attr.tokens.clone();
40 *attr = parse_quote! {
41 #[cfg_attr(feature = "serde", #path #tokens)]
48 #[proc_macro_attribute]
49 pub fn mt_derive(attr: TokenStream, item: TokenStream) -> TokenStream {
50 let item2 = item.clone();
52 let attr_args = parse_macro_input!(attr as syn::AttributeArgs);
53 let mut input = parse_macro_input!(item2 as syn::Item);
55 let args = match MacroArgs::from_list(&attr_args) {
58 return TokenStream::from(e.write_errors());
62 let (serializer, deserializer) = match args.to {
63 To::Clt => ("server", "client"),
64 To::Srv => ("client", "server"),
67 let mut out = quote! {
69 #[cfg_attr(feature = "random", derive(GenerateRandom))]
70 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
74 ($t:expr, $f:expr) => {
75 $t.iter_mut().for_each($f)
80 syn::Item::Enum(e) => {
81 iter!(e.attrs, wrap_attr);
82 iter!(e.variants, |v| {
83 iter!(v.attrs, wrap_attr);
84 iter!(v.fields, |f| iter!(f.attrs, wrap_attr));
87 let repr = args.repr.expect("missing repr for enum");
90 let repr_str = repr.to_token_stream().to_string();
93 #[derive(EnumSetType)]
94 #[enumset(repr = #repr_str, serialize_as_map)]
100 .find_map(|v| if v.fields.is_empty() { None } else { Some(()) })
104 let tag = args.tag.expect("missing tag for enum with payload");
107 #[cfg_attr(feature = "serde", serde(tag = #tag))]
110 if let Some(content) = args.content {
112 #[cfg_attr(feature = "serde", serde(content = #content))]
123 #[derive(Clone, PartialEq)]
128 #[cfg_attr(feature = #serializer, derive(MtSerialize))]
129 #[cfg_attr(feature = #deserializer, derive(MtDeserialize))]
135 #[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
138 syn::Item::Struct(s) => {
139 iter!(s.attrs, wrap_attr);
140 iter!(s.fields, |f| iter!(f.attrs, wrap_attr));
143 #[derive(Clone, PartialEq)]
148 #[cfg_attr(feature = #serializer, derive(MtSerialize))]
149 #[cfg_attr(feature = #deserializer, derive(MtDeserialize))]
153 _ => panic!("only enum and struct supported"),
156 out.extend(input.to_token_stream());
160 #[derive(Debug, Default, FromDeriveInput, FromVariant, FromField)]
161 #[darling(attributes(mt))]
165 const16: Option<u16>,
166 const32: Option<u32>,
167 const64: Option<u64>,
183 fn get_cfg(args: &MtArgs) -> syn::Type {
184 let mut ty: syn::Type = parse_quote! { mt_data::DefCfg };
187 ty = parse_quote! { mt_data::NoLen };
190 macro_rules! impl_len {
191 ($name:ident, $T:ty) => {
193 ty = parse_quote! { $T };
199 impl_len!(len16, u16);
200 impl_len!(len32, u32);
201 impl_len!(len64, u64);
204 ty = parse_quote! { mt_data::Utf16<#ty> };
211 fn is_ident(path: &syn::Path, ident: &str) -> bool {
212 matches!(path.segments.first().map(|p| &p.ident), Some(idt) if idt == ident)
215 fn get_type_generics<const N: usize>(path: &syn::Path) -> Option<[&syn::Type; N]> {
216 use syn::{AngleBracketedGenericArguments as Args, PathArguments::AngleBracketed};
220 .map(|seg| match &seg.arguments {
221 AngleBracketed(Args { args, .. }) => args
223 .flat_map(|arg| match arg {
224 syn::GenericArgument::Type(t) => Some(t),
236 type Fields<'a> = Vec<(TokStr, &'a syn::Field)>;
238 fn get_fields(fields: &syn::Fields, ident: impl Fn(TokStr) -> TokStr) -> Fields {
240 syn::Fields::Named(fs) => fs
243 .map(|f| (ident(f.ident.as_ref().unwrap().to_token_stream()), f))
245 syn::Fields::Unnamed(fs) => fs
249 .map(|(i, f)| (ident(i.to_string().to_token_stream()), f))
251 syn::Fields::Unit => Vec::new(),
255 fn serialize_args(res: darling::Result<MtArgs>, body: impl FnOnce(&MtArgs) -> TokStr) -> TokStr {
258 let mut code = TokStr::new();
260 macro_rules! impl_const {
262 if let Some(x) = args.$name {
264 #x.mt_serialize::<mt_data::DefCfg>(__writer)?;
271 impl_const!(const16);
272 impl_const!(const32);
273 impl_const!(const64);
275 code.extend(body(&args));
280 let mut __stream = mt_data::flate2::write::ZlibEncoder::new(__writer, flate2::Compression::default());
281 let __writer = &mut __stream;
288 macro_rules! impl_size {
289 ($name:ident, $T:ty) => {
292 mt_data::MtSerialize::mt_serialize::<$T>(&{
293 let mut __buf = Vec::new();
294 let __writer = &mut __buf;
303 impl_size!(size8, u8);
304 impl_size!(size16, u16);
305 impl_size!(size32, u32);
306 impl_size!(size64, u64);
310 Err(e) => return e.write_errors(),
314 fn serialize_fields(fields: &Fields) -> TokStr {
317 .map(|(ident, field)| {
318 serialize_args(MtArgs::from_field(field), |args| {
319 let cfg = get_cfg(args);
320 quote! { mt_data::MtSerialize::mt_serialize::<#cfg>(#ident, __writer)?; }
326 #[proc_macro_derive(MtSerialize, attributes(mt))]
327 pub fn derive_serialize(input: TokenStream) -> TokenStream {
328 let input = parse_macro_input!(input as syn::DeriveInput);
329 let typename = &input.ident;
331 let code = serialize_args(MtArgs::from_derive_input(&input), |_| match &input.data {
332 syn::Data::Enum(e) => {
333 let repr: syn::Type = input
336 .find(|a| a.path.is_ident("repr"))
337 .expect("missing repr")
339 .expect("invalid repr");
341 let variants: TokStr = e.variants
343 .fold((parse_quote! { 0 }, TokStr::new()), |(discr, before), v| {
344 let discr = v.discriminant.clone().map(|x| x.1).unwrap_or(discr);
346 let ident_fn = match &v.fields {
347 syn::Fields::Unnamed(_) => |f| quote! {
348 mt_data::paste::paste! { [<field_ #f>] }
350 _ => |f| quote! { #f },
353 let fields = get_fields(&v.fields, ident_fn);
354 let fields_comma: TokStr = fields.iter()
355 .rfold(TokStr::new(), |after, (ident, _)| quote! { #ident, #after });
357 let destruct = match &v.fields {
358 syn::Fields::Named(_) => quote! { { #fields_comma } },
359 syn::Fields::Unnamed(_) => quote! { ( #fields_comma ) },
360 syn::Fields::Unit => TokStr::new(),
363 let code = serialize_args(MtArgs::from_variant(v), |_|
364 serialize_fields(&fields));
365 let variant = &v.ident;
368 parse_quote! { 1 + #discr },
371 #typename::#variant #destruct => {
372 mt_data::MtSerialize::mt_serialize::<mt_data::DefCfg>(&((#discr) as #repr), __writer)?;
385 syn::Data::Struct(s) => serialize_fields(&get_fields(&s.fields, |f| quote! { &self.#f })),
387 panic!("only enum and struct supported");
392 #[automatically_derived]
393 impl mt_data::MtSerialize for #typename {
394 fn mt_serialize<C: MtCfg>(&self, __writer: &mut impl std::io::Write) -> Result<(), mt_data::SerializeError> {
403 #[proc_macro_derive(MtDeserialize, attributes(mt))]
404 pub fn derive_deserialize(input: TokenStream) -> TokenStream {
405 let syn::DeriveInput {
407 } = parse_macro_input!(input);
409 #[automatically_derived]
410 impl mt_data::MtDeserialize for #typename {
411 fn mt_deserialize<C: MtCfg>(__reader: &mut impl std::io::Read) -> Result<Self, mt_data::DeserializeError> {
412 Err(mt_data::DeserializeError::Unimplemented)