summaryrefslogtreecommitdiffstats
path: root/third_party/rust/failure_derive
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/rust/failure_derive/.cargo-checksum.json1
-rw-r--r--third_party/rust/failure_derive/Cargo.toml27
-rw-r--r--third_party/rust/failure_derive/build.rs39
-rw-r--r--third_party/rust/failure_derive/src/lib.rs266
-rw-r--r--third_party/rust/failure_derive/tests/backtrace.rs64
-rw-r--r--third_party/rust/failure_derive/tests/custom_type_bounds.rs45
-rw-r--r--third_party/rust/failure_derive/tests/no_derive_display.rs21
-rw-r--r--third_party/rust/failure_derive/tests/tests.rs55
-rw-r--r--third_party/rust/failure_derive/tests/wraps.rs98
9 files changed, 616 insertions, 0 deletions
diff --git a/third_party/rust/failure_derive/.cargo-checksum.json b/third_party/rust/failure_derive/.cargo-checksum.json
new file mode 100644
index 0000000000..3a26be720c
--- /dev/null
+++ b/third_party/rust/failure_derive/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"40252e61dfb5eaaa297f868379972f5135e1e8e2d37a8b31858c00d3e765282e","build.rs":"c7481c027fc4c09e2d6dc8ac642ec5314b6a02269fb022b0f3c1850f000d31f5","src/lib.rs":"c446d83b42f5aca4453da4e2dd8e40dbfe9aa33ba1a038217174ece5158b7196","tests/backtrace.rs":"56b2b97f83e5341108aac403a50491560dc6d897d6002973248c9c9014c0e494","tests/custom_type_bounds.rs":"745d3e488738f5d90bcb1fa66a6784b64a88881b1d62c241cba2f863f4eb31c8","tests/no_derive_display.rs":"3ab159aadf809a95d578b4909470f6ecca24cea0caf514509d326601cc7b933b","tests/tests.rs":"eaf131c01cc101b94fd6478a9964f5e3d919f2260f6d327f0e435ac3520fe71e","tests/wraps.rs":"cc2bc5a5555756082ec570afa310939ba7f74a20898991a89fab75232380fd21"},"package":null} \ No newline at end of file
diff --git a/third_party/rust/failure_derive/Cargo.toml b/third_party/rust/failure_derive/Cargo.toml
new file mode 100644
index 0000000000..ec45dc0b1d
--- /dev/null
+++ b/third_party/rust/failure_derive/Cargo.toml
@@ -0,0 +1,27 @@
+[package]
+authors = ["Without Boats <woboats@gmail.com>"]
+description = "derives for the failure crate"
+license = "MIT OR Apache-2.0"
+name = "failure_derive"
+repository = "https://github.com/withoutboats/failure_derive"
+homepage = "https://rust-lang-nursery.github.io/failure/"
+documentation = "https://docs.rs/failure"
+version = "0.1.6"
+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 = []
diff --git a/third_party/rust/failure_derive/build.rs b/third_party/rust/failure_derive/build.rs
new file mode 100644
index 0000000000..8f220458d2
--- /dev/null
+++ b/third_party/rust/failure_derive/build.rs
@@ -0,0 +1,39 @@
+use 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
+}
diff --git a/third_party/rust/failure_derive/src/lib.rs b/third_party/rust/failure_derive/src/lib.rs
new file mode 100644
index 0000000000..fe9e76c4e3
--- /dev/null
+++ b/third_party/rust/failure_derive/src/lib.rs
@@ -0,0 +1,266 @@
+extern 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<syn::Error> 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<TokenStream, Error> {
+ 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<Option<quote::__rt::TokenStream>, 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::<usize>()?];
+ 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::<usize>() {
+ 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::<Result<Vec<_>, _>>()?;
+
+ 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<Option<syn::MetaList>, 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
+}
diff --git a/third_party/rust/failure_derive/tests/backtrace.rs b/third_party/rust/failure_derive/tests/backtrace.rs
new file mode 100644
index 0000000000..a307184112
--- /dev/null
+++ b/third_party/rust/failure_derive/tests/backtrace.rs
@@ -0,0 +1,64 @@
+extern 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());
+}
diff --git a/third_party/rust/failure_derive/tests/custom_type_bounds.rs b/third_party/rust/failure_derive/tests/custom_type_bounds.rs
new file mode 100644
index 0000000000..fd1c8b975b
--- /dev/null
+++ b/third_party/rust/failure_derive/tests/custom_type_bounds.rs
@@ -0,0 +1,45 @@
+#[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: 'static + Debug + Send + Sync>(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: Fail>(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: NoDisplay>(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.\""
+ );
+}
diff --git a/third_party/rust/failure_derive/tests/no_derive_display.rs b/third_party/rust/failure_derive/tests/no_derive_display.rs
new file mode 100644
index 0000000000..20eeb308c2
--- /dev/null
+++ b/third_party/rust/failure_derive/tests/no_derive_display.rs
@@ -0,0 +1,21 @@
+extern 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.");
+}
diff --git a/third_party/rust/failure_derive/tests/tests.rs b/third_party/rust/failure_derive/tests/tests.rs
new file mode 100644
index 0000000000..4e73255ef3
--- /dev/null
+++ b/third_party/rust/failure_derive/tests/tests.rs
@@ -0,0 +1,55 @@
+extern 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.");
+}
diff --git a/third_party/rust/failure_derive/tests/wraps.rs b/third_party/rust/failure_derive/tests/wraps.rs
new file mode 100644
index 0000000000..9144325cad
--- /dev/null
+++ b/third_party/rust/failure_derive/tests/wraps.rs
@@ -0,0 +1,98 @@
+extern 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::<io::Error>())
+ .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::<io::Error>())
+ .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::<io::Error>())
+ .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::<io::Error>())
+ .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::<fmt::Error>())
+ .is_some());
+ assert!(err.backtrace().is_some());
+ assert!(err.backtrace().unwrap().is_empty());
+ assert!(err.backtrace().unwrap().to_string().trim().is_empty());
+}