summaryrefslogtreecommitdiffstats
path: root/frippy_derive
diff options
context:
space:
mode:
authorJokler <jokler.contact@gmail.com>2018-03-12 16:02:51 +0100
committerJokler <jokler.contact@gmail.com>2018-03-12 16:02:51 +0100
commit909cabe9280722e43c5fb283f768051bb85e1890 (patch)
tree506ac34b7e22cdb95568cef9e649ee64cb3b0fdb /frippy_derive
parent15e855ddecfdac31ddda26b12fcfd1a142a0ec21 (diff)
parent8e40e919aca8b8592be43e2c5bbcc0717bf14a6b (diff)
downloadfrippy-909cabe9280722e43c5fb283f768051bb85e1890.tar.gz
frippy-909cabe9280722e43c5fb283f768051bb85e1890.zip
Merge branch 'dev'
Diffstat (limited to 'frippy_derive')
-rw-r--r--frippy_derive/Cargo.toml12
-rw-r--r--frippy_derive/src/lib.rs109
2 files changed, 121 insertions, 0 deletions
diff --git a/frippy_derive/Cargo.toml b/frippy_derive/Cargo.toml
new file mode 100644
index 0000000..b258f57
--- /dev/null
+++ b/frippy_derive/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "frippy_derive"
+version = "0.1.0"
+authors = ["Jokler <jokler.contact@gmail.com>"]
+
+[lib]
+proc-macro = true
+
+[dependencies]
+syn = "0.12.13"
+quote = "0.4.2"
+failure = "0.1.1"
diff --git a/frippy_derive/src/lib.rs b/frippy_derive/src/lib.rs
new file mode 100644
index 0000000..efa349a
--- /dev/null
+++ b/frippy_derive/src/lib.rs
@@ -0,0 +1,109 @@
+//! Provides the plugin derive macro
+#![recursion_limit="128"]
+
+extern crate proc_macro;
+extern crate syn;
+#[macro_use]
+extern crate quote;
+
+extern crate failure;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(PluginName)]
+pub fn derive_plugin(data: TokenStream) -> TokenStream {
+ let ast = syn::parse(data).unwrap();
+ let gen = expand_plugin(&ast);
+ gen.into()
+}
+
+fn expand_plugin(ast: &syn::DeriveInput) -> quote::Tokens {
+ let name = &ast.ident;
+ let generics = &ast.generics;
+ let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
+ quote! {
+ impl #impl_generics PluginName for #name #ty_generics #where_clause {
+ fn name(&self) -> &str {
+ stringify!(#name)
+ }
+ }
+ }
+}
+
+#[proc_macro_derive(Error, attributes(error))]
+pub fn derive_error(data: TokenStream) -> TokenStream {
+ let ast = syn::parse(data).unwrap();
+ let tokens = expand_error(&ast);
+ // panic!("{}", tokens.to_string());
+ tokens.into()
+}
+
+fn expand_error(ast: &syn::DeriveInput) -> quote::Tokens {
+ if let syn::Data::Enum(_) = ast.data {
+ } else {
+ panic!("Error should only be derived on ErrorKind enums");
+ };
+
+ let mut name = None;
+ for attr in &ast.attrs {
+ if let Some(syn::Meta::NameValue(name_value)) = attr.interpret_meta() {
+ if "error" == name_value.ident.to_string() {
+ if let syn::Lit::Str(lit) = name_value.lit {
+ name = Some(lit.value());
+ }
+ }
+ }
+ };
+
+ let struct_name = if let Some(name) = name {
+ syn::Ident::from(name)
+ } else {
+ panic!("Define the error attribute for all Error derives");
+ };
+
+ let enum_name = &ast.ident;
+
+ quote! {
+ #[derive(Debug)]
+ pub struct #struct_name {
+ inner: ::failure::Context<#enum_name>,
+ }
+
+ impl #struct_name {
+ pub fn kind(&self) -> #enum_name {
+ *self.inner.get_context()
+ }
+ }
+
+ impl From<#enum_name> for #struct_name {
+ fn from(kind: #enum_name) -> #struct_name {
+ #struct_name {
+ inner: ::failure::Context::new(kind),
+ }
+ }
+ }
+
+ impl From<::failure::Context<#enum_name>> for #struct_name {
+ fn from(inner: ::failure::Context<#enum_name>) -> #struct_name {
+ #struct_name { inner: inner }
+ }
+ }
+
+ impl ::failure::Fail for #struct_name {
+ fn cause(&self) -> Option<&::failure::Fail> {
+ self.inner.cause()
+ }
+
+ fn backtrace(&self) -> Option<&::failure::Backtrace> {
+ self.inner.backtrace()
+ }
+ }
+
+ impl ::std::fmt::Display for #struct_name {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ use std::fmt;
+ fmt::Display::fmt(&self.inner, f)
+ }
+ }
+ }
+}