From 57d5f1b806fdfe2a9db6a37b2761a5291252c76b Mon Sep 17 00:00:00 2001 From: Akshay Date: Sun, 15 Mar 2020 22:07:03 +0530 Subject: rename to fondant --- fondant_derive/src/lib.rs | 125 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 fondant_derive/src/lib.rs (limited to 'fondant_derive/src') diff --git a/fondant_derive/src/lib.rs b/fondant_derive/src/lib.rs new file mode 100644 index 0000000..5584d84 --- /dev/null +++ b/fondant_derive/src/lib.rs @@ -0,0 +1,125 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; +use proc_macro2::Span; +use quote::quote; +use syn::{parse_macro_input, DeriveInput, Error, Ident, Lit, Meta, MetaNameValue, Result}; + +#[proc_macro_derive(Config, attributes(filename, extension))] +pub fn config_attribute(item: TokenStream) -> TokenStream { + let ast: DeriveInput = parse_macro_input!(item as DeriveInput); + let (filename, filetype) = extract_attributes(&ast); + + gen_impl( + &ast, + filename.unwrap_or("config".into()), + filetype.unwrap_or("toml".into()), + ) +} + +fn extract_attributes(ast: &DeriveInput) -> (Option, Option) { + let mut filename: Option = None; + let mut filetype: Option = None; + for option in ast.attrs.iter() { + let option = option.parse_meta().unwrap(); + match option { + Meta::NameValue(MetaNameValue { + ref path, ref lit, .. + }) if path.is_ident("filename") => { + if let Lit::Str(f) = lit { + filename = Some(f.value()); + } + } + Meta::NameValue(MetaNameValue { + ref path, ref lit, .. + }) if path.is_ident("extension") => { + if let Lit::Str(f) = lit { + filetype = Some(f.value()); + } + } + _ => {} + } + } + return (filename, filetype); +} + +fn map_ser(ext: &str) -> (Ident, Ident) { + match ext.as_ref() { + "toml" => ( + Ident::new("toml", Span::call_site()), + Ident::new("to_string_pretty", Span::call_site()), + ), + "yaml" => ( + Ident::new("serde_yaml", Span::call_site()), + Ident::new("to_string", Span::call_site()), + ), + "json" => ( + Ident::new("serde_json", Span::call_site()), + Ident::new("to_string_pretty", Span::call_site()), + ), + _ => panic!("Invalid extension!"), + } +} + +fn gen_impl(ast: &DeriveInput, filename: String, filetype: String) -> TokenStream { + let struct_name = &ast.ident.to_string(); + let struct_ident = &ast.ident; + let (ser, ser_fn) = map_ser(&filetype); + + let gen = quote! { + use ::fondant::{ ProjectDirs, toml, serde_json, serde_yaml, FondantError }; + use ::std::path::{ Path, PathBuf }; + use ::std::option::Option; + use ::std::fs::{self, File, OpenOptions}; + use ::std::io::prelude::*; + use ::std::io::{ ErrorKind::NotFound, Write }; + + impl Config for #struct_ident { + fn load() -> Result<#struct_ident, FondantError> { + let project = ProjectDirs::from("rs", "", #struct_name).ok_or(FondantError::InvalidHomeDir)?; + let config_dir = project.config_dir(); + + let tip = (Path::new(#filename)).with_extension(&#filetype); + let config_file: PathBuf = [config_dir, &tip].iter().collect(); + + match File::open(&config_file) { + Ok(mut cfg) => { + // the file exists, parse the toml and return the struct + let mut cfg_data = String::new(); + cfg.read_to_string(&mut cfg_data); + + let config: #struct_ident = #ser::from_str(&cfg_data[..]) + .map_err(|_| FondantError::ConfigParseError)?; + return Ok(config); + }, + Err(ref e) if e.kind() == NotFound => { + fs::create_dir_all(project.config_dir()); + let default_impl = #struct_ident::default(); + Config::store(&default_impl)?; + return Ok(default_impl); + }, + Err(e) => return Err(FondantError::LoadError), + }; + } + fn store(&self) -> Result<(), FondantError> { + let project = ProjectDirs::from("rs", "", #struct_name).ok_or(FondantError::InvalidHomeDir)?; + let config_dir = project.config_dir(); + + let tip = (Path::new(#filename)).with_extension(&#filetype); + let config_file: PathBuf = [config_dir, &tip].iter().collect(); + + let mut f = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(config_file) + .map_err(|_| FondantError::FileOpenError)?; + + let s = #ser::#ser_fn(self).map_err(|_| FondantError::ConfigParseError)?; + f.write_all(s.as_bytes()).map_err(|_| FondantError::FileWriteError); + Ok(()) + } + } + }; + gen.into() +} -- cgit v1.2.3