diff options
| author | Jokler <jokler.contact@gmail.com> | 2018-03-02 22:11:21 +0100 |
|---|---|---|
| committer | Jokler <jokler.contact@gmail.com> | 2018-03-02 22:11:21 +0100 |
| commit | 0b4131e8cf91ed10f24d3faed341034d518aea53 (patch) | |
| tree | 09498ec2f2ec495a1b45a6762e61ed67f496c6f8 /frippy_derive | |
| parent | 0bcc7c0923852b48ebbb94ceeecc98f551fa920d (diff) | |
| download | frippy-0b4131e8cf91ed10f24d3faed341034d518aea53.tar.gz frippy-0b4131e8cf91ed10f24d3faed341034d518aea53.zip | |
Use Error & ErrorKind pair instead of simple enums
Each plugin should define its own errors with a respective variant
in the main ErrorKind of frippy.
A new procedural macro was added to reduce the boilerplate required
for new error system.
It can be used by deriving "Error" and adding a name for the Error
via the "error" attribute.
So far non of the plugins except for Url and Factoids
use their own errors yet.
Diffstat (limited to 'frippy_derive')
| -rw-r--r-- | frippy_derive/Cargo.toml | 5 | ||||
| -rw-r--r-- | frippy_derive/src/lib.rs | 86 |
2 files changed, 86 insertions, 5 deletions
diff --git a/frippy_derive/Cargo.toml b/frippy_derive/Cargo.toml index 937afba..b258f57 100644 --- a/frippy_derive/Cargo.toml +++ b/frippy_derive/Cargo.toml @@ -7,5 +7,6 @@ authors = ["Jokler <jokler.contact@gmail.com>"] proc-macro = true [dependencies] -syn = "0.11.11" -quote = "0.3.15" +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 index 2622f0b..efa349a 100644 --- a/frippy_derive/src/lib.rs +++ b/frippy_derive/src/lib.rs @@ -1,18 +1,20 @@ - //! 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_derive_input(&data.to_string()).unwrap(); + let ast = syn::parse(data).unwrap(); let gen = expand_plugin(&ast); - gen.parse().unwrap() + gen.into() } fn expand_plugin(ast: &syn::DeriveInput) -> quote::Tokens { @@ -27,3 +29,81 @@ fn expand_plugin(ast: &syn::DeriveInput) -> quote::Tokens { } } } + +#[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) + } + } + } +} |
