tentacli_packet/
lib.rs

1use proc_macro::{TokenStream};
2use proc_macro2::{Ident};
3use quote::{quote};
4use std::collections::BTreeMap;
5use syn::{parse_macro_input, Token, ItemStruct};
6use syn::parse::{Parse, ParseStream};
7use syn::punctuated::Punctuated;
8
9mod types;
10
11use types::Imports;
12
13struct DependsOnAttribute {
14    pub name: Ident,
15}
16
17impl Parse for DependsOnAttribute {
18    fn parse(input: ParseStream) -> syn::Result<Self> {
19        let name: Ident = input.parse()?;
20
21        Ok(Self { name })
22    }
23}
24
25/// LoginPacket is a part of tentacli-based projects.
26/// This proc-macro allows to send and receive packets from WoW Login server.
27/// `#[depends_on]` attribute indicates that the field depends on another fields. These fields will be
28/// converted into bytes and the byte-array will be used as dependency for `read_from` method of
29/// BinaryConverter
30
31#[proc_macro_derive(LoginPacket, attributes(depends_on))]
32pub fn login_packet(input: TokenStream) -> TokenStream {
33    let ItemStruct { ident, fields, .. } = parse_macro_input!(input);
34    let Imports {
35        async_buf_read,
36        binary_converter,
37        byteorder_write,
38        cursor,
39        json_formatter,
40        result,
41        serialize,
42        stream_reader,
43        ..
44    } = Imports::get();
45
46    let field_names = fields.iter().map(|f| {
47        f.ident.clone()
48    }).collect::<Vec<Option<Ident>>>();
49
50    let mut depends_on: BTreeMap<Option<Ident>, Vec<Ident>> = BTreeMap::new();
51    for field in fields.iter() {
52        let ident = field.ident.clone();
53
54        if field.attrs.iter().any(|attr| attr.path().is_ident("depends_on")) {
55            let mut dependencies: Vec<Ident> = vec![];
56
57            field.attrs.iter().for_each(|attr| {
58                if attr.path().is_ident("depends_on") {
59                    let parsed_attrs = attr.parse_args_with(
60                        Punctuated::<DependsOnAttribute, Token![,]>::parse_terminated
61                    ).unwrap();
62
63                    for a in parsed_attrs {
64                        dependencies.push(a.name);
65                    }
66                }
67            });
68
69            depends_on.insert(ident, dependencies);
70        }
71    }
72
73    let initializers = fields
74        .iter()
75        .map(|f| {
76            let field_name = f.ident.clone();
77            let field_type = f.ty.clone();
78
79            if let Some(dep_fields) = depends_on.get(&field_name) {
80                quote! {
81                    {
82                        let mut data: Vec<u8> = vec![];
83                        #(
84                            #binary_converter::write_into(
85                                &mut cache.#dep_fields,
86                                &mut data,
87                            )?;
88                        )*
89                        #binary_converter::read_from(&mut reader, &mut data)?
90                    }
91                }
92            } else {
93                quote! {
94                    {
95                        let value: #field_type = #binary_converter::read_from(&mut reader, &mut vec![])?;
96                        cache.#field_name = value.clone();
97                        value
98                    }
99                }
100            }
101        });
102
103    let mut output = quote! {
104        impl #ident {
105            pub fn from_binary(buffer: &[u8]) -> #result<(Self, String)> {
106                let mut cache = Self {
107                    #(#field_names: Default::default()),*
108                };
109
110                let mut reader = #cursor::new(buffer.to_vec());
111                let mut instance = Self {
112                    #(#field_names: #initializers),*
113                };
114                let details = instance.get_json_details()?;
115
116                Ok((instance, details))
117            }
118
119            pub fn to_binary_with_opcode(&mut self, opcode: u8) -> #result<Vec<u8>> {
120                let body = self._build_body()?;
121                let header = Self::_build_header(opcode)?;
122                Ok([header, body].concat())
123            }
124
125            pub fn unpack_with_opcode(&mut self, opcode: u8) -> #result<(u32, Vec<u8>, String)> {
126                Ok((opcode as u32, self.to_binary_with_opcode(opcode)?, self.get_json_details()?))
127            }
128
129            pub fn get_json_details(&mut self) -> #result<String> {
130                let mut serializer = #json_formatter::init();
131                #serialize::serialize(self, &mut serializer)?;
132                String::from_utf8(serializer.into_inner()).map_err(|e| e.into())
133            }
134
135            fn _build_body(&mut self) -> #result<Vec<u8>> {
136                let mut body = Vec::new();
137                #(
138                    #binary_converter::write_into(
139                        &mut self.#field_names,
140                        &mut body
141                    )?;
142                )*
143
144                Ok(body)
145            }
146
147            fn _build_header(opcode: u8) -> #result<Vec<u8>> {
148                let mut header: Vec<u8> = Vec::new();
149                #byteorder_write::write_u8(
150                    &mut header,
151                    opcode,
152                )?;
153
154                Ok(header)
155           }
156        }
157    };
158
159    let async_initializers = fields
160        .iter()
161        .map(|f| {
162            let field_name = f.ident.clone();
163            let field_type = f.ty.clone();
164
165            if let Some(dep_fields) = depends_on.get(&field_name) {
166                quote! {
167                    {
168                        let mut data: Vec<u8> = vec![];
169                        #(
170                            #binary_converter::write_into(
171                                &mut cache.#dep_fields,
172                                &mut data,
173                            )?;
174                        )*
175                        #stream_reader::read_from(&mut stream, &mut data).await?
176                    }
177                }
178            } else {
179                quote! {
180                    {
181                        let value: #field_type = #stream_reader::read_from(&mut stream, &mut vec![]).await?;
182                        cache.#field_name = value.clone();
183                        value
184                    }
185                }
186            }
187        });
188
189    output = quote! {
190        #output
191
192        impl #ident {
193            pub async fn from_stream<R>(mut stream: &mut R) -> #result<Vec<u8>>
194                where R: #async_buf_read + Unpin + Send
195            {
196                let mut cache = Self {
197                    #(#field_names: Default::default()),*
198                };
199
200                let mut instance = Self {
201                    #(#field_names: #async_initializers),*
202                };
203
204                instance._build_body()
205            }
206        }
207    };
208
209    TokenStream::from(output)
210}
211
212/// WorldPacket is a part of tentacli-based projects.
213/// This proc-macro allows to send and receive packets from WoW World server.
214/// `#[depends_on]` attribute indicates that the field depends on another fields. These fields will be
215/// converted into bytes and the byte-array will be used as dependency for `read_from` method of
216/// `BinaryConverter`.
217/// `#[conditional]` attribute indicates that the field's value will be parsed only if condition
218/// is true. The result for condition will be parsed from implemented method with same name as
219/// field name.
220
221#[proc_macro_derive(WorldPacket, attributes(depends_on, conditional))]
222pub fn world_packet(input: TokenStream) -> TokenStream {
223    let ItemStruct { ident, fields, .. } = parse_macro_input!(input);
224    let Imports {
225        binary_converter,
226        byteorder_be,
227        byteorder_le,
228        byteorder_write,
229        cursor,
230        json_formatter,
231        result,
232        serialize,
233        utils,
234        ..
235    } = Imports::get();
236
237    let field_names = fields.iter().map(|f| {
238        f.ident.clone()
239    }).collect::<Vec<Option<Ident>>>();
240
241    let mut depends_on: BTreeMap<Option<Ident>, Vec<Ident>> = BTreeMap::new();
242    let mut conditional: Vec<Option<Ident>> = vec![];
243    for field in fields.iter() {
244        let ident = field.ident.clone();
245
246        if field.attrs.iter().any(|attr| attr.path().is_ident("depends_on")) {
247            let mut dependencies: Vec<Ident> = vec![];
248
249            field.attrs.iter().for_each(|attr| {
250                if attr.path().is_ident("depends_on") {
251                    let parsed_attrs = attr.parse_args_with(
252                        Punctuated::<DependsOnAttribute, Token![,]>::parse_terminated
253                    ).unwrap();
254
255                    for a in parsed_attrs {
256                        dependencies.push(a.name);
257                    }
258                }
259            });
260
261            depends_on.insert(ident.clone(), dependencies);
262        }
263
264        if field.attrs.iter().any(|attr| attr.path().is_ident("conditional")) {
265            conditional.push(ident);
266        }
267    }
268
269    let initializers = fields
270        .iter()
271        .map(|f| {
272            let field_name = f.ident.clone();
273            let field_type = f.ty.clone();
274
275            let output = if let Some(dep_fields) = depends_on.get(&field_name) {
276                quote! {
277                    {
278                        let mut data: Vec<u8> = vec![];
279                        #(
280                            #binary_converter::write_into(
281                                &mut cache.#dep_fields,
282                                &mut data,
283                            )?;
284                        )*
285                        #binary_converter::read_from(&mut reader, &mut data)?
286                    }
287                }
288            } else {
289                quote! {
290                    {
291                        let value: #field_type = #binary_converter::read_from(
292                            &mut reader, &mut vec![]
293                        ).unwrap_or_default();
294
295                        cache.#field_name = value.clone();
296                        value
297                    }
298                }
299            };
300
301            if conditional.contains(&field_name) {
302                quote! {
303                    {
304                        if Self::#field_name(&mut cache) {
305                            #output
306                        } else {
307                            Default::default()
308                        }
309                    }
310                }
311            } else {
312                output
313            }
314        });
315
316    let writable_fields = fields.iter().map(|f| {
317        let field_name = f.ident.clone();
318
319        if conditional.contains(&field_name) {
320            quote! {
321                if Self::#field_name(self) {
322                    #binary_converter::write_into(&mut self.#field_name, &mut body)?;
323                }
324            }
325        } else {
326            quote! {
327                #binary_converter::write_into(&mut self.#field_name, &mut body)?;
328            }
329        }
330    });
331
332    let output = quote! {
333        impl #ident {
334            pub fn from_binary(buffer: &[u8]) -> #result<(Self, String)> {
335                Self::build_instance(buffer)
336            }
337
338            pub fn from_compressed_binary(buffer: &[u8]) -> #result<(Self, String)> {
339                let mut buffer = #utils::deflate_decompress(&buffer[6..])?;
340                Self::build_instance(&buffer)
341            }
342
343            pub fn to_binary_with_server_opcode(
344                &mut self,
345                opcode: u16
346            ) -> #result<Vec<u8>> {
347                let body = self._build_body()?;
348                let header = Self::_build_header_for_server_packet(body.len(), opcode)?;
349                Ok([header, body].concat())
350            }
351
352            pub fn to_binary_with_client_opcode(&mut self, opcode: u32) -> #result<Vec<u8>> {
353                let body = self._build_body()?;
354                let header = Self::_build_header_for_client_packet(body.len(), opcode)?;
355                Ok([header, body].concat())
356            }
357
358            pub fn unpack_with_server_opcode(
359                &mut self,
360                opcode: u16
361            ) -> #result<(u16, Vec<u8>, String)> {
362                Ok((opcode,
363                    self.to_binary_with_server_opcode(opcode)?,
364                    self.get_json_details()?))
365            }
366
367            pub fn unpack_with_client_opcode(&mut self, opcode: u32) -> #result<(u32, Vec<u8>, String)> {
368                Ok((opcode, self.to_binary_with_client_opcode(opcode)?, self.get_json_details()?))
369            }
370
371            pub fn get_json_details(&mut self) -> #result<String> {
372                let mut serializer = #json_formatter::init();
373                #serialize::serialize(self, &mut serializer)?;
374                String::from_utf8(serializer.into_inner()).map_err(|e| e.into())
375            }
376
377            fn _build_body(&mut self) -> #result<Vec<u8>> {
378                let mut body = Vec::new();
379                #(#writable_fields)*
380
381                Ok(body)
382            }
383
384            fn _build_header_for_server_packet(body_len: usize, opcode: u16) -> #result<Vec<u8>> {
385                let mut header: Vec<u8> = Vec::new();
386
387                let is_large_packet = body_len > 0x7FFF;
388
389                #byteorder_write::write_u16::<#byteorder_be>(
390                    &mut header,
391                    // header is 2 bytes packet size + 2 bytes outcoming opcode size
392                    (body_len as u16) + 2,
393                )?;
394
395                #byteorder_write::write_u16::<#byteorder_le>(
396                    &mut header,
397                    opcode,
398                )?;
399
400                if is_large_packet {
401                    header.insert(0, 128);
402                }
403
404                Ok(header)
405           }
406
407            fn _build_header_for_client_packet(body_len: usize, opcode: u32) -> #result<Vec<u8>> {
408                let mut header: Vec<u8> = Vec::new();
409                #byteorder_write::write_u16::<#byteorder_be>(
410                    &mut header,
411                    // header is 2 bytes packet size + 4 bytes outcoming opcode size
412                    (body_len as u16) + 4,
413                )?;
414
415                #byteorder_write::write_u32::<#byteorder_le>(
416                    &mut header,
417                    opcode,
418                )?;
419
420                Ok(header)
421           }
422
423            fn build_instance(buffer: &[u8]) -> #result<(Self, String)> {
424                let mut cache = Self {
425                    #(#field_names: Default::default()),*
426                };
427
428                let mut reader = #cursor::new(buffer);
429                let mut instance = Self {
430                    #(#field_names: #initializers),*
431                };
432
433                let details = instance.get_json_details()?;
434
435                Ok((instance, details))
436            }
437        }
438    };
439
440    TokenStream::from(output)
441}
442
443/// Segment is a part of tentacli-based projects.
444/// This proc-macro is used mostly for serialization, when there's a need to serialize set of fields
445/// into byte-array. Can be useful for sharing duplicated parts between different packets.
446/// `#[depends_on]` attribute indicates that the field depends on another fields. These fields will be
447/// converted into bytes and the byte-array will be used as dependency for `read_from` method of
448/// `BinaryConverter`.
449/// `#[conditional]` attribute indicates that the field's value will be parsed only if condition
450/// is true. The result for condition will be parsed from implemented method with same name as
451/// field name.
452
453#[proc_macro_derive(Segment, attributes(depends_on, conditional))]
454pub fn segment(input: TokenStream) -> TokenStream {
455    let ItemStruct { ident, fields, .. } = parse_macro_input!(input);
456    let Imports {
457        binary_converter,
458        buf_read,
459        result,
460        ..
461    } = Imports::get();
462
463    let field_names = fields.iter().map(|f| {
464        f.ident.clone()
465    }).collect::<Vec<Option<Ident>>>();
466
467    let mut depends_on: BTreeMap<Option<Ident>, Vec<Ident>> = BTreeMap::new();
468    let mut conditional: Vec<Option<Ident>> = vec![];
469    for field in fields.iter() {
470        let ident = field.ident.clone();
471
472        if field.attrs.iter().any(|attr| attr.path().is_ident("depends_on")) {
473            let mut dependencies: Vec<Ident> = vec![];
474
475            field.attrs.iter().for_each(|attr| {
476                if attr.path().is_ident("depends_on") {
477                    let parsed_attrs = attr.parse_args_with(
478                        Punctuated::<DependsOnAttribute, Token![,]>::parse_terminated
479                    ).unwrap();
480
481                    for a in parsed_attrs {
482                        dependencies.push(a.name);
483                    }
484                }
485            });
486
487            depends_on.insert(ident.clone(), dependencies);
488        }
489
490        if field.attrs.iter().any(|attr| attr.path().is_ident("conditional")) {
491            conditional.push(ident);
492        }
493    }
494
495    let initializers = fields
496        .iter()
497        .map(|f| {
498            let field_name = f.ident.clone();
499            let field_type = f.ty.clone();
500
501            let output = if let Some(dep_fields) = depends_on.get(&field_name) {
502                quote! {
503                    {
504                        let mut data: Vec<u8> = vec![];
505                        #(
506                            #binary_converter::write_into(
507                                &mut cache.#dep_fields,
508                                &mut data,
509                            )?;
510                        )*
511                        #binary_converter::read_from(&mut reader, &mut data)?
512                    }
513                }
514            } else {
515                quote! {
516                    {
517                        let value: #field_type = #binary_converter::read_from(&mut reader, &mut vec![])?;
518                        cache.#field_name = value.clone();
519                        value
520                    }
521                }
522            };
523
524            if conditional.contains(&field_name) {
525                quote! {
526                    {
527                        if Self::#field_name(&mut cache) {
528                            #output
529                        } else {
530                            Default::default()
531                        }
532                    }
533                }
534            } else {
535                output
536            }
537        });
538
539    let writable_fields = fields.iter().map(|f| {
540        let field_name = f.ident.clone();
541
542        if conditional.contains(&field_name) {
543            quote! {
544                if Self::#field_name(self) {
545                    #binary_converter::write_into(&mut self.#field_name, &mut body)?;
546                }
547            }
548        } else {
549            quote! {
550                #binary_converter::write_into(&mut self.#field_name, &mut body)?;
551            }
552        }
553    });
554
555    let output = quote! {
556        impl #ident {
557            pub fn read_from<R: #buf_read>(mut reader: &mut R) -> #result<Self> {
558                let mut cache = Self {
559                    #(#field_names: Default::default()),*
560                };
561
562                let mut instance = Self {
563                    #(#field_names: #initializers),*
564                };
565
566                Ok(instance)
567            }
568
569            pub fn to_binary(&mut self) -> #result<Vec<u8>> {
570                let mut body = Vec::new();
571                #(#writable_fields)*
572
573                Ok(body)
574            }
575        }
576
577        impl #binary_converter for #ident {
578            fn write_into(&mut self, buffer: &mut Vec<u8>) -> #result<()> {
579                buffer.extend(self.to_binary()?);
580                Ok(())
581            }
582
583            fn read_from<R: #buf_read>(reader: &mut R, _: &mut Vec<u8>) -> #result<Self> {
584                Self::read_from(reader)
585            }
586        }
587    };
588
589    TokenStream::from(output)
590}