I have a fairly convoluted crate that gets used is several different contexts (compiled to WASM, into a Lua module, into a Python module, etc.). I'm trying to refactor it a bit to avoid panics that can cross those boundaries ... because duh! However the resulting error handling using Snafu is giving me conniptions. The actual code in context is here, but I've gotten as far as distilling it down to a similar set of scopes and trait implementations in MWE that can be run with rust-script from a single file:
#!/usr/bin/env rust-script
//! ```cargo
//! [dependencies]
//! snafu = "0.8"
//! strum_macros = "0.27"
//! ```
mod othertypes {
use snafu::prelude::*;
use std::convert::{Infallible, TryFrom};
use std::str::FromStr;
use strum_macros::Display;
#[derive(Snafu)]
pub enum ColorError {
#[snafu(display("failed to to parse '{input}'"))]
UnknownColor { input: String },
}
impl std::fmt::Debug for ColorError {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(self, fmt)
}
}
impl From<Infallible> for ColorError {
fn from(_: Infallible) -> Self {
unreachable!("Infallible errors should never occure")
}
}
pub type Result<T, E = ColorError> = std::result::Result<T, E>;
#[derive(Debug, Display, Clone, Copy)]
pub enum Color {
Red,
Green,
}
impl FromStr for Color {
type Err = ColorError;
fn from_str(s: &str) -> Result<Self> {
Ok(match s {
"red" => Color::Red,
"green" => Color::Green,
input => UnknownColorSnafu { input }.fail()?,
})
}
}
impl TryFrom<&str> for Color {
type Error = ColorError;
fn try_from(s: &str) -> Result<Self> {
Self::from_str(s)
}
}
}
use othertypes::{Color, Result};
fn takes_a_try(input: impl TryInto<Color>) -> Result<String> {
let color: Color = input.try_into()?;
Ok(color.to_string())
}
fn main() -> Result<()> {
let inputs = ["red", "green", "blue"];
for input in &inputs {
let color = takes_a_try(*input)?;
println!("Success: parsed '{input}' -> {color}");
}
Ok(())
}
The result I get throws these errors:
$ rust-script snafu-wazu.rs
error[E0277]: `?` couldn't convert the error to `ColorError`
--> /home/caleb/scratch/snafu-wazu.rs:63:40
|
62 | fn takes_a_try(input: impl TryInto<Color>) -> Result<String> {
| -------------- expected `ColorError` because of this
63 | let color: Color = input.try_into()?;
| ----------^ the trait `From<<impl TryInto<Color> as TryInto<Color>>::Error>` is not implemented for `ColorError`
| |
| this can't be annotated with `?` because it has type `Result<_, <impl TryInto<Color> as TryInto<Color>>::Error>`
|
note: `ColorError` needs to implement `From<<impl TryInto<Color> as TryInto<Color>>::Error>`
--> /home/caleb/scratch/snafu-wazu.rs:16:5
|
16 | pub enum ColorError {
| ^^^^^^^^^^^^^^^^^^^
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
For more information about this error, try `rustc --explain E0277`.
error: could not compile `snafu-wazu_b0c5d36811b0565c3d2fece2` (bin "snafu-wazu_b0c5d36811b0565c3d2fece2") due to 1 previous error
For the life of me I can't figure out why the ? operator is having trouble converting error types given that everything here is already the same error type. I was unable to replicate this error without the extra layers of complexity caused by having the error types and other things in a different module scope than the functions running them.
I did figure out ways to work around this, mostly by using .map_err() to flatten the error and re-create it, but its a mess and I'd like to clean it up and keep it simple. Why isn't this error type propagating?
I have a fairly convoluted crate that gets used is several different contexts (compiled to WASM, into a Lua module, into a Python module, etc.). I'm trying to refactor it a bit to avoid panics that can cross those boundaries ... because duh! However the resulting error handling using Snafu is giving me conniptions. The actual code in context is here, but I've gotten as far as distilling it down to a similar set of scopes and trait implementations in MWE that can be run with
rust-scriptfrom a single file:The result I get throws these errors:
For the life of me I can't figure out why the
?operator is having trouble converting error types given that everything here is already the same error type. I was unable to replicate this error without the extra layers of complexity caused by having the error types and other things in a different module scope than the functions running them.I did figure out ways to work around this, mostly by using
.map_err()to flatten the error and re-create it, but its a mess and I'd like to clean it up and keep it simple. Why isn't this error type propagating?