Implement a trait for another trait Item type - error-handling

I need to convert a parse error to my own Error type while returning Result. Simplified, it looks like the following:
enum MyError {
Parse,
...,
}
fn process<R: FromStr>(s: &str) -> Result<(), MyError> {
Ok(s.parse::<R>()?)
}
For above to work From trait should be implemented. This doesn't work:
impl From<std::str::FromStr::Err> for MyError {
fn from(e: std::str::FromStr::Err) -> MyError {
MyError::Parse
}
}
The compiler diagnostics:
help: use fully-qualified syntax: `<Type as std::str::FromStr>::Err`
But I don't know the exact Type here. The whole point is to allow conversion from all possible errors.

The type FromStr::Err is an associated type of the FromStr trait. Every implementation of FromStr has its own associated type, and this type is completely unconstrained – it could be any type at all. This means you would need a conversion from any type to MyError to achieve what you want:
impl<T> From<T> for MyError {
fn from(e: T) -> MyError {
MyError::Parse
}
}
However, this implementation is disallowed by the coherence rules – it conflicts with the implementation of From<T> for any type T in the standard library. And even if this implementation was allowed, it wouldn't really do what you want – any error type would be converted to MyError::Parse, not just parse errors.
One possible workaround is to introduce a marker trait for parse error types:
trait ParseError {}
impl<T: ParseError> From<T> for MyError {
fn from(e: T) -> MyError {
MyError::Parse
}
}
You can then implement this marker trait for all parse error types:
impl ParseError for std::str::ParseBoolError {}
impl ParseError for std::num::ParseFloatError {}
impl ParseError for std::num::ParseIntError {}
impl ParseError for std::net::AddrParseError {}
impl ParseError for std::char::ParseCharError {}

If you're discarding the parse error anyway, use map_err to change the error locally:
fn process<R: FromStr>(s: &str) -> Result<(), MyError> {
let _ = s.parse::<R>().map_err(|_| MyError::Parse)?;
Ok(())
}

Related

How do I solve this lifetime error for Serde Deserialize?

Goal: I would like to implement this trait without getting lifetime errors.
Dependencies: pqcrypto-dilithium = "0.4.5" and serde = {version = "1.0.138", features = ["derive"]}. Import this in Cargo.toml
Import:
pub use pqcrypto_dilithium::dilithium5::*;
pub use pqcrypto_dilithium::dilithium5::DetachedSignature;
pub use serde::ser::{SerializeTuple};
pub use serde::de::Visitor;
pub use serde::{Serialize, Serializer, Deserialize, Deserializer};
The Seriaize implementation functions properly but the Deserialization one has lifetime issues.
#[derive(Serialize, Deserialize)]
pub struct Keys {
pub public_key: pqcrypto_dilithium::dilithium5::PublicKey,
pub private_key: pqcrypto_dilithium::dilithium5::SecretKey,
}
impl Serialize for Keys {
fn serialize<S>(&self, serializer: &mut S) -> Result<S::Ok, S::Error>
where S: Serializer
{
let mut state = serializer.serialize_tuple(2)?;
state.serialize_element(&self.public_key)?;
state.serialize_element(&self.private_key)?;
state.end()
}
}
impl Deserialize<'de> for Keys {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
deserializer.deserialize_tuple(2, Visitor)
}
}
The problem here is in the deserialize implementation for Keys. I am getting this error.
use of undeclared lifetime name `'de`
undeclared lifetimerustcE0261
crypto.rs(36, 5): consider introducing lifetime `'de` here: `<'de>`
crypto.rs(37, 20): consider introducing lifetime `'de` here: `'de, `
[E0261] use of undeclared lifetime name `'de`.
[Note] undeclared lifetime
Correct Answer:
impl <'de> Deserialize<'de> for Keys {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer<'de>...

What's the idiomatic way of creating a Rust Error shim?

I have two error types that are defined in external crates. Let's call them foo::Error and bar::Error. Because they are both defined externally, I cannot create a direct From or Into conversion between the two.
In my own crate, I'm using implementing a trait from bar, which expects return values of Result<T, bar::Error>. In the methods of my implementation, I'm calling functions from foo, which return many Result<T, foo::Error> types.
I would like to map these foo::Error errors to bar::Error errors, so that my trait implementation is neat, but the best that I can do is create a separate shim error, and then have a clunky .map_err(ShimErr::from)? on everything. This can start to litter up my code if I'm calling many foo:: functions in my implementation.
use foo;
use bar;
struct ShimErr(foo::Error);
impl From<foo::Error> for ShimErr {
fn from(e: foo::Error) -> Self {
Self(e)
}
}
impl From<ShimErr> for bar::Error {
fn from(e: ShimErr) -> Self {
Self{}
}
}
struct MyTraitImpl {}
impl bar::SomeTrait for MyTraitImpl {
fn do_something() -> Result<i32, bar::Error> {
// FIXME: THIS IS CLUNKY
let foo_val: i32 = foo::call_something().map_err(ShimErr::from)?;
Ok(foo_val * 2)
}
}
Is there a better way? In an ideal world, there would be a way to just use ?
If I remove map_err and try to use ? directly:
error[E0277]: `?` couldn't convert the error to `bar::Error`
--> shimtest.rs:32:49
|
32 | let foo_val: i32 = foo::call_something()?;
| ^ the trait `std::convert::From<foo::Error>` is not implemented for `bar::Error`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following implementations were found:
<bar::Error as std::convert::From<ShimErr>>
= note: required by `std::convert::From::from`
The way I handle multiple different errors from other crates would be to make my own Error enum and use that instead of other errors directly.
So instead of a tuple struct that only contains foo::Error, you can create an enum that can have both foo::Error and bar::Error. After this, you can convert all the errors to the custom enum error with ?.
In certain cases, I think you'll still need to use something like .map_err(Into::into) occasionally, but usually only when the variable being returned is a Result with an external error.
use bar::Error as BarError;
use foo::Error as FooError;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::result::Result as StdResult;
/// Common result type that uses the custom error
pub type Result<T> = StdResult<T, Error>;
/// Common error type used as a holder for errors from various other libraries.
#[derive(Debug)]
pub enum Error {
Bar(BarError),
Foo(FooError),
}
impl From<BarError> for Error {
fn from(err: BarError) -> Error {
Error::Bar(err)
}
}
impl From<FooError> for Error {
fn from(err: FooError) -> Error {
Error::Foo(err)
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
match *self {
Error::Bar(ref inner) => inner.fmt(f),
Error::Foo(ref inner) => inner.fmt(f),
}
}
}
impl StdError for Error {
fn description(&self) -> &str {
match *self {
Error::Bar(ref inner) => inner.description(),
Error::Foo(ref inner) => inner.description(),
}
}
}
Now you can use the custom Result and Error as follows.
// this Result is now our custom Result type with custom error
// same as std::result::Result<i32, Error> (with Error as our custom error)
fn do_something() -> Result<i32> {
let foo_val: i32 = foo::call_something()?; // should convert to our custom error
Ok(foo_val * 2)
}
fn do_something_else() -> Result<i32> {
// directly returning a Result<> with a different error type will need map_err
foo::call_something().map_err(Into::into)
}

What is the most idiomatic way to merge two error types?

I have a type Foo whose methods may "raise" errors of an associated type Foo::Err.
pub trait Foo {
type Err;
fn foo(&mut self) -> Result<(), Self::Err>;
}
I have another trait Bar with a method intended to process a Foo. Bar may issue errors of its own (specified by an associated type Bar::Err), but it may also encounter errors generated by the Foo it is processing.
I can see two ways to do this, but I don't know which one would be the most idiomatic to Rust.
The first one embeds a result in a result:
pub trait Bar1 {
type Err;
fn bar<F: Foo>(&mut self, foo: F) -> Result<Result<F, F::Err>, Self::Err>;
}
The second one merges the two error types into a dedicated enum:
pub trait Bar2 {
type Err;
fn bar<F: Foo>(&mut self, foo: F) -> Result<F, Choice<F::Err, Self::Err>>;
}
The second one looks semantically cleaner, but creates some hurdles for handling the additional enum.
playground
Typically you don't do a "merge", but instead use nested errors, like this.
enum IntError {
Overflow,
Underflow
}
enum StrError {
TooLong,
TooShort,
}
enum GenericError {
Int(IntError),
Str(StrError),
}
impl From<IntError> for GenericError {
fn from(e: IntError) -> Self {
GenericError::Int(e)
}
}
impl From<StrError> for GenericError {
fn from(e: StrError) -> Self {
GenericError::Str(e)
}
}
You should use a trait object Error, and you return the first error that you encounter:
pub trait Bar {
fn bar<F: Foo>(&mut self, foo: F) -> Result<F, Box<dyn Error>>;
}
or implement your trait like this:
impl Bar for MyType {
type Err = Box<dyn Error>;
fn bar<F: Foo>(&mut self, foo: F) -> Result<F, Self::Err>;
}
If you really want to have your two errors (but this is strange because one error suffices to make the process not ok), you can use a crate like failure to create an "error trace".
As a general advice, you should not forget to use the traits from std to add more semantic to your code.

How to manually return a Result<(), Box<dyn Error>>?

I want to return an error from a function in case a condition is true:
use std::error::Error;
pub fn run() -> Result<(), Box<dyn Error>> {
// -- snip ---
if condition {
// return error
}
// -- snip --
Ok(())
}
fn main() {}
I probably don't have the basics of the typesystem down, but everywhere I looked people use the ? operator, so I can't figure out what type to return.
Is it possible to just return an error like this?
Is there a better way to handle this logic?
Error is a trait and you want to return a trait object (note the dyn keyword), so you need to implement this trait:
use std::error::Error;
use std::fmt;
#[derive(Debug)]
struct MyError(String);
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "There is an error: {}", self.0)
}
}
impl Error for MyError {}
pub fn run() -> Result<(), Box<dyn Error>> {
let condition = true;
if condition {
return Err(Box::new(MyError("Oops".into())));
}
Ok(())
}
fn main() {
if let Err(e) = run() {
println!("{}", e); // "There is an error: Oops"
}
}
Create your own error type,
Implement Debug, Display, then Error for it,
If there is an error, return the Err variant of Result.
I advise you to use failure that remove all the error boilerplate:
#[derive(Fail, Debug)]
#[fail(display = "There is an error: {}.", _0)]
struct MyError(String);
--
Note that if you expect an Error, you can return whatever type you want, given that it implements Error. This includes the error types in std.
To return custom errors, given that the function is set to return Result<(), Box<dyn Error>>:
fn serve(config: &Config, stream: TcpStream) -> Result<(), Box<dyn Error>> {
// ...
if request_is_bad() {
// This returns immediately a custom "Bad request" error
Err("Bad request")?;
}
// ...
}
Box<dyn Error> is handy for types that implement it:
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
Err("March")?
}
but surprisingly, it doesn't work with all types:
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
// the trait `std::error::Error` is not implemented for `{integer}`
Err(9)?
}
as a workaround, you can use what I call the Error Format idiom:
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
Err(format!("{}", 9))?
}
Note this has many variations, for example with literals you can do this:
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
Err(concat!(9))?
}
and also, you may not even need to use Box<dyn Error>:
fn main() -> Result<(), String> {
Err(concat!(9))?
}
It can also be useful in cases where you normally don't need it. For example, this example below could work without it, but it's useful as it adds the filename to the error, which normally isn't shown:
use std::fs;
fn main() -> Result<(), String> {
let s = "a.rs";
match fs::read_to_string(s) {
Ok(v) => print!("{}", v),
// normal message is just: The system cannot find the file specified
Err(v) => Err(format!("{} {}", s, v))?
}
Ok(())
}
A Result<T, E> is an enum with two variants. To return either of them, you just use corresponding variants.
fn foo(var: bool) -> Result<(), i32> {
if var {
Ok(()) //in fact this is std::result::Result::Ok
} else {
Err(-3) //in fact this is std::result::Result::Err
}
}
The reason why you don't have to write std::result::Result::Ok is that it is in the prelude. As you can see, you don't have to stick to Box<Error>, but can return any type you want. It is a generic enum, with no restrictions.
The ?-operator is a handy shortcut for early returns, so you don't have to be too verbose about results.

How do I use a trait object in a BinaryHeap? [duplicate]

Editor's note: This code example is from a version of Rust prior to 1.0 and is not syntactically valid Rust 1.0 code. Updated versions of this code produce different errors, but the answers still contain valuable information.
It seems like we cannot test for equality in the following case. Why is this? Is there a workaround? (I am using Rust 0.11).
trait A: PartialEq {}
#[deriving(PartialEq)]
enum T {Ta, Tb}
impl A for T {}
fn main() {
assert!(Ta == Ta);
assert!(Ta != Tb);
assert!(some_fn(&Ta, &Ta));
assert!(!some_fn(&Ta, &Tb));
}
fn some_fn(an_a: &A, another_a: &A) -> bool {
an_a == another_a
// ERROR ^~~~~~~~~~~~ binary operation `==` cannot be applied to type `&A`
}
fn another_fn(an_a: &A + PartialEq, another_a: &A + PartialEq) -> bool {
// ERROR: ^~~~~~~~~ only the builtin traits can be used as closure or object bounds
an_a == another_a
}
With help from Vladimir Matveev, I figured out how to use Any to downcast my trait to a concrete type and test the resulting value for equality:
// `Any` allows us to do dynamic typecasting.
use std::any::Any;
trait A {
// An &Any can be cast to a reference to a concrete type.
fn as_any(&self) -> &dyn Any;
// Perform the test.
fn equals_a(&self, _: &dyn A) -> bool;
}
#[derive(Debug, PartialEq)]
enum T {
Ta,
Tb,
}
// Implement A for all 'static types implementing PartialEq.
impl<S: 'static + PartialEq> A for S {
fn as_any(&self) -> &dyn Any {
self
}
fn equals_a(&self, other: &dyn A) -> bool {
// Do a type-safe casting. If the types are different,
// return false, otherwise test the values for equality.
other
.as_any()
.downcast_ref::<S>()
.map_or(false, |a| self == a)
}
}
fn main() {
assert_eq!(T::Ta, T::Ta);
assert_ne!(T::Ta, T::Tb);
assert!(some_fn(&T::Ta, &T::Ta));
assert!(!some_fn(&T::Ta, &T::Tb));
}
fn some_fn(an_a: &dyn A, another_a: &dyn A) -> bool {
// It works!
an_a.equals_a(another_a)
}
Here is the definition of the PartialEq trait:
pub trait PartialEq<Rhs = Self>
where
Rhs: ?Sized,
{
fn eq(&self, other: &Rhs) -> bool;
fn ne(&self, other: &Rhs) -> bool { ... }
}
Note the Self parameter type. This means that eq() and ne() methods accept a parameter of the same type as implementor. For example:
impl PartialEq for i32 {
fn eq(&self, other: &i32) -> bool { ... }
}
impl PartialEq for String {
fn eq(&self, other: &String) -> bool { ... }
}
Note how type of other changes to reflect the type PartialEq is implemented for.
This is the problem. In trait objects, the actual type is erased and unavailable at runtime. This means that it is impossible to obtain a reference to a concrete type from a trait object; in particular, you can't go from &A to &T in your example.
This means that it is impossible to call methods accepting or returning the Self type on trait objects. Indeed, these methods always require a concrete type, but if you have only a trait object, there is no concrete type, and there is no way such method could work in any sensible way.
In certain cases of trait objects, you wish to compare them based on some properties exposed via the trait. You can achieve this by implementing methods on the trait type itself:
trait A {
fn id(&self) -> i32;
}
impl PartialEq for dyn A + '_ {
fn eq(&self, other: &Self) -> bool {
self.id() == other.id()
}
}
impl Eq for dyn A + '_ {}
fn some_fn(an_a: &dyn A, another_a: &dyn A) -> bool {
an_a == another_a
}
This doesn't directly address the original case which wants to delegate back to the implementation of PartialEq of the underlying type, but you can combine the existing solution:
impl PartialEq for dyn A + '_ {
fn eq(&self, other: &Self) -> bool {
self.equals_a(other)
}
}
See also:
Why would I implement methods on a trait instead of as part of the trait?