1 #![recursion_limit = "1024"]
2
3 extern crate proc_macro;
4 use proc_macro2;
5 use quote::quote;
6
7 use proc_macro::TokenStream;
8
impl_field(ident: &proc_macro2::TokenStream, ty: &syn::Type) -> proc_macro2::TokenStream9 fn impl_field(ident: &proc_macro2::TokenStream, ty: &syn::Type) -> proc_macro2::TokenStream {
10 match *ty {
11 syn::Type::Array(ref array) => match array.len {
12 syn::Expr::Lit(syn::ExprLit {
13 lit: syn::Lit::Int(ref int),
14 ..
15 }) => {
16 let size = int.base10_parse::<usize>().unwrap();
17 quote! {
18 #ident: { let mut __tmp: #ty = [0u8.into(); #size]; src.gread_inout_with(offset, &mut __tmp, ctx)?; __tmp }
19 }
20 }
21 _ => panic!("Pread derive with bad array constexpr"),
22 },
23 syn::Type::Group(ref group) => impl_field(ident, &group.elem),
24 _ => {
25 quote! {
26 #ident: src.gread_with::<#ty>(offset, ctx)?
27 }
28 }
29 }
30 }
31
impl_struct( name: &syn::Ident, fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>, generics: &syn::Generics, ) -> proc_macro2::TokenStream32 fn impl_struct(
33 name: &syn::Ident,
34 fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>,
35 generics: &syn::Generics,
36 ) -> proc_macro2::TokenStream {
37 let items: Vec<_> = fields
38 .iter()
39 .enumerate()
40 .map(|(i, f)| {
41 let ident = &f.ident.as_ref().map(|i| quote! {#i}).unwrap_or({
42 let t = proc_macro2::Literal::usize_unsuffixed(i);
43 quote! {#t}
44 });
45 let ty = &f.ty;
46 impl_field(ident, ty)
47 })
48 .collect();
49
50 let gl = &generics.lt_token;
51 let gp = &generics.params;
52 let gg = &generics.gt_token;
53 let gn = gp.iter().map(|param: &syn::GenericParam| match param {
54 syn::GenericParam::Type(ref t) => {
55 let ident = &t.ident;
56 quote! { #ident }
57 }
58 p => quote! { #p },
59 });
60 let gn = quote! { #gl #( #gn ),* #gg };
61 let gw = if !gp.is_empty() {
62 let gi = gp.iter().map(|param: &syn::GenericParam| match param {
63 syn::GenericParam::Type(ref t) => {
64 let ident = &t.ident;
65 quote! {
66 #ident : ::scroll::ctx::TryFromCtx<'a, ::scroll::Endian> + ::std::convert::From<u8> + ::std::marker::Copy,
67 ::scroll::Error : ::std::convert::From<< #ident as ::scroll::ctx::TryFromCtx<'a, ::scroll::Endian>>::Error>,
68 < #ident as ::scroll::ctx::TryFromCtx<'a, ::scroll::Endian>>::Error : ::std::convert::From<scroll::Error>
69 }
70 },
71 p => quote! { #p }
72 });
73 quote! { #( #gi ),* , }
74 } else {
75 quote! {}
76 };
77
78 quote! {
79 impl<'a, #gp > ::scroll::ctx::TryFromCtx<'a, ::scroll::Endian> for #name #gn where #gw #name #gn : 'a {
80 type Error = ::scroll::Error;
81 #[inline]
82 fn try_from_ctx(src: &'a [u8], ctx: ::scroll::Endian) -> ::scroll::export::result::Result<(Self, usize), Self::Error> {
83 use ::scroll::Pread;
84 let offset = &mut 0;
85 let data = Self { #(#items,)* };
86 Ok((data, *offset))
87 }
88 }
89 }
90 }
91
impl_try_from_ctx(ast: &syn::DeriveInput) -> proc_macro2::TokenStream92 fn impl_try_from_ctx(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
93 let name = &ast.ident;
94 let generics = &ast.generics;
95 match ast.data {
96 syn::Data::Struct(ref data) => match data.fields {
97 syn::Fields::Named(ref fields) => impl_struct(name, &fields.named, generics),
98 syn::Fields::Unnamed(ref fields) => impl_struct(name, &fields.unnamed, generics),
99 _ => {
100 panic!("Pread can not be derived for unit structs")
101 }
102 },
103 _ => panic!("Pread can only be derived for structs"),
104 }
105 }
106
107 #[proc_macro_derive(Pread)]
derive_pread(input: TokenStream) -> TokenStream108 pub fn derive_pread(input: TokenStream) -> TokenStream {
109 let ast: syn::DeriveInput = syn::parse(input).unwrap();
110 let gen = impl_try_from_ctx(&ast);
111 gen.into()
112 }
113
impl_pwrite_field(ident: &proc_macro2::TokenStream, ty: &syn::Type) -> proc_macro2::TokenStream114 fn impl_pwrite_field(ident: &proc_macro2::TokenStream, ty: &syn::Type) -> proc_macro2::TokenStream {
115 match ty {
116 syn::Type::Array(ref array) => match array.len {
117 syn::Expr::Lit(syn::ExprLit {
118 lit: syn::Lit::Int(ref int),
119 ..
120 }) => {
121 let size = int.base10_parse::<usize>().unwrap();
122 quote! {
123 for i in 0..#size {
124 dst.gwrite_with(&self.#ident[i], offset, ctx)?;
125 }
126 }
127 }
128 _ => panic!("Pwrite derive with bad array constexpr"),
129 },
130 syn::Type::Group(group) => impl_pwrite_field(ident, &group.elem),
131 _ => {
132 quote! {
133 dst.gwrite_with(&self.#ident, offset, ctx)?
134 }
135 }
136 }
137 }
138
impl_try_into_ctx( name: &syn::Ident, fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>, generics: &syn::Generics, ) -> proc_macro2::TokenStream139 fn impl_try_into_ctx(
140 name: &syn::Ident,
141 fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>,
142 generics: &syn::Generics,
143 ) -> proc_macro2::TokenStream {
144 let items: Vec<_> = fields
145 .iter()
146 .enumerate()
147 .map(|(i, f)| {
148 let ident = &f.ident.as_ref().map(|i| quote! {#i}).unwrap_or({
149 let t = proc_macro2::Literal::usize_unsuffixed(i);
150 quote! {#t}
151 });
152 let ty = &f.ty;
153 impl_pwrite_field(ident, ty)
154 })
155 .collect();
156
157 let gl = &generics.lt_token;
158 let gp = &generics.params;
159 let gg = &generics.gt_token;
160 let gn = gp.iter().map(|param: &syn::GenericParam| match param {
161 syn::GenericParam::Type(ref t) => {
162 let ident = &t.ident;
163 quote! { #ident }
164 }
165 p => quote! { #p },
166 });
167 let gn = quote! { #gl #( #gn ),* #gg };
168 let gwref = if !gp.is_empty() {
169 let gi = gp.iter().map(|param: &syn::GenericParam| match param {
170 syn::GenericParam::Type(ref t) => {
171 let ident = &t.ident;
172 quote! {
173 &'a #ident : ::scroll::ctx::TryIntoCtx<::scroll::Endian>,
174 ::scroll::Error: ::std::convert::From<<&'a #ident as ::scroll::ctx::TryIntoCtx<::scroll::Endian>>::Error>,
175 <&'a #ident as ::scroll::ctx::TryIntoCtx<::scroll::Endian>>::Error: ::std::convert::From<scroll::Error>
176 }
177 },
178 p => quote! { #p }
179 });
180 quote! { where #( #gi ),* }
181 } else {
182 quote! {}
183 };
184 let gw = if !gp.is_empty() {
185 let gi = gp.iter().map(|param: &syn::GenericParam| match param {
186 syn::GenericParam::Type(ref t) => {
187 let ident = &t.ident;
188 quote! {
189 #ident : ::scroll::ctx::TryIntoCtx<::scroll::Endian>,
190 ::scroll::Error: ::std::convert::From<<#ident as ::scroll::ctx::TryIntoCtx<::scroll::Endian>>::Error>,
191 <#ident as ::scroll::ctx::TryIntoCtx<::scroll::Endian>>::Error: ::std::convert::From<scroll::Error>
192 }
193 },
194 p => quote! { #p }
195 });
196 quote! { where Self: ::std::marker::Copy, #( #gi ),* }
197 } else {
198 quote! {}
199 };
200
201 quote! {
202 impl<'a, #gp > ::scroll::ctx::TryIntoCtx<::scroll::Endian> for &'a #name #gn #gwref {
203 type Error = ::scroll::Error;
204 #[inline]
205 fn try_into_ctx(self, dst: &mut [u8], ctx: ::scroll::Endian) -> ::scroll::export::result::Result<usize, Self::Error> {
206 use ::scroll::Pwrite;
207 let offset = &mut 0;
208 #(#items;)*;
209 Ok(*offset)
210 }
211 }
212
213 impl #gl #gp #gg ::scroll::ctx::TryIntoCtx<::scroll::Endian> for #name #gn #gw {
214 type Error = ::scroll::Error;
215 #[inline]
216 fn try_into_ctx(self, dst: &mut [u8], ctx: ::scroll::Endian) -> ::scroll::export::result::Result<usize, Self::Error> {
217 (&self).try_into_ctx(dst, ctx)
218 }
219 }
220 }
221 }
222
impl_pwrite(ast: &syn::DeriveInput) -> proc_macro2::TokenStream223 fn impl_pwrite(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
224 let name = &ast.ident;
225 let generics = &ast.generics;
226 match ast.data {
227 syn::Data::Struct(ref data) => match data.fields {
228 syn::Fields::Named(ref fields) => impl_try_into_ctx(name, &fields.named, generics),
229 syn::Fields::Unnamed(ref fields) => impl_try_into_ctx(name, &fields.unnamed, generics),
230 _ => {
231 panic!("Pwrite can not be derived for unit structs")
232 }
233 },
234 _ => panic!("Pwrite can only be derived for structs"),
235 }
236 }
237
238 #[proc_macro_derive(Pwrite)]
derive_pwrite(input: TokenStream) -> TokenStream239 pub fn derive_pwrite(input: TokenStream) -> TokenStream {
240 let ast: syn::DeriveInput = syn::parse(input).unwrap();
241 let gen = impl_pwrite(&ast);
242 gen.into()
243 }
244
size_with( name: &syn::Ident, fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>, generics: &syn::Generics, ) -> proc_macro2::TokenStream245 fn size_with(
246 name: &syn::Ident,
247 fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>,
248 generics: &syn::Generics,
249 ) -> proc_macro2::TokenStream {
250 let items: Vec<_> = fields
251 .iter()
252 .map(|f| {
253 let ty = &f.ty;
254 match *ty {
255 syn::Type::Array(ref array) => {
256 let elem = &array.elem;
257 match array.len {
258 syn::Expr::Lit(syn::ExprLit {
259 lit: syn::Lit::Int(ref int),
260 ..
261 }) => {
262 let size = int.base10_parse::<usize>().unwrap();
263 quote! {
264 (#size * <#elem>::size_with(ctx))
265 }
266 }
267 _ => panic!("Pread derive with bad array constexpr"),
268 }
269 }
270 _ => {
271 quote! {
272 <#ty>::size_with(ctx)
273 }
274 }
275 }
276 })
277 .collect();
278
279 let gl = &generics.lt_token;
280 let gp = &generics.params;
281 let gg = &generics.gt_token;
282 let gn = gp.iter().map(|param: &syn::GenericParam| match param {
283 syn::GenericParam::Type(ref t) => {
284 let ident = &t.ident;
285 quote! { #ident }
286 }
287 p => quote! { #p },
288 });
289 let gn = quote! { #gl #( #gn ),* #gg };
290 let gw = if !gp.is_empty() {
291 let gi = gp.iter().map(|param: &syn::GenericParam| match param {
292 syn::GenericParam::Type(ref t) => {
293 let ident = &t.ident;
294 quote! {
295 #ident : ::scroll::ctx::SizeWith<::scroll::Endian>
296 }
297 }
298 p => quote! { #p },
299 });
300 quote! { where #( #gi ),* }
301 } else {
302 quote! {}
303 };
304
305 quote! {
306 impl #gl #gp #gg ::scroll::ctx::SizeWith<::scroll::Endian> for #name #gn #gw {
307 #[inline]
308 fn size_with(ctx: &::scroll::Endian) -> usize {
309 0 #(+ #items)*
310 }
311 }
312 }
313 }
314
impl_size_with(ast: &syn::DeriveInput) -> proc_macro2::TokenStream315 fn impl_size_with(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
316 let name = &ast.ident;
317 let generics = &ast.generics;
318 match ast.data {
319 syn::Data::Struct(ref data) => match data.fields {
320 syn::Fields::Named(ref fields) => size_with(name, &fields.named, generics),
321 syn::Fields::Unnamed(ref fields) => size_with(name, &fields.unnamed, generics),
322 _ => {
323 panic!("SizeWith can not be derived for unit structs")
324 }
325 },
326 _ => panic!("SizeWith can only be derived for structs"),
327 }
328 }
329
330 #[proc_macro_derive(SizeWith)]
derive_sizewith(input: TokenStream) -> TokenStream331 pub fn derive_sizewith(input: TokenStream) -> TokenStream {
332 let ast: syn::DeriveInput = syn::parse(input).unwrap();
333 let gen = impl_size_with(&ast);
334 gen.into()
335 }
336
impl_cread_struct( name: &syn::Ident, fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>, generics: &syn::Generics, ) -> proc_macro2::TokenStream337 fn impl_cread_struct(
338 name: &syn::Ident,
339 fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>,
340 generics: &syn::Generics,
341 ) -> proc_macro2::TokenStream {
342 let items: Vec<_> = fields.iter().enumerate().map(|(i, f)| {
343 let ident = &f.ident.as_ref().map(|i|quote!{#i}).unwrap_or({let t = proc_macro2::Literal::usize_unsuffixed(i); quote!{#t}});
344 let ty = &f.ty;
345 match *ty {
346 syn::Type::Array(ref array) => {
347 let arrty = &array.elem;
348 match array.len {
349 syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(ref int), ..}) => {
350 let size = int.base10_parse::<usize>().unwrap();
351 let incr = quote! { ::scroll::export::mem::size_of::<#arrty>() };
352 quote! {
353 #ident: {
354 let mut __tmp: #ty = [0u8.into(); #size];
355 for i in 0..__tmp.len() {
356 __tmp[i] = src.cread_with(*offset, ctx);
357 *offset += #incr;
358 }
359 __tmp
360 }
361 }
362 },
363 _ => panic!("IOread derive with bad array constexpr")
364 }
365 },
366 _ => {
367 let size = quote! { ::scroll::export::mem::size_of::<#ty>() };
368 quote! {
369 #ident: { let res = src.cread_with::<#ty>(*offset, ctx); *offset += #size; res }
370 }
371 }
372 }
373 }).collect();
374
375 let gl = &generics.lt_token;
376 let gp = &generics.params;
377 let gg = &generics.gt_token;
378 let gn = gp.iter().map(|param: &syn::GenericParam| match param {
379 syn::GenericParam::Type(ref t) => {
380 let ident = &t.ident;
381 quote! { #ident }
382 }
383 p => quote! { #p },
384 });
385 let gn = quote! { #gl #( #gn ),* #gg };
386 let gw = if !gp.is_empty() {
387 let gi = gp.iter().map(|param: &syn::GenericParam| match param {
388 syn::GenericParam::Type(ref t) => {
389 let ident = &t.ident;
390 quote! {
391 #ident : ::scroll::ctx::FromCtx<::scroll::Endian> + ::std::convert::From<u8> + ::std::marker::Copy
392 }
393 },
394 p => quote! { #p }
395 });
396 quote! { where #( #gi ),* , }
397 } else {
398 quote! {}
399 };
400
401 quote! {
402 impl #gl #gp #gg ::scroll::ctx::FromCtx<::scroll::Endian> for #name #gn #gw {
403 #[inline]
404 fn from_ctx(src: &[u8], ctx: ::scroll::Endian) -> Self {
405 use ::scroll::Cread;
406 let offset = &mut 0;
407 let data = Self { #(#items,)* };
408 data
409 }
410 }
411 }
412 }
413
impl_from_ctx(ast: &syn::DeriveInput) -> proc_macro2::TokenStream414 fn impl_from_ctx(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
415 let name = &ast.ident;
416 let generics = &ast.generics;
417 match ast.data {
418 syn::Data::Struct(ref data) => match data.fields {
419 syn::Fields::Named(ref fields) => impl_cread_struct(name, &fields.named, generics),
420 syn::Fields::Unnamed(ref fields) => impl_cread_struct(name, &fields.unnamed, generics),
421 _ => {
422 panic!("IOread can not be derived for unit structs")
423 }
424 },
425 _ => panic!("IOread can only be derived for structs"),
426 }
427 }
428
429 #[proc_macro_derive(IOread)]
derive_ioread(input: TokenStream) -> TokenStream430 pub fn derive_ioread(input: TokenStream) -> TokenStream {
431 let ast: syn::DeriveInput = syn::parse(input).unwrap();
432 let gen = impl_from_ctx(&ast);
433 gen.into()
434 }
435
impl_into_ctx( name: &syn::Ident, fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>, generics: &syn::Generics, ) -> proc_macro2::TokenStream436 fn impl_into_ctx(
437 name: &syn::Ident,
438 fields: &syn::punctuated::Punctuated<syn::Field, syn::Token![,]>,
439 generics: &syn::Generics,
440 ) -> proc_macro2::TokenStream {
441 let items: Vec<_> = fields
442 .iter()
443 .enumerate()
444 .map(|(i, f)| {
445 let ident = &f.ident.as_ref().map(|i| quote! {#i}).unwrap_or({
446 let t = proc_macro2::Literal::usize_unsuffixed(i);
447 quote! {#t}
448 });
449 let ty = &f.ty;
450 let size = quote! { ::scroll::export::mem::size_of::<#ty>() };
451 match *ty {
452 syn::Type::Array(ref array) => {
453 let arrty = &array.elem;
454 quote! {
455 let size = ::scroll::export::mem::size_of::<#arrty>();
456 for i in 0..self.#ident.len() {
457 dst.cwrite_with(self.#ident[i], *offset, ctx);
458 *offset += size;
459 }
460 }
461 }
462 _ => {
463 quote! {
464 dst.cwrite_with(self.#ident, *offset, ctx);
465 *offset += #size;
466 }
467 }
468 }
469 })
470 .collect();
471
472 let gl = &generics.lt_token;
473 let gp = &generics.params;
474 let gg = &generics.gt_token;
475 let gn = gp.iter().map(|param: &syn::GenericParam| match param {
476 syn::GenericParam::Type(ref t) => {
477 let ident = &t.ident;
478 quote! { #ident }
479 }
480 p => quote! { #p },
481 });
482 let gw = if !gp.is_empty() {
483 let gi = gp.iter().map(|param: &syn::GenericParam| match param {
484 syn::GenericParam::Type(ref t) => {
485 let ident = &t.ident;
486 quote! {
487 #ident : ::scroll::ctx::IntoCtx<::scroll::Endian> + ::std::marker::Copy
488 }
489 }
490 p => quote! { #p },
491 });
492 quote! { where #( #gi ),* }
493 } else {
494 quote! {}
495 };
496 let gn = quote! { #gl #( #gn ),* #gg };
497
498 quote! {
499 impl<'a, #gp > ::scroll::ctx::IntoCtx<::scroll::Endian> for &'a #name #gn #gw {
500 #[inline]
501 fn into_ctx(self, dst: &mut [u8], ctx: ::scroll::Endian) {
502 use ::scroll::Cwrite;
503 let offset = &mut 0;
504 #(#items;)*;
505 ()
506 }
507 }
508
509 impl #gl #gp #gg ::scroll::ctx::IntoCtx<::scroll::Endian> for #name #gn #gw {
510 #[inline]
511 fn into_ctx(self, dst: &mut [u8], ctx: ::scroll::Endian) {
512 (&self).into_ctx(dst, ctx)
513 }
514 }
515 }
516 }
517
impl_iowrite(ast: &syn::DeriveInput) -> proc_macro2::TokenStream518 fn impl_iowrite(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
519 let name = &ast.ident;
520 let generics = &ast.generics;
521 match ast.data {
522 syn::Data::Struct(ref data) => match data.fields {
523 syn::Fields::Named(ref fields) => impl_into_ctx(name, &fields.named, generics),
524 syn::Fields::Unnamed(ref fields) => impl_into_ctx(name, &fields.unnamed, generics),
525 _ => {
526 panic!("IOwrite can not be derived for unit structs")
527 }
528 },
529 _ => panic!("IOwrite can only be derived for structs"),
530 }
531 }
532
533 #[proc_macro_derive(IOwrite)]
derive_iowrite(input: TokenStream) -> TokenStream534 pub fn derive_iowrite(input: TokenStream) -> TokenStream {
535 let ast: syn::DeriveInput = syn::parse(input).unwrap();
536 let gen = impl_iowrite(&ast);
537 gen.into()
538 }
539