1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{parse_macro_input, Data, DeriveInput, Field};
6
7#[proc_macro_derive(Context)]
8pub fn derive_context(input: TokenStream) -> TokenStream {
9 let input = parse_macro_input!(input as DeriveInput);
10 let data = match input.data {
11 Data::Struct(s) => s,
12 _ => panic!("Deriving kimari::Context only supports a struct."),
13 };
14
15 let arms = data
16 .fields
17 .iter()
18 .map(|Field { ident, .. }| {
19 quote! {
20 stringify!(#ident) => self.#ident.get_from_context(path),
21 }
22 })
23 .collect::<Vec<_>>();
24
25 let name = &input.ident;
26 let output = quote! {
27 impl kimari::context::Context for #name {
28 fn get_from_context<'a, I>(&self, path: I) -> Result<kimari::Value, kimari::context::Error>
29 where
30 I: IntoIterator<Item = &'a str>,
31 {
32 let mut path = path.into_iter();
33 let name = path.next();
34 match name {
35 Some(s) => match s {
36 #(#arms)*
37 _ => return Err(kimari::context::Error::UnexpectedPath([s].into()))
38 },
39 _ => unimplemented!("Value representation of structs is not supported yet."),
40 }
41 }
42 }
43 };
44
45 output.into()
46}