minecraft_net_proc/
lib.rs

1extern crate proc_macro;
2mod types;
3
4use proc_macro2::TokenStream;
5use quote::{quote, ToTokens, TokenStreamExt};
6use syn::parse::{Parse, ParseStream};
7use syn::{braced, parse_macro_input, Attribute, Data, Lit, Meta, Token};
8use syn::{DeriveInput, Expr, LitInt, Path, PathArguments, PathSegment, Type};
9use crate::types::FieldType;
10
11struct FieldMacroInput {
12    attributes: Vec<Attribute>,
13    name: syn::Ident,
14    body: Vec<types::Field>,
15}
16impl Parse for FieldMacroInput {
17    fn parse(input: ParseStream) -> syn::Result<Self> {
18        let attributes = Attribute::parse_outer(input)?;
19        let name = input.parse::<syn::Ident>()?;
20        input.parse::<Token![,]>()?;
21        let raw_body;
22        braced!(raw_body in input);
23        let mut body = Vec::new();
24        while let Ok(f) = raw_body.parse::<types::Field>() {
25            if f.r#type.is_none() {
26                panic!("Field field type can't be None");
27            }
28            body.push(f);
29        }
30        Ok(Self { name, body, attributes })
31    }
32}
33impl ToTokens for FieldMacroInput {
34    fn to_tokens(&self, tokens: &mut TokenStream) {
35        let name = &self.name;
36        let attributes = &self.attributes;
37        if self.body.len() == 0 {
38            tokens.extend(quote! {
39                #(#attributes)*
40                #[derive(Debug, Clone)]
41                pub struct #name {}
42                impl crate::Field for #name {
43                    fn to_bytes(&self) -> Vec<u8> {Vec::new()}
44                    fn from_reader(reader: &mut crate::fields::PacketReader) -> crate::errors::Result<Self> {Ok(Self {})}
45                }
46                impl #name {
47                    pub fn new() -> Self {Self {}}
48                }
49            });
50            return;
51        }
52        let field_names = self.body.iter().map(|f| &f.name).collect::<Vec<_>>();
53        let field_types = self.body.iter().map(|f| &f.r#type).collect::<Vec<_>>();
54        let field_attributes = self.body.iter().map(|f| &f.attributes).collect::<Vec<_>>();
55        let encoders = self.body.iter().map(|f| f.get_struct_encoder()).collect::<Vec<_>>();
56        let decoders = self.body.iter().map(|f| f.get_struct_decoder()).collect::<Vec<_>>();
57        tokens.append_all(quote! {
58            #(#attributes)*
59            #[derive(Debug, Clone)]
60            pub struct #name {
61                #(
62                    #(#field_attributes)*
63                    pub #field_names: #field_types,
64                )*
65            }
66            impl crate::Field for #name {
67                fn to_bytes(&self) -> Vec<u8> {
68                    vec![#(#encoders,)*].iter().flatten().cloned().collect::<Vec<u8>>()
69                }
70                fn from_reader(reader: &mut crate::fields::PacketReader) -> crate::errors::Result<Self> {
71                    Ok(Self {
72                        #(#field_names: #decoders,)*
73                    })
74                }
75            }
76        });
77        tokens.extend(quote! {
78            impl #name {
79                pub fn new(#(#field_names: #field_types,)*) -> Self {
80                    Self {#(#field_names,)*}
81                }
82            }
83        })
84    }
85}
86#[proc_macro]
87#[allow(non_snake_case)]
88pub fn Field(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
89    let input = parse_macro_input!(input as FieldMacroInput);
90    input.to_token_stream().into()
91}
92
93struct PacketMacroInput {
94    name: syn::Ident,
95    id: syn::LitInt,
96    attributes: Vec<Attribute>,
97    body: Vec<types::Field>,
98}
99impl Parse for PacketMacroInput {
100    fn parse(input: ParseStream) -> syn::Result<Self> {
101        let attributes = Attribute::parse_outer(input)?;
102        let name = input.parse::<syn::Ident>()?;
103        input.parse::<Token![,]>()?;
104        let id = input.parse::<syn::LitInt>()?;
105        input.parse::<Token![,]>()?;
106        let raw_body;
107        braced!(raw_body in input);
108        let mut body = Vec::new();
109        while let Ok(f) = raw_body.parse::<types::Field>() {
110            if f.r#type.is_none() {
111                panic!("Packet field type can't be None");
112            }
113            body.push(f);
114        }
115        Ok(Self { name, id, body, attributes })
116    }
117}
118impl ToTokens for PacketMacroInput {
119    fn to_tokens(&self, tokens: &mut TokenStream) {
120        let name = &self.name;
121        let id = &self.id;
122        let attributes = &self.attributes;
123        if self.body.len() == 0 {
124            tokens.extend(quote! {
125                #(#attributes)*
126                #[derive(Debug, Clone)]
127                pub struct #name {}
128                impl crate::Packet for #name {
129                    const ID: i32 = #id;
130                    fn to_bytes(&self) -> Vec<u8> {Vec::new()}
131                    fn from_reader(reader: &mut crate::fields::PacketReader) -> crate::errors::Result<Self> {Ok(Self {})}
132                }
133                impl #name {
134                    pub fn new() -> Self {Self {}}
135                }
136            });
137            return;
138        }
139        let field_names = self.body.iter().map(|f| &f.name).collect::<Vec<_>>();
140        let field_types = self.body.iter().map(|f| &f.r#type).collect::<Vec<_>>();
141        let field_attributes = self.body.iter().map(|f| &f.attributes).collect::<Vec<_>>();
142        let encoders = self.body.iter().map(|f| f.get_struct_encoder()).collect::<Vec<_>>();
143        let decoders = self.body.iter().map(|f| f.get_struct_decoder()).collect::<Vec<_>>();
144        tokens.append_all(quote! {
145            #(#attributes)*
146            #[derive(Debug, Clone)]
147            pub struct #name {
148                
149                #(
150                    #(#field_attributes)*
151                    pub #field_names: #field_types,
152                )*
153            }
154            impl crate::Packet for #name {
155                const ID: i32 = #id;
156                fn to_bytes(&self) -> Vec<u8> {
157                    vec![#(#encoders,)*].iter().flatten().cloned().collect()
158                }
159                fn from_reader(reader: &mut crate::fields::PacketReader) -> crate::errors::Result<Self> {
160                    Ok(Self {
161                        #(#field_names: #decoders,)*
162                    })
163                }
164            }
165        });
166        tokens.extend(quote! {
167            impl #name {
168                pub fn new(#(#field_names: #field_types,)*) -> Self {
169                    Self {#(#field_names,)*}
170                }
171            }
172        })
173    }
174}
175#[proc_macro]
176#[allow(non_snake_case)]
177pub fn Packet(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
178    let input = parse_macro_input!(input as PacketMacroInput);
179    input.to_token_stream().into()
180}
181
182
183struct EnumMacroInput {
184    name: syn::Ident,
185    attributes: Vec<Attribute>,
186    body: Vec<types::Field>,
187}
188impl Parse for EnumMacroInput {
189    fn parse(input: ParseStream) -> syn::Result<Self> {
190        let attributes = Attribute::parse_outer(input)?;
191        let name = input.parse::<syn::Ident>()?;
192        input.parse::<Token![,]>()?;
193        let raw_body;
194        braced!(raw_body in input);
195        let mut body = Vec::new();
196        while let Ok(f) = raw_body.parse::<types::Field>() {
197            body.push(f);
198        }
199        Ok(Self { name, body, attributes })
200    }
201}
202impl ToTokens for EnumMacroInput {
203    fn to_tokens(&self, tokens: &mut TokenStream) {
204        let name = &self.name;
205        let attributes = &self.attributes;
206        if self.body.len() == 0 {
207            tokens.extend(quote! {
208                #(#attributes)*
209                #[derive(Debug, Clone)]
210                pub enum #name {}
211                impl crate::Field for #name {
212                    fn to_bytes(&self) -> Vec<u8> {compile_error!("can't convert empty enum to bytes")}
213                    fn from_reader(reader: &mut crate::fields::PacketReader) -> crate::errors::Result<Self> {compile_error!("can't convert empty enum to bytes")}
214                }
215                impl crate::Field for #name {
216                    pub fn new() -> Self {Self {}}
217                }
218            });
219            return;
220        }
221        if self.body.len() > i32::MAX as usize {
222            panic!("can't encode an enum with more options than an Integer. How did you even get here?")
223        }
224        let field_names = self.body.iter().map(|f| &f.name).collect::<Vec<_>>();
225        let field_types = self.body.iter().map(|f| match &f.r#type {
226            FieldType::None => quote! {},
227            v => quote!{(#v)},
228        }).collect::<Vec<_>>();
229        let field_attributes = self.body.iter().map(|f| &f.attributes).collect::<Vec<_>>();
230        let encoders = self.body.iter()
231            .enumerate().map(|(i, f)| match std::panic::catch_unwind(|| {
232                f.get_enum_encoder(i)}) {
233                Err(e) => {eprintln!("error while parsing {}", self.name); std::panic::resume_unwind(e)},
234                Ok(v) => v,
235            })
236            .collect::<Vec<_>>();
237        let decoders = self.body.iter()
238            .enumerate()
239            .map(|(i, f)| f.get_enum_decoder(i))
240            .collect::<Vec<_>>();
241        tokens.extend(quote! {
242            #(#attributes)*
243            #[derive(Debug, Clone)]
244            pub enum #name {
245                #(
246                    #(#field_attributes)*
247                    #field_names #field_types,
248                )*
249            }
250            impl crate::Field for #name {
251                fn to_bytes(&self) -> Vec<u8> {
252                    match self.clone() {
253                        #(#encoders,)*
254                    }
255                }
256                fn from_reader(reader: &mut crate::fields::PacketReader) -> crate::errors::Result<Self> {
257                    Ok(match reader.read_var_int()? {
258                        #(#decoders,)*
259                        v => return Err(crate::errors::Errors::InvalidEnum(format!("Integer {v} is outside of range for enum"))),
260                    })
261                }
262            }
263        })
264    }
265}
266#[proc_macro]
267#[allow(non_snake_case)]
268pub fn VarIntEnum(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
269    parse_macro_input!(input as EnumMacroInput).to_token_stream().into()
270}
271
272
273#[proc_macro_derive(Packet_old, attributes(id, len, Var, Const, when))]
274pub fn derive_packet(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
275    // Parse the input tokens into a syntax tree
276    let ast: DeriveInput = syn::parse(input).unwrap();
277
278    let id = get_packet_id(&ast.attrs);
279    let name = &ast.ident;
280    let Data::Struct(s) = &ast.data else {
281        panic!("Can only be used for structs");
282    };
283
284    let mut field_encoders = Vec::with_capacity(s.fields.len());
285    let mut field_decoders = Vec::with_capacity(s.fields.len());
286    let mut field_names = Vec::with_capacity(s.fields.len());
287    for field in &s.fields {
288        let field_name = field.ident.clone().expect("unnamed fields");
289        let field_type = &field.ty;
290        field_names.push(field_name.clone());
291        let (encoder, decoder) = get_encoder_and_decoder_for_field(field_type, quote! {self.#field_name}, &field.attrs);
292        let decoder = quote! {let #field_name = #decoder};
293        field_encoders.push(encoder);
294        field_decoders.push(decoder);
295    };
296
297    let res = quote! {
298        impl crate::Packet for #name {
299            const ID: i32 = #id;
300            fn to_bytes(&self) -> Vec<u8> {
301                let vector: Vec<Vec<u8>> = vec![
302                    #(#field_encoders),*
303                ];
304                vector.iter().flatten().cloned().collect()
305            }
306            fn from_reader(reader: &mut crate::fields::PacketReader) -> crate::Result<Self> {
307                #(#field_decoders);*;
308                Ok(Self {
309                    #(#field_names),*
310                })
311            }
312        }
313    };
314    res.into()
315}
316
317#[proc_macro_derive(Field_old, attributes(len, Var, Const, when))]
318pub fn derive_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
319    // Parse the input tokens into a syntax tree
320    let ast: DeriveInput = syn::parse(input).unwrap();
321
322    let name = &ast.ident;
323    let Data::Struct(s) = &ast.data else {
324        panic!("Can only be used for structs");
325    };
326
327    let mut field_encoders = Vec::with_capacity(s.fields.len());
328    let mut field_decoders = Vec::with_capacity(s.fields.len());
329    let mut field_names = Vec::with_capacity(s.fields.len());
330    for field in &s.fields {
331        let field_name = field.ident.clone().expect("unnamed fields");
332        let field_type = &field.ty;
333        field_names.push(field_name.clone());
334        let (encoder, decoder) = get_encoder_and_decoder_for_field(field_type, quote! {self.#field_name}, &field.attrs);
335        let decoder = quote! {let #field_name = #decoder};
336        field_encoders.push(encoder);
337        field_decoders.push(decoder);
338    };
339
340    let res = quote! {
341        impl crate::Field for #name {
342            fn to_bytes(&self) -> Vec<u8> {
343                let vector: Vec<Vec<u8>> = vec![
344                    #(#field_encoders),*
345                ];
346                vector.iter().flatten().cloned().collect()
347            }
348                fn from_reader(reader: &mut crate::fields::PacketReader) -> crate::Result<Self> {
349                #(#field_decoders);*;
350                Ok(Self {
351                    #(#field_names),*
352                })
353            }
354        }
355    };
356    res.into()
357}
358fn get_packet_id(attrs: &[Attribute]) -> &LitInt {
359    for attr in attrs {
360        let Meta::NameValue(name_value) = &attr.meta else {
361            continue;
362        };
363        if !name_value.path.is_ident("id") {continue}
364        let Expr::Lit(lit) = &name_value.value else {
365            panic!("id must a literal")
366        };
367        let Lit::Int(int) = &lit.lit else {
368            panic!("id must be an integer")
369        };
370        return int;
371    }
372    panic!("requires id attribute for struct");
373}
374
375fn get_encoder_and_decoder_for_field(field_type: &Type, val_ref: impl ToTokens + Clone, attrs: &[Attribute]) -> (TokenStream, TokenStream) {
376    let path = match field_type {
377        Type::Paren(type_paren) => return get_encoder_and_decoder_for_field(&type_paren.elem, val_ref, attrs),
378        Type::Path(path) => &path.path,
379        t => panic!("invalid field type: {}", t.to_token_stream().to_string()),
380    };
381    let segment = path.segments.last().unwrap();
382    let ident = &segment.ident;
383    
384    match ident.to_string().as_ref() {
385        "bool" => (quote! { crate::fields::encode_bool(#val_ref) }, quote! { reader.read_bool()? }),
386        "u8" => (quote! { crate::fields::encode_ubyte(#val_ref) }, quote! { reader.read_ubyte() }),
387        "i8" => (quote! { crate::fields::encode_byte(#val_ref) }, quote! { reader.read_byte() }),
388        "u16" => (quote! { crate::fields::encode_ushort(#val_ref) }, quote! { reader.read_ushort() }),
389        "i16" => (quote! { crate::fields::encode_short(#val_ref) }, quote! { reader.read_short() }),
390        "i32" => handle_int(attrs, val_ref),
391        "i64" => handle_long(attrs, val_ref),
392        "u128" => (quote! { crate::fields::encode_uuid(#val_ref) }, quote! { reader.read_uuid() }),
393        "f32" => (quote! { crate::fields::encode_float(#val_ref) }, quote! { reader.read_float() }),
394        "f64" => (quote! { crate::fields::encode_double(#val_ref) }, quote! { reader.read_double() }),
395        "String" => (quote! { crate::fields::encode_string(#val_ref .clone()) }, quote! { reader.read_string()? }),
396        
397        "Byte" => (quote! { crate::fields::encode_byte(#val_ref) }, quote! { reader.read_byte() }),
398        "UByte" => (quote! { crate::fields::encode_ubyte(#val_ref) }, quote! { reader.read_ubyte() }),
399        "Short" => (quote! { crate::fields::encode_short(#val_ref) }, quote! { reader.read_short() }),
400        "UShort" => (quote! { crate::fields::encode_ushort(#val_ref) }, quote! { reader.read_ushort() }),
401        "Int" => (quote! { crate::fields::encode_int(#val_ref) }, quote! { reader.read_int() }),
402        "UInt" => (quote! { crate::fields::encode_uint(#val_ref) }, quote! { reader.read_uint() }),
403        "Long" => (quote! { crate::fields::encode_long(#val_ref) }, quote! { reader.read_long() }),
404        "UUID" => (quote! { crate::fields::encode_uuid(#val_ref) }, quote! { reader.read_uuid() }),
405        "Float" => (quote! { crate::fields::encode_float(#val_ref) }, quote! { reader.read_float() }),
406        "Double" => (quote! { crate::fields::encode_double(#val_ref) }, quote! { reader.read_double() }),
407        
408        "Identifier" => (quote! { crate::fields::encode_identifier(#val_ref .clone()) }, quote! { reader.read_identifier()? }),
409        "Angle" => (quote! { crate::fields::encode_angle(#val_ref) }, quote! { reader.read_angle() }),
410        "VarInt" => (quote! { crate::fields::encode_var_int(#val_ref) }, quote! { reader.read_var_int()? }),
411        "VarLong" => (quote! { crate::fields::encode_var_long(#val_ref) }, quote! { reader.read_var_long()? }),
412        "PrefixedArray" => handle_prefixed_array(segment, val_ref, attrs),
413        "PrefixedOptional" => handle_prefixed_option(segment, val_ref, attrs),
414        
415        _ => if ident == "Vec" {
416            handle_vec(segment, val_ref, attrs)
417        } else if ident == "Option" {
418            handle_option(segment, val_ref, attrs)
419        } else {
420            handle_generic(val_ref, path)
421        },
422    }
423}
424fn handle_prefixed_array(segment: &PathSegment, name: impl ToTokens + Clone, attrs: &[Attribute]) -> (TokenStream, TokenStream) {
425    let PathArguments::AngleBracketed(args) = &segment.arguments else {
426        panic!("Invalid vector inner type")
427    };
428    let Some(syn::GenericArgument::Type(inner_type)) = args.args.first() else {
429        panic!("Invalid vector inner type")
430    };
431    let (inner_encoder, inner_decoder) = get_encoder_and_decoder_for_field(&inner_type, quote! {v.clone()}, attrs);
432    (quote! {
433        vec![crate::fields::encode_var_int(#name.len() as i32), #name.iter().cloned().flat_map(|v| #inner_encoder).collect()].iter().cloned().flatten().collect()
434    }, quote! {
435        {
436            let len = reader.read_var_int()?;
437            let mut v = Vec::with_capacity(len as usize);
438            for _ in 0..len {
439                v.push(#inner_decoder);
440            }
441            v
442        }
443    })
444}
445
446fn handle_prefixed_option(segment: &PathSegment, name: impl ToTokens + Clone, attrs: &[Attribute]) -> (TokenStream, TokenStream) {
447    let PathArguments::AngleBracketed(args) = &segment.arguments else {
448        panic!("Invalid vector inner type")
449    };
450    let Some(syn::GenericArgument::Type(inner_type)) = args.args.first() else {
451        panic!("Invalid vector inner type")
452    };
453    let (inner_encoder, inner_decoder) = get_encoder_and_decoder_for_field(&inner_type, quote! {v.clone()}, attrs);
454    (quote! {
455        if let Some(v) = &#name {vec![crate::fields::encode_bool(true), #inner_encoder].iter().cloned().flatten().collect()} else {crate::fields::encode_bool(false)}
456    }, quote! {
457        if reader.read_bool()? {Some(#inner_decoder)} else {None} 
458    })
459}
460fn is_var(attrs: &[Attribute]) -> bool {
461    for attr in attrs {
462        let Meta::Path(path) = &attr.meta else {continue};
463        if path.is_ident("Var") {
464          return true;
465        }
466    }
467    false
468}
469fn is_const(attrs: &[Attribute]) -> bool {
470    for attr in attrs {
471        let Meta::Path(path) = &attr.meta else {continue};
472        if path.is_ident("Const") {
473            return true;
474        }
475    }
476    false
477}
478fn handle_int(attrs: &[Attribute], name: impl ToTokens) -> (TokenStream, TokenStream) {
479    if is_var(attrs) {
480        (quote! {
481            crate::fields::encode_var_int(#name)
482        }, quote! {
483            reader.read_var_int()?
484        })
485    } else {
486        #[cfg(debug_assertions)]
487        if !is_const(attrs) {
488            eprintln!("warning: unspecified Integer used for field {} guessing regular integer", name.to_token_stream());
489        }
490        (quote! {
491            crate::fields::encode_int(#name)
492        }, quote! {
493            reader.read_int()
494        })
495    }
496}
497fn handle_long(attrs: &[Attribute], name: impl ToTokens) -> (TokenStream, TokenStream) {
498    if is_var(attrs) {
499        (quote! {
500            crate::fields::encode_var_long(#name)
501        }, quote! {
502            reader.read_var_long()?
503        })
504    } else {
505        #[cfg(debug_assertions)]
506        if !is_const(attrs) {
507            eprintln!("warning: unspecified Long used for field {} guessing fixed size", name.to_token_stream());
508        }
509        (quote! {
510            crate::fields::encode_long(#name)
511        }, quote! {
512            reader.read_long()
513        })
514    }
515}
516fn handle_vec(segment: &PathSegment, name: impl ToTokens + Clone, attrs: &[Attribute]) -> (TokenStream, TokenStream) {
517    let PathArguments::AngleBracketed(args) = &segment.arguments else {
518        panic!("Invalid vector inner type")
519    };
520    let Some(syn::GenericArgument::Type(inner_type)) = args.args.first() else {
521        panic!("Invalid vector inner type")
522    };
523    let len_resp_field = get_length_responsible_attr(attrs);
524    let (inner_encoder, inner_decoder) = get_encoder_and_decoder_for_field(&inner_type, quote! {v.clone()}, attrs);
525    (quote! {
526        #name.iter().flat_map(|v| #inner_encoder).collect()
527    }, quote! {
528        {
529            let mut v = Vec::with_capacity(#len_resp_field as usize);
530            for _ in 0..#len_resp_field {
531                v.push(#inner_decoder);
532            }
533            v
534        }
535    })
536}
537fn get_length_responsible_attr(attrs: &[Attribute]) -> Path {
538    for attr in attrs {
539        let Meta::NameValue(meta) = &attr.meta else {
540            continue;
541        };
542        if !meta.path.is_ident("len") {continue}
543        let Expr::Lit(expr) = &meta.value else {
544            panic!("len must be literal expression")
545        };
546        let Lit::Str(path_str) = &expr.lit else {
547            panic!("len must be a string literal")
548        };
549        return syn::parse_str::<Path>(&*path_str.value()).expect("Invalid path");
550    }
551    panic!("requires a \"len\" attribute");
552}
553fn handle_option(segment: &PathSegment, name: impl ToTokens + Clone, attrs: &[Attribute]) -> (TokenStream, TokenStream) {
554    let PathArguments::AngleBracketed(args) = &segment.arguments else {
555        panic!("Invalid option inner type")
556    };
557    let Some(syn::GenericArgument::Type(inner_type)) = args.args.first() else {
558        panic!("Invalid option inner type")
559    };
560    let dependency = get_dependency(attrs);
561
562    let (inner_encoder, inner_decoder) = get_encoder_and_decoder_for_field(&inner_type, quote! {v}, attrs);
563    (quote! {
564        if self.#dependency {
565            let v = #name.clone().unwrap();
566            #inner_encoder
567        } else {vec![]}
568    }, quote! {
569        if #dependency {core::option::Option::Some(#inner_decoder)} else {core::option::Option::None}
570    })
571}
572fn get_dependency(attrs: &[Attribute]) -> Path {
573    for attr in attrs {
574        let Meta::NameValue(meta) = &attr.meta else {
575            continue;
576        };
577        if !meta.path.is_ident("when") {continue}
578        let Expr::Lit(expr) = &meta.value else {
579            panic!("when must be literal expression")
580        };
581        let Lit::Str(path_str) = &expr.lit else {
582            panic!("when must be a string literal")
583        };
584        return syn::parse_str::<Path>(&*path_str.value()).expect("Invalid path");
585    }
586    panic!("requires a \"len\" attribute");
587}
588
589fn handle_generic(name: impl ToTokens, path: &Path) -> (TokenStream, TokenStream) {
590    (quote! {crate::Field::to_bytes(&#name)}, quote! {{use crate::Field; #path::from_reader(reader)?}})
591}