#error #macro #traits #context #structs #msg #type

hb_error

用于创建和处理错误的实用宏和特质

3个版本

0.1.2 2023年3月25日
0.1.1 2022年9月24日
0.1.0 2022年8月29日

Rust模式中排名第1164

每月下载量22

MIT许可协议

18KB
84

hb_error

此crate包含用于创建错误类型和处理错误的宏和特质。

此crate的主要功能是hberror宏和上下文宏。

hberror宏

此宏用于生成错误类型的所有样板代码,以便它们具有相同的格式。

概述

此宏应用于如下结构的struct。

#[hberror]
struct ExampleError {
}

此宏将修改struct以添加msg和inner_msgs字段,以及为new、ErrorContext、Display和Debug执行impl。这将生成以下代码


pub struct ExampleError {
    msg: String,
    inner_msgs: Vec<String>,
}

impl ExampleError {
    pub fn new() -> ExampleError {
        ExampleError {
            msg: default::Default(),
            inner_msgs: default::Default(),
        }
    }
}

impl ErrorContext for ExampleError {
    fn make_inner(mut self) -> ExampleError {
        self.inner_msgs.push(self.msg);
        self.msg = String::new();
        self
    }

    fn msg<T: Into<String>>(mut self, msg: T) -> ExampleError {
        self.msg = msg.into();
        self
    }
}

impl std::fmt::Display for ExampleError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
        write!(f,"{}{}", self.msg, self.inner_msgs.join("\n...because..."))
    }
}

impl std::fmt::Debug for ExampleError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
        write!(f,"{}{}", self.msg, self.inner_msgs.join("\n...because..."))
    }
}

自定义字段和消息

此宏还具有处理自定义字段和自定义消息的能力。使用这些自定义字段上的Default属性将告诉宏使用new函数中提供的值而不是default::Default()。

#[hberror("{self.custom_field}:{self.msg}{self.inner_msgs.join(\"\n...due to...\")}")]
struct ExampleError {
    #[Default(10)]
    custom_field: i32,
}

这变成

pub struct ExampleError {
    msg: String,
    inner_msgs: Vec<String>,
    custom_field: i32
}

impl ExampleError {
    pub fn new() -> ExampleError {
        ExampleError {
            msg: default::Default(),
            inner_msgs: default::Default(),
            custom_field: 10
        }
    }
}

impl ErrorContext for ExampleError {
    fn make_inner(mut self) -> ExampleError {
        self.inner_msgs.push(self.msg);
        self.msg = String::new();
        self
    }

    fn msg<T: Into<String>>(mut self, msg: T) -> ExampleError {
        self.msg = msg.into();
        self
    }
}

impl std::fmt::Display for ExampleError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
        write!(f,"{}:{}{}", self.custom_field, self.msg, self.inner_msgs.join("\n...due to..."))
    }
}

impl std::fmt::Debug for ExampleError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
        write!(f,"{}:{}{}", self.custom_field, self.msg, self.inner_msgs.join("\n...due to..."))
    }
}

从其他错误轻松转换

您还可以定义要转换的错误并将它们存储为source变量,这些变量将在消息后打印出来。Source属性告诉宏哪些字段作为源进行处理。将使用具有Source结尾的结构身份创建一个枚举(例如ExampleErrorSource)。此枚举将为具有源属性的字段以及一个None值创建变体。源变体使用字段身份作为枚举变体身份创建,并包含提供的错误类型。

这意味着可以在不进行任何额外工作的前提下在错误类型上使用context或convert_error宏。

#[hberror]
struct ExampleError {
    #[Source]
    IOError: std::io::Error,
}

这变成

use std::default;
pub struct ExampleError {
    msg: String,
    inner_msgs: Vec<String>,
    source: ExampleErrorSource,
}

impl ExampleError {
    pub fn new() -> ExampleError {
        ExampleError {
            msg: default::Default(),
            inner_msgs: default::Default(),
            source: default::Default(),
        }
    }

    pub fn source(mut self, s: ExampleErrorSource) -> ExampleError {
        self.source = s;
        self
    }
}

impl ErrorContext for ExampleError {
    fn make_inner(mut self) -> ExampleError {
        self.inner_msgs.push(self.msg);
        self.msg = String::new();
        self
    }

    fn msg<T: Into<String>>(mut self, msg: T) -> ExampleError {
        self.msg = msg.into();
        self
    }
}

impl std::fmt::Display for ExampleError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
        write!(f,"{}{}{}", self.msg, self.inner_msgs.join("\n...due to..."), self.source)
    }
}

impl std::fmt::Debug for ExampleError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
        write!(f,"{}{}{}", self.msg, self.inner_msgs.join("\n...due to..."), self.source)
    }
}

pub enum ExampleErrorSource {
    None,
    IOError(std::io::Error),
}

impl std::default::Default for ExampleErrorSource {
    fn default() -> Self { ExampleErrorSource::None }
}

impl std::fmt::Display for ExampleErrorSource {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
        match self {
            ExampleErrorSource::None => Ok(()),
            ExampleErrorSource::IOError(e) => write!("\n...Source Error...{}", e)
        }
    }
}

impl std::fmt::Debug for ExampleErrorSource {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
        match self {
            ExampleErrorSource::None => Ok(()),
            ExampleErrorSource::IOError(e) => write!("\n...Source Error...{}", e)
        }
    }
}

convert宏

将函数返回的错误转换为函数正确的类型,并添加提供的上下文消息。这需要从源错误实现From到返回类型错误。此宏将以下函数...

#[context("context message")]
fn basic_exampleerror() -> Result<(), ExampleError> {
    if io_error()? {
        return example_error().map_err(|e| e.msg("msgs are great"));
    }
    example_error()
}

转换为...

fn basic_exampleerror() -> Result<(), ExampleError> {
    #[allow(unreachable_code)]
    let ret: Result<(), ExampleError> = {
           #[warn(unreachable_code)]
        if hb_error::ConvertInto::Result<(), ExampleError>::convert(io_error()).map_err(|er| er.make_inner().msg("context message")? {
            return hb_error::ConvertInto::Result<(), ExampleError>::convert(example_error().map_err(|e| e.msg("msgs are great"))).map_err(|er| er.make_inner().msg("context message");
        }
        example_error()
    };
    #[allow(unreachable_code)]
    ret.map_err(|er| e.make_inner().msg("context message")
}

依赖关系

~1.5MB
~35K SLoC