aboutsummaryrefslogtreecommitdiffstats
path: root/frippy_derive/src/lib.rs
diff options
context:
space:
mode:
authorJokler <jokler.contact@gmail.com>2018-03-02 22:11:21 +0100
committerJokler <jokler.contact@gmail.com>2018-03-02 22:11:21 +0100
commit0b4131e8cf91ed10f24d3faed341034d518aea53 (patch)
tree09498ec2f2ec495a1b45a6762e61ed67f496c6f8 /frippy_derive/src/lib.rs
parent0bcc7c0923852b48ebbb94ceeecc98f551fa920d (diff)
downloadfrippy-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/src/lib.rs')
-rw-r--r--frippy_derive/src/lib.rs86
1 files changed, 83 insertions, 3 deletions
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)
+ }
+ }
+ }
+}