failure_derive-0.1.7/.gitignore0100644*Sq{000000000221363022206600156360ustar0000000000000000Cargo.lock target failure_derive-0.1.7/Cargo.toml.orig0100644*Sq{000000011531363022270000165360ustar0000000000000000[package] authors = ["Without Boats "] description = "derives for the failure crate" license = "MIT OR Apache-2.0" name = "failure_derive" repository = "https://github.com/rust-lang-nursery/failure" homepage = "https://rust-lang-nursery.github.io/failure/" documentation = "https://docs.rs/failure" version = "0.1.7" build = "build.rs" [dependencies] quote = "1" syn = "1.0.3" synstructure = "0.12.0" proc-macro2 = "1" [dev-dependencies.failure] version = "0.1.0" path = ".." [lib] proc-macro = true [features] # This is kept for backward-compatibility reasons, but is otherwise a no-op std = [] failure_derive-0.1.7/Cargo.toml0000644000000021561363022323000121200ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "failure_derive" version = "0.1.7" authors = ["Without Boats "] build = "build.rs" description = "derives for the failure crate" homepage = "https://rust-lang-nursery.github.io/failure/" documentation = "https://docs.rs/failure" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang-nursery/failure" [lib] proc-macro = true [dependencies.proc-macro2] version = "1" [dependencies.quote] version = "1" [dependencies.syn] version = "1.0.3" [dependencies.synstructure] version = "0.12.0" [dev-dependencies.failure] version = "0.1.0" [features] std = [] failure_derive-0.1.7/build.rs0100644*Sq{000000015331363022206600153230ustar0000000000000000use std::env; use std::process::Command; use std::str; use std::str::FromStr; fn main() { if rustc_has_dyn_trait() { println!("cargo:rustc-cfg=has_dyn_trait"); } } fn rustc_has_dyn_trait() -> bool { let rustc = match env::var_os("RUSTC") { Some(rustc) => rustc, None => return false, }; let output = match Command::new(rustc).arg("--version").output() { Ok(output) => output, Err(_) => return false, }; let version = match str::from_utf8(&output.stdout) { Ok(version) => version, Err(_) => return false, }; let mut pieces = version.split('.'); if pieces.next() != Some("rustc 1") { return true; } let next = match pieces.next() { Some(next) => next, None => return false, }; u32::from_str(next).unwrap_or(0) >= 27 } failure_derive-0.1.7/src/lib.rs0100644*Sq{000000207671363022206600155730ustar0000000000000000extern crate proc_macro2; extern crate syn; #[macro_use] extern crate synstructure; #[macro_use] extern crate quote; use proc_macro2::{TokenStream, Span}; use syn::LitStr; use syn::spanned::Spanned; #[derive(Debug)] struct Error(TokenStream); impl Error { fn new(span: Span, message: &str) -> Error { Error(quote_spanned! { span => compile_error!(#message); }) } fn into_tokens(self) -> TokenStream { self.0 } } impl From for Error { fn from(e: syn::Error) -> Error { Error(e.to_compile_error()) } } decl_derive!([Fail, attributes(fail, cause)] => fail_derive); fn fail_derive(s: synstructure::Structure) -> TokenStream { match fail_derive_impl(s) { Err(err) => err.into_tokens(), Ok(tokens) => tokens, } } fn fail_derive_impl(s: synstructure::Structure) -> Result { let make_dyn = if cfg!(has_dyn_trait) { quote! { &dyn } } else { quote! { & } }; let ty_name = LitStr::new(&s.ast().ident.to_string(), Span::call_site()); let cause_body = s.each_variant(|v| { if let Some(cause) = v.bindings().iter().find(is_cause) { quote!(return Some(::failure::AsFail::as_fail(#cause))) } else { quote!(return None) } }); let bt_body = s.each_variant(|v| { if let Some(bi) = v.bindings().iter().find(is_backtrace) { quote!(return Some(#bi)) } else { quote!(return None) } }); let fail = s.unbound_impl( quote!(::failure::Fail), quote! { fn name(&self) -> Option<&str> { Some(concat!(module_path!(), "::", #ty_name)) } #[allow(unreachable_code)] fn cause(&self) -> ::failure::_core::option::Option<#make_dyn(::failure::Fail)> { match *self { #cause_body } None } #[allow(unreachable_code)] fn backtrace(&self) -> ::failure::_core::option::Option<&::failure::Backtrace> { match *self { #bt_body } None } }, ); let display = display_body(&s)?.map(|display_body| { s.unbound_impl( quote!(::failure::_core::fmt::Display), quote! { #[allow(unreachable_code)] fn fmt(&self, f: &mut ::failure::_core::fmt::Formatter) -> ::failure::_core::fmt::Result { match *self { #display_body } write!(f, "An error has occurred.") } }, ) }); Ok(quote! { #fail #display }) } fn display_body(s: &synstructure::Structure) -> Result, Error> { let mut msgs = s.variants().iter().map(|v| find_error_msg(&v.ast().attrs)); if msgs.all(|msg| msg.map(|m| m.is_none()).unwrap_or(true)) { return Ok(None); } let mut tokens = TokenStream::new(); for v in s.variants() { let msg = find_error_msg(&v.ast().attrs)? .ok_or_else(|| Error::new( v.ast().ident.span(), "All variants must have display attribute." ))?; if msg.nested.is_empty() { return Err(Error::new( msg.span(), "Expected at least one argument to fail attribute" )); } let format_string = match msg.nested[0] { syn::NestedMeta::Meta(syn::Meta::NameValue(ref nv)) if nv.path.is_ident("display") => { nv.lit.clone() } _ => { return Err(Error::new( msg.span(), "Fail attribute must begin `display = \"\"` to control the Display message." )); } }; let args = msg.nested.iter().skip(1).map(|arg| match *arg { syn::NestedMeta::Lit(syn::Lit::Int(ref i)) => { let bi = &v.bindings()[i.base10_parse::()?]; Ok(quote!(#bi)) } syn::NestedMeta::Meta(syn::Meta::Path(ref path)) => { let id_s = path.get_ident().map(syn::Ident::to_string).unwrap_or("".to_string()); if id_s.starts_with("_") { if let Ok(idx) = id_s[1..].parse::() { let bi = match v.bindings().get(idx) { Some(bi) => bi, None => { return Err(Error::new( arg.span(), &format!( "display attempted to access field `{}` in `{}::{}` which \ does not exist (there are {} field{})", idx, s.ast().ident, v.ast().ident, v.bindings().len(), if v.bindings().len() != 1 { "s" } else { "" } ) )); } }; return Ok(quote!(#bi)); } } for bi in v.bindings() { let id = bi.ast().ident.as_ref(); if id.is_some() && path.is_ident(id.unwrap()) { return Ok(quote!(#bi)); } } return Err(Error::new( arg.span(), &format!( "Couldn't find field `{:?}` in `{}::{}`", path, s.ast().ident, v.ast().ident ) )); } ref arg => { return Err(Error::new( arg.span(), "Invalid argument to fail attribute!" )); }, }); let args = args.collect::, _>>()?; let pat = v.pat(); tokens.extend(quote!(#pat => { return write!(f, #format_string #(, #args)*) })); } Ok(Some(tokens)) } fn find_error_msg(attrs: &[syn::Attribute]) -> Result, Error> { let mut error_msg = None; for attr in attrs { if let Ok(meta) = attr.parse_meta() { if meta.path().is_ident("fail") { if error_msg.is_some() { return Err(Error::new( meta.span(), "Cannot have two display attributes" )); } else { if let syn::Meta::List(list) = meta { error_msg = Some(list); } else { return Err(Error::new( meta.span(), "fail attribute must take a list in parentheses" )); } } } } } Ok(error_msg) } fn is_backtrace(bi: &&synstructure::BindingInfo) -> bool { match bi.ast().ty { syn::Type::Path(syn::TypePath { qself: None, path: syn::Path { segments: ref path, .. }, }) => path.last().map_or(false, |s| { s.ident == "Backtrace" && s.arguments.is_empty() }), _ => false, } } fn is_cause(bi: &&synstructure::BindingInfo) -> bool { let mut found_cause = false; for attr in &bi.ast().attrs { if let Ok(meta) = attr.parse_meta() { if meta.path().is_ident("cause") { if found_cause { panic!("Cannot have two `cause` attributes"); } found_cause = true; } if meta.path().is_ident("fail") { if let syn::Meta::List(ref list) = meta { if let Some(ref pair) = list.nested.first() { if let &&syn::NestedMeta::Meta(syn::Meta::Path(ref path)) = pair { if path.is_ident("cause") { if found_cause { panic!("Cannot have two `cause` attributes"); } found_cause = true; } } } } } } } found_cause } failure_derive-0.1.7/tests/backtrace.rs0100644*Sq{000000032601363022206600173040ustar0000000000000000extern crate failure; #[macro_use] extern crate failure_derive; use failure::{Backtrace, Fail}; #[derive(Fail, Debug)] #[fail(display = "Error code: {}", code)] struct BacktraceError { backtrace: Backtrace, code: u32, } #[test] fn backtrace_error() { let err = BacktraceError { backtrace: Backtrace::new(), code: 7, }; let s = format!("{}", err); assert_eq!(&s[..], "Error code: 7"); assert!(err.backtrace().is_some()); } #[derive(Fail, Debug)] #[fail(display = "An error has occurred.")] struct BacktraceTupleError(Backtrace); #[test] fn backtrace_tuple_error() { let err = BacktraceTupleError(Backtrace::new()); let s = format!("{}", err); assert_eq!(&s[..], "An error has occurred."); assert!(err.backtrace().is_some()); } #[derive(Fail, Debug)] enum BacktraceEnumError { #[fail(display = "Error code: {}", code)] StructVariant { code: i32, backtrace: Backtrace }, #[fail(display = "Error: {}", _0)] TupleVariant(&'static str, Backtrace), #[fail(display = "An error has occurred.")] UnitVariant, } #[test] fn backtrace_enum_error() { let err = BacktraceEnumError::StructVariant { code: 2, backtrace: Backtrace::new(), }; let s = format!("{}", err); assert_eq!(&s[..], "Error code: 2"); assert!(err.backtrace().is_some()); let err = BacktraceEnumError::TupleVariant("foobar", Backtrace::new()); let s = format!("{}", err); assert_eq!(&s[..], "Error: foobar"); assert!(err.backtrace().is_some()); let err = BacktraceEnumError::UnitVariant; let s = format!("{}", err); assert_eq!(&s[..], "An error has occurred."); assert!(err.backtrace().is_none()); } failure_derive-0.1.7/tests/custom_type_bounds.rs0100644*Sq{000000023161363022206600213130ustar0000000000000000#[macro_use] extern crate failure; use std::fmt::Debug; use failure::Fail; #[derive(Debug, Fail)] #[fail(display = "An error has occurred.")] pub struct UnboundedGenericTupleError(T); #[test] fn unbounded_generic_tuple_error() { let s = format!("{}", UnboundedGenericTupleError(())); assert_eq!(&s[..], "An error has occurred."); } #[derive(Debug, Fail)] #[fail(display = "An error has occurred: {}", _0)] pub struct FailBoundsGenericTupleError(T); #[test] fn fail_bounds_generic_tuple_error() { let error = FailBoundsGenericTupleError(UnboundedGenericTupleError(())); let s = format!("{}", error); assert_eq!(&s[..], "An error has occurred: An error has occurred."); } pub trait NoDisplay: 'static + Debug + Send + Sync {} impl NoDisplay for &'static str {} #[derive(Debug, Fail)] #[fail(display = "An error has occurred: {:?}", _0)] pub struct CustomBoundsGenericTupleError(T); #[test] fn custom_bounds_generic_tuple_error() { let error = CustomBoundsGenericTupleError("more details unavailable."); let s = format!("{}", error); assert_eq!( &s[..], "An error has occurred: \"more details unavailable.\"" ); } failure_derive-0.1.7/tests/no_derive_display.rs0100644*Sq{000000006451363022206600210700ustar0000000000000000extern crate failure; #[macro_use] extern crate failure_derive; use failure::Fail; use std::fmt::{self, Display}; #[derive(Debug, Fail)] struct Foo; impl Display for Foo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("An error occurred.") } } #[test] fn handwritten_display() { assert!(Foo.cause().is_none()); assert_eq!(&format!("{}", Foo)[..], "An error occurred."); } failure_derive-0.1.7/tests/tests.rs0100644*Sq{000000024201363022206600165240ustar0000000000000000extern crate failure; #[macro_use] extern crate failure_derive; #[derive(Fail, Debug)] #[fail(display = "An error has occurred.")] struct UnitError; #[test] fn unit_struct() { let s = format!("{}", UnitError); assert_eq!(&s[..], "An error has occurred."); } #[derive(Fail, Debug)] #[fail(display = "Error code: {}", code)] struct RecordError { code: u32, } #[test] fn record_struct() { let s = format!("{}", RecordError { code: 0 }); assert_eq!(&s[..], "Error code: 0"); } #[derive(Fail, Debug)] #[fail(display = "Error code: {}", _0)] struct TupleError(i32); #[test] fn tuple_struct() { let s = format!("{}", TupleError(2)); assert_eq!(&s[..], "Error code: 2"); } #[derive(Fail, Debug)] enum EnumError { #[fail(display = "Error code: {}", code)] StructVariant { code: i32 }, #[fail(display = "Error: {}", _0)] TupleVariant(&'static str), #[fail(display = "An error has occurred.")] UnitVariant, } #[test] fn enum_error() { let s = format!("{}", EnumError::StructVariant { code: 2 }); assert_eq!(&s[..], "Error code: 2"); let s = format!("{}", EnumError::TupleVariant("foobar")); assert_eq!(&s[..], "Error: foobar"); let s = format!("{}", EnumError::UnitVariant); assert_eq!(&s[..], "An error has occurred."); } failure_derive-0.1.7/tests/wraps.rs0100644*Sq{000000047521363022206600165300ustar0000000000000000extern crate failure; #[macro_use] extern crate failure_derive; use std::fmt; use std::io; use failure::{Backtrace, Fail}; #[derive(Fail, Debug)] #[fail(display = "An error has occurred: {}", inner)] struct WrapError { #[fail(cause)] inner: io::Error, } #[test] fn wrap_error() { let inner = io::Error::from_raw_os_error(98); let err = WrapError { inner }; assert!(err .cause() .and_then(|err| err.downcast_ref::()) .is_some()); } #[derive(Fail, Debug)] #[fail(display = "An error has occurred: {}", _0)] struct WrapTupleError(#[fail(cause)] io::Error); #[test] fn wrap_tuple_error() { let io_error = io::Error::from_raw_os_error(98); let err: WrapTupleError = WrapTupleError(io_error); assert!(err .cause() .and_then(|err| err.downcast_ref::()) .is_some()); } #[derive(Fail, Debug)] #[fail(display = "An error has occurred: {}", inner)] struct WrapBacktraceError { #[fail(cause)] inner: io::Error, backtrace: Backtrace, } #[test] fn wrap_backtrace_error() { let inner = io::Error::from_raw_os_error(98); let err: WrapBacktraceError = WrapBacktraceError { inner, backtrace: Backtrace::new(), }; assert!(err .cause() .and_then(|err| err.downcast_ref::()) .is_some()); assert!(err.backtrace().is_some()); assert!(err.backtrace().unwrap().is_empty()); assert!(err.backtrace().unwrap().to_string().trim().is_empty()); } #[derive(Fail, Debug)] enum WrapEnumError { #[fail(display = "An error has occurred: {}", _0)] Io(#[fail(cause)] io::Error), #[fail(display = "An error has occurred: {}", inner)] Fmt { #[fail(cause)] inner: fmt::Error, backtrace: Backtrace, }, } #[test] fn wrap_enum_error() { let io_error = io::Error::from_raw_os_error(98); let err: WrapEnumError = WrapEnumError::Io(io_error); assert!(err .cause() .and_then(|err| err.downcast_ref::()) .is_some()); assert!(err.backtrace().is_none()); let fmt_error = fmt::Error::default(); let err: WrapEnumError = WrapEnumError::Fmt { inner: fmt_error, backtrace: Backtrace::new(), }; assert!(err .cause() .and_then(|err| err.downcast_ref::()) .is_some()); assert!(err.backtrace().is_some()); assert!(err.backtrace().unwrap().is_empty()); assert!(err.backtrace().unwrap().to_string().trim().is_empty()); } failure_derive-0.1.7/.cargo_vcs_info.json0000644000000001121363022323000141100ustar00{ "git": { "sha1": "e7817e4044449c2b57ff8babca42b7b72eb2d99d" } }