Skip to main content

mant_core/mandoc/
error.rs

1//! Product-level failures while loading and parsing one native manual.
2
3use std::{
4    fmt,
5    path::{Path, PathBuf},
6};
7
8use libmandoc_rs::ParseError;
9
10/// Stable category for a native manual failure.
11#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12pub enum ManualErrorKind {
13    Read,
14    Decompression,
15    Limit,
16    UnsafePath,
17    Redirect,
18    Parse,
19}
20
21/// Failure produced by `ManT`'s source policy or by the underlying roff parser.
22#[derive(Clone, Debug, Eq, PartialEq)]
23pub enum ManualError {
24    Read { path: PathBuf, message: String },
25    Decompression { path: PathBuf, message: String },
26    Limit { path: PathBuf, message: String },
27    UnsafePath { path: PathBuf, message: String },
28    Redirect { path: PathBuf, message: String },
29    Parse(ParseError),
30}
31
32impl ManualError {
33    pub(super) fn read(path: &Path, message: impl Into<String>) -> Self {
34        Self::Read {
35            path: path.to_path_buf(),
36            message: message.into(),
37        }
38    }
39
40    pub(super) fn decompression(path: &Path, message: impl Into<String>) -> Self {
41        Self::Decompression {
42            path: path.to_path_buf(),
43            message: message.into(),
44        }
45    }
46
47    pub(super) fn limit(path: &Path, message: impl Into<String>) -> Self {
48        Self::Limit {
49            path: path.to_path_buf(),
50            message: message.into(),
51        }
52    }
53
54    pub(super) fn unsafe_path(path: &Path, message: impl Into<String>) -> Self {
55        Self::UnsafePath {
56            path: path.to_path_buf(),
57            message: message.into(),
58        }
59    }
60
61    pub(super) fn redirect(path: &Path, message: impl Into<String>) -> Self {
62        Self::Redirect {
63            path: path.to_path_buf(),
64            message: message.into(),
65        }
66    }
67
68    #[must_use]
69    pub const fn kind(&self) -> ManualErrorKind {
70        match self {
71            Self::Read { .. } => ManualErrorKind::Read,
72            Self::Decompression { .. } => ManualErrorKind::Decompression,
73            Self::Limit { .. } => ManualErrorKind::Limit,
74            Self::UnsafePath { .. } => ManualErrorKind::UnsafePath,
75            Self::Redirect { .. } => ManualErrorKind::Redirect,
76            Self::Parse(_) => ManualErrorKind::Parse,
77        }
78    }
79
80    #[must_use]
81    pub fn path(&self) -> &Path {
82        match self {
83            Self::Read { path, .. }
84            | Self::Decompression { path, .. }
85            | Self::Limit { path, .. }
86            | Self::UnsafePath { path, .. }
87            | Self::Redirect { path, .. } => path,
88            Self::Parse(error) => &error.path,
89        }
90    }
91
92    #[must_use]
93    pub fn message(&self) -> &str {
94        match self {
95            Self::Read { message, .. }
96            | Self::Decompression { message, .. }
97            | Self::Limit { message, .. }
98            | Self::UnsafePath { message, .. }
99            | Self::Redirect { message, .. } => message,
100            Self::Parse(error) => &error.message,
101        }
102    }
103}
104
105impl From<ParseError> for ManualError {
106    fn from(error: ParseError) -> Self {
107        Self::Parse(error)
108    }
109}
110
111impl fmt::Display for ManualError {
112    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
113        write!(formatter, "{}: {}", self.path().display(), self.message())
114    }
115}
116
117impl std::error::Error for ManualError {
118    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
119        match self {
120            Self::Parse(error) => Some(error),
121            Self::Read { .. }
122            | Self::Decompression { .. }
123            | Self::Limit { .. }
124            | Self::UnsafePath { .. }
125            | Self::Redirect { .. } => None,
126        }
127    }
128}