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}