1use proc_macro::{self, TokenStream};
2use proc_macro2::TokenTree;
3use quote::quote;
4use syn::{parse_macro_input, DeriveInput};
5
6#[proc_macro_derive(TryFromByte)]
15pub fn try_from_byte(input: TokenStream) -> TokenStream {
16 let DeriveInput { ident, data, .. } = parse_macro_input!(input);
18 let len = match data {
21 syn::Data::Enum(enum_item) => enum_item.variants.len(),
22 _ => panic!("TryFromByte only works on Enums"),
23 };
24 let output = quote! {
26 impl TryFrom<u8> for #ident {
27 type Error = &'static str;
28 fn try_from(x: u8) -> Result<Self, Self::Error> {
29 let right_size = x >= 0 && x <= (#len as u8);
30 match right_size {
31 true => Ok(unsafe { std::mem::transmute(x as u8) }),
32 _ => Err("invalid #ident Value"),
33 }
34 }
35 }
36 };
37 output.into()
38}
39#[proc_macro_derive(Persistable, attributes(persist_with_name, persist_with_data))]
59pub fn persistable(input: TokenStream) -> TokenStream {
60 let DeriveInput { ident, attrs, .. } = parse_macro_input!(input);
61 let mut with_name_method = None;
62 for attr in attrs {
65 if attr.path.is_ident("persist_with_name") {
66 attr.tokens
67 .into_iter()
68 .for_each(|tokentree| match tokentree {
69 TokenTree::Group(group) => {
70 group
71 .stream()
72 .into_iter()
73 .for_each(|subtokentree| match subtokentree {
74 TokenTree::Ident(ident) => {
75 with_name_method = Some(ident);
76 }
77 _ => {}
78 });
79 }
80 _ => {}
81 });
82 }
83 }
84 let struct_name = &ident.to_string().to_lowercase();
87 let file_name_append_token_stream;
90 if with_name_method.is_some() {
91 file_name_append_token_stream = quote! {
92 let mut filename: String = String::from("data/");
93 filename.push_str(&self.#with_name_method());
94 };
95 } else {
96 file_name_append_token_stream = quote! {
97 let mut filename: String = String::from("data/");
98 filename.push_str(#struct_name);
99 };
100 }
101 let output = quote! {
103 impl Persistable for #ident {
104 fn save(&self) {
105 let serialized = serde_json::to_string(&self).unwrap();
106 #file_name_append_token_stream
107 Storage::write(serialized.as_bytes().to_vec(), &filename);
108 }
109 fn load(relative_filename: &str) -> Self {
110 let mut filename: String = String::from("data/");
111 filename.push_str(relative_filename);
112 let serialized = Storage::read(&filename).unwrap();
113 let out = serde_json::from_str(std::str::from_utf8(&serialized[..]).unwrap()).unwrap();
114 out
115 }
116 }
117 };
118 output.into()
119}