1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use proc_macro::TokenStream;
use quote::quote;
use spanned::Spanned;
use syn::*;
#[proc_macro_derive(Write, attributes(raad))]
/// Types are written in order of declaration.
pub fn impl_write(input: TokenStream) -> TokenStream {
    let DeriveInput {
        data,
        ident,
        vis,
        generics,
        ..
    } = parse_macro_input!(input as DeriveInput);
    let Data::Struct(DataStruct { fields, .. }) = data else {
        return syn::Error::new(vis.span(), "only structs are supported for codegen")
            .to_compile_error()
            .into();
    };
    let fields_le = fields
        .iter()
        .zip((0..).map(proc_macro2::Literal::usize_unsuffixed))
        .map(|(Field { ident, .. }, i)| match ident {
            None => quote! { ::raad::le::W::w(to, self.#i)?; },
            Some(i) => quote! { ::raad::le::W::w(to, self.#i)?; },
        });
    let fields_be = fields
        .iter()
        .zip((0..).map(proc_macro2::Literal::usize_unsuffixed))
        .map(|(Field { ident, .. }, i)| match ident {
            None => quote! { ::raad::be::W::w(to, self.#i)?; },
            Some(i) => quote! { ::raad::be::W::w(to, self.#i)?; },
        });
    quote! {
        impl ::raad::le::Writable for #ident {
            fn _w(self, to: &mut impl ::std::io::Write) -> ::std::io::Result<()> {
                #(#fields_le)*
                Ok(())
            }
        }
        impl ::raad::be::Writable for #ident {
            fn _w(self, to: &mut impl ::std::io::Write) -> ::std::io::Result<()> {
                #(#fields_be)*
                Ok(())
            }
        }
    }
    .into()
}

#[proc_macro_derive(Read, attributes(raad))]
/// Types are read in order of declaration.
pub fn impl_read(input: TokenStream) -> TokenStream {
    let DeriveInput {
        data,
        ident,
        vis,
        generics,
        ..
    } = parse_macro_input!(input as DeriveInput);
    let Data::Struct(DataStruct { fields, .. }) = data else {
        return syn::Error::new(vis.span(), "only structs are supported for codegen")
            .to_compile_error()
            .into();
    };
    let fields_le = fields
        .iter()
        .zip((0..).map(proc_macro2::Literal::usize_unsuffixed))
        .map(|(Field { ident, .. }, i)| match ident {
            None => quote! { #i: ::raad::le::R::r(from)?, },
            Some(i) => quote! { #i: ::raad::le::R::r(from)?, },
        });
    let fields_be = fields
        .iter()
        .zip((0..).map(proc_macro2::Literal::usize_unsuffixed))
        .map(|(Field { ident, .. }, i)| match ident {
            None => quote! { #i: ::raad::be::R::r(from)?, },
            Some(i) => quote! { #i: ::raad::be::R::r(from)?, },
        });
    quote! {
        impl ::raad::le::Readable for #ident {
            fn r(from: &mut impl std::io::Read) -> ::std::io::Result<Self> {
                Ok(Self { #(#fields_le)* })
            }
        }
        impl ::raad::be::Readable for #ident {
            fn r(from: &mut impl ::std::io::Read) -> ::std::io::Result<Self> {
                Ok(Self { #(#fields_be)* })
            }
        }
    }
    .into()
}