jppe_derive/
lib.rs

1//!
2//! ```
3//! 
4//! use jppe::{ByteEncode, ByteDecode};
5//! use jppe_derive::{ByteEncode, ByteDecode};
6//!
7//!
8//! #[derive(Debug, PartialEq, Eq, ByteEncode, ByteDecode)]
9//! pub struct SimpleExample {
10//!     pub length: u16,
11//!     #[jppe(length="length")]
12//!     pub value: String,
13//!     pub cmd: u8,
14//!     #[jppe(branch="cmd")]
15//!     pub body: SimpleExampleBody,
16//! }
17//! 
18//! 
19//! #[derive(Debug, PartialEq, Eq, ByteEncode, ByteDecode)]
20//! #[repr(u8)]
21//! pub enum SimpleExampleBody {
22//!     Read {
23//!         address: u8,
24//!     } = 1,
25//!     Write {
26//!         address: u8,
27//!         value: [u8; 3],
28//!     },
29//!     #[jppe(enum_default)]
30//!     Unknown, 
31//! }
32//! 
33//! 
34//! fn main() {
35//!     let input = b"\x00\x03\x31\x32\x33\x01\x05";
36//!     let (input_remain, value) = jppe::decode::<SimpleExample>(input).unwrap();
37//!     assert_eq!(value, SimpleExample { length: 3, value: "123".to_string(), cmd: 1, body: SimpleExampleBody::Read { address: 5 } });
38//!     assert_eq!(input_remain.is_empty(), true);
39//!     assert_eq!(jppe::encode(value), input);
40//! }
41//! ```
42extern crate proc_macro;
43
44mod jppe;
45
46use jppe::attribute::ContainerAttributes;
47use jppe::derive_enum;
48use jppe::derive_struct;
49
50use proc_macro::TokenStream;
51use quote::ToTokens;
52use virtue::prelude::*;
53use syn::{parse_macro_input, DeriveInput};
54
55
56#[proc_macro_derive(ByteDecode, attributes(jppe))]
57pub fn derive_decode(input: TokenStream) -> TokenStream {
58    derive_decode_inner(input).unwrap_or_else(|e|e.into_token_stream())
59}
60
61
62fn derive_decode_inner(input: TokenStream) -> Result<TokenStream> {
63    let parse = Parse::new(input)?;
64    let (mut generator, attributes, body) = parse.into_generator();
65    let attributes = attributes
66        .get_attribute::<ContainerAttributes>()?
67        .unwrap_or_default();
68
69    match body {
70        Body::Struct(body) => {
71            derive_struct::DeriveStruct {
72                fields: body.fields,
73                attributes,
74                lifetimes: None,
75            }.generate_decode(&mut generator)?;
76        }
77        Body::Enum(body) => {
78            derive_enum::DeriveEnum {
79                variants: body.variants,
80                attributes,
81                lifetimes: None,
82            }
83            .generate_decode(&mut generator)?;
84        }
85    }
86
87    generator.export_to_file("jppe", "Decode");
88    generator.finish()
89}
90
91
92#[proc_macro_derive(BorrowByteDecode, attributes(jppe))]
93pub fn derive_borrow_decode(input: TokenStream) -> TokenStream {
94    let input_tmp = input.clone();
95    let derive_input = parse_macro_input!(input_tmp as DeriveInput);
96    let lifetimes = derive_input.generics.to_token_stream().to_string();
97
98    derive_borrow_decode_inner(input, lifetimes).unwrap_or_else(|e|e.into_token_stream())
99}
100
101
102fn derive_borrow_decode_inner(input: TokenStream, lifetimes: String) -> Result<TokenStream> {
103    let parse = Parse::new(input)?;
104    let (mut generator, attributes, body) = parse.into_generator();
105    let attributes = attributes
106        .get_attribute::<ContainerAttributes>()?
107        .unwrap_or_default();
108
109    match body {
110        Body::Struct(body) => {
111            derive_struct::DeriveStruct {
112                fields: body.fields,
113                attributes,
114                lifetimes: if lifetimes.is_empty() { None } else {Some(lifetimes)},
115            }.generate_borrow_decode(&mut generator)?;
116        }
117        Body::Enum(body) => {
118            derive_enum::DeriveEnum {
119                variants: body.variants,
120                attributes,
121                lifetimes: if lifetimes.is_empty() { None } else {Some(lifetimes)},
122            }
123            .generate_borrow_decode(&mut generator)?;
124        }
125    }
126
127    generator.export_to_file("jppe", "Decode");
128    generator.finish()
129}
130
131
132#[proc_macro_derive(ByteEncode, attributes(jppe))]
133pub fn derive_encode(input: TokenStream) -> TokenStream {
134    derive_encode_inner(input).unwrap_or_else(|e|e.into_token_stream())
135}
136
137
138fn derive_encode_inner(input: TokenStream) -> Result<TokenStream> {
139    let parse = Parse::new(input)?;
140    let (mut generator, attributes, body) = parse.into_generator();
141    let attributes = attributes
142        .get_attribute::<ContainerAttributes>()?
143        .unwrap_or_default();
144
145    match body {
146        Body::Struct(body) => {
147            derive_struct::DeriveStruct {
148                fields: body.fields,
149                attributes,
150                lifetimes: None,
151            }.generate_encode(&mut generator)?;
152        }
153        Body::Enum(body) => {
154            derive_enum::DeriveEnum {
155                variants: body.variants,
156                attributes,
157                lifetimes: None,
158            }
159            .generate_encode(&mut generator)?;
160        }
161    }
162
163    generator.export_to_file("jppe", "Encode");
164    generator.finish()
165}
166
167
168#[proc_macro_derive(BorrowByteEncode, attributes(jppe))]
169pub fn derive_borrow_encode(input: TokenStream) -> TokenStream {
170    derive_borrow_encode_inner(input).unwrap_or_else(|e|e.into_token_stream())
171}
172
173
174fn derive_borrow_encode_inner(input: TokenStream) -> Result<TokenStream> {
175    let parse = Parse::new(input)?;
176    let (mut generator, attributes, body) = parse.into_generator();
177    let attributes = attributes
178        .get_attribute::<ContainerAttributes>()?
179        .unwrap_or_default();
180
181    match body {
182        Body::Struct(body) => {
183            derive_struct::DeriveStruct {
184                fields: body.fields,
185                attributes,
186                lifetimes: None,
187            }.generate_borrow_encode(&mut generator)?;
188        }
189        Body::Enum(body) => {
190            derive_enum::DeriveEnum {
191                variants: body.variants,
192                attributes,
193                lifetimes: None,
194            }
195            .generate_borrow_encode(&mut generator)?;
196        }
197    }
198
199    generator.export_to_file("jppe", "Encode");
200    generator.finish()
201}