micropb_gen/
error.rs

1use std::{fmt::Display, io};
2
3/// Error encountered while processing proto files and generating Rust code
4#[derive(Debug)]
5pub enum Error {
6    /// IO error
7    Io(io::Error),
8    /// Protoc invocation error
9    Protoc(String),
10    /// Protobuf field error
11    Field {
12        /// Protobuf package
13        package: String,
14        /// Protobuf message
15        message: String,
16        /// Protobuf field
17        field: String,
18        /// Error text
19        text: String,
20    },
21    /// Protobuf message error
22    Message {
23        /// Protobuf package
24        package: String,
25        /// Protobuf message
26        message: String,
27        /// Error text
28        text: String,
29    },
30    /// Protobuf package error
31    Package {
32        /// Protobuf package
33        package: String,
34        /// Error text
35        text: String,
36    },
37    #[cfg(feature = "config-file")]
38    /// Config file parsing error
39    ConfigFile {
40        /// File name
41        file_name: std::path::PathBuf,
42        /// TOML parsing error
43        err: toml::de::Error,
44    },
45}
46
47/// Result alias
48pub type Result<T> = std::result::Result<T, Error>;
49
50impl Display for Error {
51    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52        match self {
53            Error::Io(error) => error.fmt(f),
54            Error::Protoc(error) => write!(f, "protoc failed: {error}"),
55            Error::Field {
56                package,
57                message,
58                field,
59                text,
60            } => {
61                let dot = if package.is_empty() { "" } else { "." };
62                write!(f, "({dot}{package}.{message}.{field}) {text}")
63            }
64            Error::Message {
65                package,
66                message,
67                text,
68            } => {
69                let dot = if package.is_empty() { "" } else { "." };
70                write!(f, "({dot}{package}.{message}) {text}")
71            }
72            Error::Package { package, text } => {
73                let dot = if package.is_empty() { "" } else { "." };
74                write!(f, "({dot}{package}) {text}")
75            }
76            #[cfg(feature = "config-file")]
77            Error::ConfigFile { file_name, err } => {
78                write!(f, "Failed to parse {}: {err}", file_name.display())
79            }
80        }
81    }
82}
83
84impl std::error::Error for Error {
85    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
86        match self {
87            Error::Io(error) => Some(error),
88            #[cfg(feature = "config-file")]
89            Error::ConfigFile { err, .. } => Some(err),
90            Error::Field { .. }
91            | Error::Message { .. }
92            | Error::Package { .. }
93            | Error::Protoc(_) => None,
94        }
95    }
96}
97
98impl From<io::Error> for Error {
99    fn from(err: io::Error) -> Self {
100        Self::Io(err)
101    }
102}
103
104pub(crate) fn field_error(
105    pkg: &str,
106    msg_name: &str,
107    field_name: &str,
108    err_text: impl Display,
109) -> Error {
110    Error::Field {
111        package: pkg.to_owned(),
112        message: msg_name.to_owned(),
113        field: field_name.to_owned(),
114        text: err_text.to_string(),
115    }
116}
117
118pub(crate) fn msg_error(pkg: &str, msg_name: &str, err_text: impl Display) -> Error {
119    Error::Message {
120        package: pkg.to_owned(),
121        message: msg_name.to_owned(),
122        text: err_text.to_string(),
123    }
124}
125
126pub(crate) fn pkg_error(pkg: &str, err_text: impl Display) -> Error {
127    Error::Package {
128        package: pkg.to_owned(),
129        text: err_text.to_string(),
130    }
131}