macro_rules! custom_error {
(
$( #[$meta_attribute:meta] )* // Attributes, like #[derive(SomeTrait)]
$visibility:vis // `pub` marker
$errtype:ident // Name of the error type to generate
$( < $(
$type_param:tt // Optional type parameters for generic error types
),*
> )?
$(
$( #[$field_meta:meta] )* // Meta-attributes for the variant, such as a doc comment
$field:ident // Name of an error variant
$( { $(
$( #[$attr_meta:meta] )* // Meta-attributes for the attribute of the error variant
$attr_name:ident // Name of an attribute of the error variant
:
$attr_type:ty // type of the attribute
),* } )?
=
$( @{ $($msg_fun:tt)* } )?
$($msg:expr)? // The human-readable error message
),*
$(,)* // Trailing comma
) => { ... };
(
$( #[$meta_attribute:meta] )* // Attributes, like #[derive(SomeTrait)]
$visibility:vis // `pub` marker
$errtype:ident // Name of the error type to generate
$( < $(
$type_param:tt // Optional type parameters for generic error types
),*
> )?
{ $(
$( #[$field_meta:meta] )* // Field meta attributes, such as doc comments
$field_name:ident // Name of an attribute of the error variant
:
$field_type:ty // type of the attribute
),* }
=
$( @{ $($msg_fun:tt)* } )?
$($msg:expr)? // The human-readable error message
$(,)* // Trailing comma
) => { ... };
}
Expand description
Constructs a custom error type.
§Examples
§Simple error
For an error with multiple cases you can generate an enum:
use custom_error::custom_error;
custom_error! { pub MyError
Bad = "Something bad happened",
Terrible = "This is a very serious error!!!"
}
assert_eq!("Something bad happened", MyError::Bad.to_string());
assert_eq!(
"This is a very serious error!!!",
MyError::Terrible.to_string()
);
For an error with a single case you can generate a struct:
use custom_error::custom_error;
custom_error! { pub MyError{} = "Something bad happened" }
assert_eq!("Something bad happened", MyError {}.to_string());
§Custom error with parameters
use custom_error::custom_error;
custom_error!{SantaError
BadChild{name:String, foolishness:u8} = "{name} has been bad {foolishness} times this year",
TooFar = "The location you indicated is too far from the north pole",
InvalidReindeer{legs:u8} = "The reindeer has {legs} legs"
}
assert_eq!(
"Thomas has been bad 108 times this year",
SantaError::BadChild{
name: "Thomas".into(),
foolishness: 108
}.to_string());
assert_eq!(
"The location you indicated is too far from the north pole",
SantaError::TooFar.to_string()
);
assert_eq!(
"The reindeer has 8 legs",
SantaError::InvalidReindeer{legs:8}.to_string()
);
§Automatic conversion from other error types
You can add a special field named source
to your error types.
Use this field to include the lower-level source of the error.
It will be used in the error
source()
method, and automatic conversion from the source error type to your custom error type will be possible
(your error type will implement From<SourceErrorType>
).
§limitations
- You cannot have several error cases that contain a single source field of the same type:
custom_error!(E A{source:X} B{source:Y})
is allowed, butcustom_error!(E A{source:X} B{source:X})
is forbidden. - If the source field is not the only one, then the automatic conversion will not be implemented.
- The type of source must be valid for the
'static
lifetime (because of the type signature of thesource()
method). You can still have a field with a non-static type that you will not namesource
, and manually implement the error conversion from this type to your error type.
use std::{fs::File, io, io::Read, result::Result};
use custom_error::custom_error;
custom_error! {MyError
IO{source: io::Error} = "input/output error",
Unknown = "unknown error"
}
fn read_file(filename: &str) -> Result<String, MyError> {
let mut res = String::new();
File::open(filename)?.read_to_string(&mut res)?;
Ok(res)
}
assert_eq!(
"input/output error",
read_file("/i'm not a file/").unwrap_err().to_string()
)
§Custom formatting function for error messages
If the format string syntax is not enough to express your complex error formatting needs, you can use custom code to generate your error description.
use custom_error::custom_error;
static LANG: &'static str = "FR";
custom_error! { pub MyError
Problem = @{ localize(LANG, "A problem occurred") },
}
assert_eq!("Un problème est survenu", MyError::Problem.to_string());
use std::io::Error;
use std::io::ErrorKind::*;
use custom_error::custom_error;
custom_error! { pub MyError
Io{source: Error} = @{
match source.kind() {
NotFound => "The file does not exist",
TimedOut => "The operation timed out",
_ => "unknown error",
}
},
}
assert_eq!(
"The operation timed out",
MyError::Io {
source: TimedOut.into()
}
.to_string()
);
§Derive traits for your errors
You can add custom attributes at the beginning of the macro invocation. This allows you to derive traits for your error:
use custom_error::custom_error;
custom_error! {
#[derive(PartialEq,PartialOrd)]
ErrLevel Small = "Don't worry", Serious = "Aaargh!!!"
}
assert_ne!(ErrLevel::Small, ErrLevel::Serious);
assert!(ErrLevel::Small < ErrLevel::Serious);