1#![doc(html_logo_url = "https://gitlab.com/bjoernager/oct/-/raw/master/doc-icon.svg")]
10
11extern crate self as oct_macros;
15
16use proc_macro::TokenStream;
17use quote::quote;
18use syn::{
19 parse_macro_input,
20 parse2,
21 Data,
22 DeriveInput,
23 Type,
24};
25use syn::parse::Parse;
26
27mod derive_impl;
28
29mod discriminants;
30mod repr;
31
32use discriminants::Discriminants;
33use repr::Repr;
34
35#[proc_macro_derive(Decode, attributes(oct))]
36pub fn derive_decode(input: TokenStream) -> TokenStream {
37 let input = parse_macro_input!(input as DeriveInput);
38
39 let self_name = input.ident;
40
41 let mut error: Type = parse2(quote! { ::oct::error::GenericDecodeError }).unwrap();
42
43 for attr in &input.attrs {
44 if attr.meta.path().is_ident("oct") {
45 let _ = attr.parse_nested_meta(|meta| {
46 if meta.path.is_ident("decode_error") {
47 error = Parse::parse(meta.value()?)?;
48 }
49
50 Ok(())
51 });
52 }
53 }
54
55 let body = match input.data {
56 Data::Struct(data) => derive_impl::decode_struct(data, error),
57
58 Data::Enum(data) => {
59 let repr = Repr::get(&input.attrs).unwrap_or_default();
60
61 derive_impl::decode_enum(data, repr, error)
62 }
63
64 Data::Union(_) => panic!("untagged union `{self_name}` cannot derive `oct::decode::Decode`"),
65 };
66
67 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
68
69 let output = quote! {
70 #[automatically_derived]
71 impl #impl_generics ::oct::decode::Decode for #self_name #ty_generics
72 #where_clause
73 {
74 #body
75 }
76 };
77
78 output.into()
79}
80
81#[proc_macro_derive(Encode, attributes(oct))]
82pub fn derive_encode(input: TokenStream) -> TokenStream {
83 let input = parse_macro_input!(input as DeriveInput);
84
85 let self_name = input.ident;
86
87 let mut error: Type = parse2(quote! { ::oct::error::GenericEncodeError }).unwrap();
88
89 for attr in &input.attrs {
90 if attr.meta.path().is_ident("oct") {
91 let _ = attr.parse_nested_meta(|meta| {
92 if meta.path.is_ident("encode_error") {
93 error = Parse::parse(meta.value()?)?;
94 }
95
96 Ok(())
97 });
98 }
99 }
100
101 let body = match input.data {
102 Data::Struct(data) => derive_impl::encode_struct(data, error),
103
104 Data::Enum(data) => {
105 let repr = Repr::get(&input.attrs).unwrap_or_default();
106
107 derive_impl::encode_enum(data, repr, error)
108 }
109
110 Data::Union(_) => panic!("untagged union `{self_name}` cannot derive `oct::encode::Encode`"),
111 };
112
113 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
114
115 let output = quote! {
116 #[automatically_derived]
117 impl #impl_generics ::oct::encode::Encode for #self_name #ty_generics
118 #where_clause
119 {
120 #body
121 }
122 };
123
124 output.into()
125}
126
127#[proc_macro_derive(SizedEncode)]
128pub fn derive_sized_encode(input: TokenStream) -> TokenStream {
129 let input = parse_macro_input!(input as DeriveInput);
130
131 let self_name = input.ident;
132
133 let body = match input.data {
134 Data::Struct(data) => derive_impl::sized_encode_struct(data),
135
136 Data::Enum(data) => {
137 let repr = Repr::get(&input.attrs).unwrap_or_default();
138
139 derive_impl::sized_encode_enum(data, repr)
140 }
141
142 Data::Union(_) => panic!("untagged union `{self_name}` cannot derive `oct::encode::SizedEncode`"),
143 };
144
145 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
146
147 let output = quote! {
148 #[automatically_derived]
149 impl #impl_generics ::oct::encode::SizedEncode for #self_name #ty_generics
150 #where_clause
151 {
152 #body
153 }
154 };
155
156 output.into()
157}