#error #boilerplate #syntax #io-error

nightly error_def

Rust 语法扩展,用于生成错误处理样板代码

19 个版本

使用旧的 Rust 2015

0.3.16 2017 年 10 月 4 日
0.3.14 2017 年 6 月 11 日
0.3.12 2017 年 2 月 21 日
0.3.11 2016 年 8 月 27 日
0.3.2 2015 年 6 月 20 日

#1089 in Rust 模式


用于 3 个包(直接使用 2 个)

GPL-2.0 许可证

26KB
462

error_def:Rust 语法扩展,用于生成错误处理样板代码。

快速示例:以下代码

error_def! ExampleError {
    AVariant
        => "Unit-like variant",
    AVariantWithALongDescription
        => "Unit-like variant" ("A more verbose description"),
    AVariantWithArgs { flim: u32, flam: u32 }
        => "Variant with args" ("This is a format string. flim is {}. flam is {}.", flim, flam),
    AVariantWithACause { blah: bool, #[from] cause: io::Error }
        => "Variant with a cause" ("self.cause() would return Some({})", cause)
    AVariantWithJustACause { #[from] blah: io::Error }
        => "This variant can be made `From` an `io::Error`"
}

大致展开为

pub enum ExampleError {
    /// Unit-like variant
    AVariant,

    /// Unit-like variant
    AVariantWithALongDescription,

    /// Variant with args
    AVariantWithArgs {
        flim: u32,
        flam: u32,
    },

    /// Variant with a cause
    AVariantWithACause {
        blah: bool,
        cause: io::Error,
    },

    /// This variant can be made `From` an `io::Error`
    AVariantWithJustACause {
        blah: io::Error,
    },
}

impl fmt::Debug for ExampleError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result<(), fmt::Error> {
        match self {
            &ExampleError::AVariant
                => write!(f, "AVariant /* {} */", self),
            &ExampleError::AVariantWithALongDescription
                => write!(f, "AVariantWithALongDescription /* {} */", self),
            &ExampleError::AVariantWithArgs { ref flim, ref flam }
                => write!(f, "AVariantWithArgs {{ flim: {:?}, flam: {:?} }} /* {} */", flim, flim, self),
            &ExampleError::AVariantWithACause { ref blah, ref cause }
                => write!(f, "AVariantWithACause {{ blah: {:?}, cause: {:?} }} /* {} */", blah, cause, self),
            &ExampleError::AVariantWithJustACause { ref blah }
                => write!(f, "AVariantWithJustACause {{ blah: {:?} }} /* {} */", blah, self),
        }
    }
}

impl fmt::Display for ExampleError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result<(), fmt::Error> {
        match self {
            &ExampleError::AVariant                                => {
                try!(write!(f, "Unit-like variant."));
                Ok(())
            },
            &ExampleError::AVariantWithALongDescription            => {
                try!(write!(f, "Unit-like variant"));
                try!(write!(f, "A more verbose description"));
                Ok(())
            },
            &ExampleError::AVariantWithArgs { ref flim, ref flam } => {
                try!(write!(f, "Variant with args"));
                try!(write!(f, "This is a format string. flim is {}. flam is {}.", flim, flam));
                Ok(())
            },
            &ExampleError::AVariantWithACause { ref cause, .. }    => {
                try!(write!(f, "Variant with a cause"));
                try!(write!(f, "self.cause() would return Some({})", cause));
                Ok(())
            },
            &ExampleError::AVariantWithJustACause { .. }           => {
                try!(write!(f, "This variant can be made `From` an `io::Error`"));
                Ok(())
            },
        }
    }
}

impl Error for ExampleError {
    fn description(&self) -> &str {
        match self {
            &ExampleError::AVariant                            => "Unit-like variant",
            &ExampleError::AVariantWithALongDescription { .. } => "Unit-like variant",
            &ExampleError::AVariantWithArgs { .. }             => "Variant with args",
            &ExampleError::AVariantWithACause { .. }           => "Variant with a cause",
            &ExampleError::AVariantWithJustACause { .. }       => "This variant can be made `From` an `io::Error`",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &ExampleError::AVariant                                => None,
            &ExampleError::AVariantWithALongDescription { .. }     => None,
            &ExampleError::AVariantWithArgs { .. }                 => None,
            &ExampleError::AVariantWithACause { ref cause, .. }    => Some(cause as &Error),
            &ExampleError::AVariantWithJustACause { ref blah, .. } => Some(blah as &Error),
        }
    }
}

impl From<io::Error> for ExampleError {
    fn from(e: io::Error) -> ExampleError {
        ExampleError::AVariantWithJustACause { blah: e }
    }
}

说明: error_def 定义了一个 enum,其中每个变体都与变体的描述配对。

error_def! SomeError {
    AVariant       => "A description",
    AnotherVariant => "Another description",
}

此描述作为文档注释添加到变体,并通过调用 Error::description 返回。

assert!(SomeError::AVariant.description() == "A description")

变体可以是结构体-like。

error_def! SomeError {
    AVariant { an_i32: i32 }  => "I'm a variant",
}

变体还可以有一个可选的详细描述,它由一个格式字符串和一系列参数组成。详细描述放在简短描述之后,用括号括起来。如果变体是结构体,格式字符串的参数可以引用它的成员。

error_def! SomeError {
    Io { cause: io::Error }
        => "I/O error occured!" ("Error: {}", cause),
}

error_def! 使用简短和详细描述提供 fmt::Displayfmt::Debug 的实现。在上面的例子中,SomeError::Io 将格式化为

I/O error occurred. Error: <在此处插入 fmt::Display(cause) here>

对于 fmt::Display

SomeError::Io { cause: <在此处插入 fmt::Debug(cause) here> } /* I/O error occurred. Error: <在此处插入 fmt::Display(cause) here> */

对于 fmt::Debug

结构体变体的成员可以标记为可选的伪属性 #[from]

error_def! SomeError {
    Io {
        foo: u32,
        #[from] cause: io::Error,
    } => "Io error"
}

这会导致在调用 Error::cause 时返回该成员。在上面的例子中,对 SomeError::Io 调用 Error::cause 将返回一个 Option<&Error>,其中 &Error 指向一个 io::Error

如果一个结构体变体只有一个成员并且被标记为 #[from],那么将实现 From 以将该成员的类型转换为错误类型。

例如,如果我们定义一个错误如下

error_def! SomeError {
    Io { #[from] cause: io::Error } => "I/O error",
}

那么 error_def! 将定义一个 impl

impl std::convert::From<io::Error> for SomeError {
    fn from(e: io::Error) -> SomeError {
        SomeError::Io {
            cause: e,
        }
    }
}

无运行时依赖