bitsparrow_derive/
lib.rs

1//! # `#[derive]` macros for BitSparrow in Rust
2//!
3//! **[Homepage](http://!bitsparrow.io/) -**
4//! **[Cargo](https://!crates.io/crates/bitsparrow-derive)**
5//!
6//! ## Usage
7//!
8//! ```
9//! #[macro_use]
10//! extern crate bitsparrow_derive;
11//! extern crate bitsparrow;
12//!
13//! use bitsparrow::*;
14//!
15//! #[derive(BitEncode, BitDecode, PartialEq, Debug)]
16//! struct Foo {
17//!     bar: Vec<Bar>,
18//!     baz: String,
19//!     derp: bool,
20//! }
21//!
22//! #[derive(BitEncode, BitDecode, PartialEq, Debug)]
23//! struct Bar(u16);
24//!
25//! fn main() {
26//!     let foo = Foo {
27//!         bar: vec![Bar(10), Bar(1337)],
28//!         baz: "Hello world".into(),
29//!         derp: true,
30//!     };
31//!
32//!     let expect = vec![
33//!         2,                                                      //! Vec length
34//!         0x00,0x0A,                                              //! |-> 10
35//!         0x05,0x39,                                              //! `-> 1337
36//!         11,                                                     //! String length
37//!         b'H',b'e',b'l',b'l',b'o',b' ',b'w',b'o',b'r',b'l',b'd', //! `-> String data
38//!         1                                                       //! bool
39//!     ];
40//!
41//!     let buffer = Encoder::encode(&foo);
42//!     let decoded: Foo = Decoder::decode(&buffer).unwrap();
43//!
44//!     assert_eq!(buffer, expect);
45//!     assert_eq!(decoded, foo);
46//! }
47//! ```
48
49// The `quote!` macro requires deep recursion.
50#![recursion_limit = "192"]
51
52extern crate syn;
53#[macro_use]
54extern crate quote;
55extern crate proc_macro;
56
57mod encode;
58mod decode;
59
60use proc_macro::TokenStream;
61use encode::{encode_struct, encode_enum};
62use decode::{decode_struct, decode_enum};
63use syn::Body;
64
65#[proc_macro_derive(BitEncode)]
66pub fn derive_encode(input: TokenStream) -> TokenStream {
67    let input = syn::parse_derive_input(&input.to_string()).unwrap();
68
69    let ident = input.ident;
70
71    let (size_hint, body) = match input.body {
72        Body::Struct(body) => encode_struct(body),
73        Body::Enum(variants) => encode_enum(&ident, variants),
74    };
75
76    let tokens = quote! {
77        impl BitEncode for #ident {
78            fn encode(&self, e: &mut Encoder) {
79                #body
80            }
81
82            #[inline]
83            fn size_hint() -> usize {
84                #size_hint
85            }
86        }
87
88        impl<'a> BitEncode for &'a #ident {
89            #[inline]
90            fn encode(&self, e: &mut Encoder) {
91                BitEncode::encode(*self, e)
92            }
93
94            #[inline]
95            fn size_hint() -> usize {
96                #size_hint
97            }
98        }
99    };
100
101    tokens.parse().unwrap()
102}
103
104#[proc_macro_derive(BitDecode)]
105pub fn derive_decode(input: TokenStream) -> TokenStream {
106    let input = syn::parse_derive_input(&input.to_string()).unwrap();
107
108    let ident = input.ident;
109
110    let body = match input.body {
111        Body::Struct(body) => decode_struct(&ident, body),
112        Body::Enum(variants) => decode_enum(&ident, variants),
113    };
114
115    let tokens = quote! {
116        impl BitDecode for #ident {
117            fn decode(d: &mut Decoder) -> Result<Self, Error> {
118                Ok(#body)
119            }
120        }
121    };
122
123    tokens.parse().unwrap()
124}