1#![allow(dead_code)]
6#![allow(unused_must_use)]
7
8mod attribute;
9mod derive_bit_packed;
10mod derive_enum;
11mod derive_fingerprint;
12mod derive_static_size;
13mod derive_struct;
14mod derive_zerocopy;
15
16use attribute::ContainerAttributes;
17use virtue::prelude::AttributeAccess;
18use virtue::prelude::Body;
19#[allow(unused_imports)]
20use virtue::prelude::Error;
21use virtue::prelude::Parse;
22use virtue::prelude::Result;
23use virtue::prelude::TokenStream;
24
25#[proc_macro_derive(Encode, attributes(bincode))]
26pub fn derive_encode(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
27 derive_encode_inner(input).unwrap_or_else(|e| e.into_token_stream())
28}
29
30fn derive_encode_inner(input: TokenStream) -> Result<TokenStream> {
34 let parse = Parse::new(input)?;
35 let (mut generator, attributes, body) = parse.into_generator();
36 let attributes = attributes
37 .get_attribute::<ContainerAttributes>()?
38 .unwrap_or_default();
39
40 match body {
41 | Body::Struct(body) => {
42 derive_struct::DeriveStruct {
43 fields: body.fields,
44 attributes,
45 }
46 .generate_encode(&mut generator)?;
47 },
48 | Body::Enum(body) => {
49 derive_enum::DeriveEnum {
50 variants: body.variants,
51 attributes,
52 }
53 .generate_encode(&mut generator)?;
54 },
55 }
56
57 generator.export_to_file("bincode_next", "Encode");
58 generator.finish()
59}
60
61#[proc_macro_derive(Decode, attributes(bincode))]
62pub fn derive_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
63 derive_decode_inner(input).unwrap_or_else(|e| e.into_token_stream())
64}
65
66fn derive_decode_inner(input: TokenStream) -> Result<TokenStream> {
70 let parse = Parse::new(input)?;
71 let (mut generator, attributes, body) = parse.into_generator();
72 let attributes = attributes
73 .get_attribute::<ContainerAttributes>()?
74 .unwrap_or_default();
75
76 match body {
77 | Body::Struct(body) => {
78 derive_struct::DeriveStruct {
79 fields: body.fields,
80 attributes,
81 }
82 .generate_decode(&mut generator)?;
83 },
84 | Body::Enum(body) => {
85 derive_enum::DeriveEnum {
86 variants: body.variants,
87 attributes,
88 }
89 .generate_decode(&mut generator)?;
90 },
91 }
92
93 generator.export_to_file("bincode_next", "Decode");
94 generator.finish()
95}
96
97#[proc_macro_derive(BorrowDecode, attributes(bincode))]
98pub fn derive_borrow_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
99 derive_borrow_decode_inner(input).unwrap_or_else(|e| e.into_token_stream())
100}
101
102fn derive_borrow_decode_inner(input: TokenStream) -> Result<TokenStream> {
106 let parse = Parse::new(input)?;
107 let (mut generator, attributes, body) = parse.into_generator();
108 let attributes = attributes
109 .get_attribute::<ContainerAttributes>()?
110 .unwrap_or_default();
111
112 match body {
113 | Body::Struct(body) => {
114 derive_struct::DeriveStruct {
115 fields: body.fields,
116 attributes,
117 }
118 .generate_borrow_decode(&mut generator)?;
119 },
120 | Body::Enum(body) => {
121 derive_enum::DeriveEnum {
122 variants: body.variants,
123 attributes,
124 }
125 .generate_borrow_decode(&mut generator)?;
126 },
127 }
128
129 generator.export_to_file("bincode_next", "BorrowDecode");
130 generator.finish()
131}
132
133#[proc_macro_derive(BitPacked, attributes(bincode))]
134pub fn derive_bit_packed(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
135 derive_bit_packed_inner(input).unwrap_or_else(|e| e.into_token_stream())
136}
137
138fn derive_bit_packed_inner(input: TokenStream) -> Result<TokenStream> {
142 let parse = Parse::new(input)?;
143 let (mut generator, attributes, body) = parse.into_generator();
144 let attributes = attributes
145 .get_attribute::<ContainerAttributes>()?
146 .unwrap_or_default();
147
148 match body {
149 | Body::Struct(body) => {
150 derive_bit_packed::DeriveBitPacked {
151 fields: body.fields,
152 attributes,
153 }
154 .generate(&mut generator)?;
155 },
156 | Body::Enum(body) => {
157 derive_bit_packed::DeriveBitPackedEnum {
158 variants: body.variants,
159 attributes,
160 }
161 .generate(&mut generator)?;
162 },
163 }
164
165 generator.export_to_file("bincode_next", "BitPacked");
166 generator.finish()
167}
168
169#[cfg(feature = "zero-copy")]
170#[proc_macro_derive(ZeroCopy, attributes(bincode))]
171pub fn derive_zerocopy(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
172 derive_zerocopy_inner(input).unwrap_or_else(|e| e.into_token_stream())
173}
174
175#[cfg(feature = "zero-copy")]
176fn derive_zerocopy_inner(input: TokenStream) -> Result<TokenStream> {
177 let parse = Parse::new(input)?;
178
179 let visibility = match &parse {
180 | Parse::Struct { visibility, .. } => visibility.clone(),
181 | Parse::Enum { visibility, .. } => visibility.clone(),
182 | _ => unreachable!(),
183 };
184 let (mut generator, attributes, body) = parse.into_generator();
185 let repr = attributes
186 .get_attribute::<attribute::ReprAttributes>()?
187 .unwrap_or_default();
188
189 let attributes = attributes
190 .get_attribute::<ContainerAttributes>()?
191 .unwrap_or_default();
192
193 match body {
194 | Body::Struct(body) => {
195 if !repr.is_c && !repr.is_transparent {
196 return Err(Error::custom(
197 "ZeroCopy structs must have #[repr(C)] or #[repr(transparent)]",
198 ));
199 }
200 derive_zerocopy::DeriveZeroCopy {
201 fields: body.fields,
202 variants: None,
203 attributes,
204 repr,
205 visibility,
206 }
207 .generate(&mut generator)?;
208 },
209 | Body::Enum(body) => {
210 if !repr.is_c
211 && !repr.is_u8
212 && !repr.is_u16
213 && !repr.is_u32
214 && !repr.is_u64
215 && !repr.is_i8
216 && !repr.is_i16
217 && !repr.is_i32
218 && !repr.is_i64
219 {
220 return Err(Error::custom(
221 "ZeroCopy enums must have #[repr(C)] or a primitive repr like #[repr(u8)]",
222 ));
223 }
224 derive_zerocopy::DeriveZeroCopy {
225 fields: None,
226 variants: Some(body.variants),
227 attributes,
228 repr,
229 visibility,
230 }
231 .generate(&mut generator)?;
232 },
233 }
234
235 generator.export_to_file("bincode_next", "ZeroCopy");
236 generator.finish()
237}
238
239#[cfg(feature = "static-size")]
240#[proc_macro_derive(StaticSize, attributes(bincode, static_size))]
241pub fn derive_static_size(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
242 derive_static_size_inner(input).unwrap_or_else(|e| e.into_token_stream())
243}
244
245#[cfg(feature = "static-size")]
246fn derive_static_size_inner(input: TokenStream) -> Result<TokenStream> {
247 let parse = Parse::new(input)?;
248 let (mut generator, attributes, body) = parse.into_generator();
249 let attributes = attributes
250 .get_attribute::<ContainerAttributes>()?
251 .unwrap_or_default();
252
253 match body {
254 | Body::Struct(body) => {
255 derive_static_size::DeriveStaticSize {
256 fields: body.fields,
257 variants: None,
258 attributes,
259 }
260 .generate(&mut generator)?;
261 },
262 | Body::Enum(body) => {
263 derive_static_size::DeriveStaticSize {
264 fields: None,
265 variants: Some(body.variants),
266 attributes,
267 }
268 .generate(&mut generator)?;
269 },
270 }
271
272 generator.export_to_file("bincode_next", "StaticSize");
273 generator.finish()
274}
275
276#[proc_macro_derive(Fingerprint, attributes(bincode))]
277pub fn derive_fingerprint(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
278 derive_fingerprint_inner(input).unwrap_or_else(|e| e.into_token_stream())
279}
280
281fn derive_fingerprint_inner(input: TokenStream) -> Result<TokenStream> {
282 let parse = Parse::new(input)?;
283 let type_name = match &parse {
284 | Parse::Struct { name, .. } | Parse::Enum { name, .. } => name.to_string(),
285 | _ => unreachable!(),
286 };
287 let (mut generator, attributes, body) = parse.into_generator();
288 let attributes = attributes
289 .get_attribute::<ContainerAttributes>()?
290 .unwrap_or_default();
291
292 match body {
293 | Body::Struct(body) => {
294 derive_fingerprint::DeriveFingerprint {
295 fields: body.fields,
296 variants: None,
297 attributes,
298 }
299 .generate(&mut generator, &type_name)?;
300 },
301 | Body::Enum(body) => {
302 derive_fingerprint::DeriveFingerprint {
303 fields: None,
304 variants: Some(body.variants),
305 attributes,
306 }
307 .generate(&mut generator, &type_name)?;
308 },
309 }
310
311 generator.export_to_file("bincode_next", "Fingerprint");
312 generator.finish()
313}