1use std::error::Error;
7use std::fmt::{self, Display};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum WriteError {
12 InvalidHeadingLevel(u8),
14 NewlineInInlineElement(String),
16 FmtError(String),
18 UnsupportedNodeType,
20 InvalidStructure(String),
22 Custom {
24 message: String,
26 code: Option<String>,
28 },
29}
30
31impl Display for WriteError {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 match self {
34 WriteError::InvalidHeadingLevel(level) => write!(
35 f,
36 "Invalid heading level: {}. Level must be between 1 and 6.",
37 level
38 ),
39 WriteError::NewlineInInlineElement(context) => write!(
40 f,
41 "Newline character found within an inline element ({}) which is not allowed in strict mode or this context.",
42 context
43 ),
44 WriteError::FmtError(msg) => write!(f, "Formatting error: {}", msg),
45 WriteError::UnsupportedNodeType => {
46 write!(f, "Unsupported node type encountered during writing.")
47 },
48 WriteError::InvalidStructure(msg) => {
49 write!(f, "Invalid structure: {}", msg)
50 },
51 WriteError::Custom { message, code } => {
52 if let Some(code) = code {
53 write!(f, "Custom error [{}]: {}", code, message)
54 } else {
55 write!(f, "Custom error: {}", message)
56 }
57 }
58 }
59 }
60}
61
62impl Error for WriteError {}
63
64impl From<fmt::Error> for WriteError {
66 fn from(err: fmt::Error) -> Self {
67 WriteError::FmtError(err.to_string())
68 }
69}
70
71pub type WriteResult<T> = Result<T, WriteError>;
73
74impl WriteError {
76 pub fn custom<S: Into<String>>(message: S) -> Self {
78 WriteError::Custom {
79 message: message.into(),
80 code: None,
81 }
82 }
83
84 pub fn custom_with_code<S1: Into<String>, S2: Into<String>>(message: S1, code: S2) -> Self {
86 WriteError::Custom {
87 message: message.into(),
88 code: Some(code.into()),
89 }
90 }
91}
92
93pub trait CustomErrorFactory {
98 fn create_error(&self) -> WriteError;
100}
101
102pub struct StructureError {
104 format: String,
106 args: Vec<String>,
108}
109
110impl StructureError {
111 pub fn new<S: Into<String>>(format: S) -> Self {
113 Self {
114 format: format.into(),
115 args: Vec::new(),
116 }
117 }
118
119 pub fn arg<S: Into<String>>(mut self, arg: S) -> Self {
121 self.args.push(arg.into());
122 self
123 }
124}
125
126impl CustomErrorFactory for StructureError {
127 fn create_error(&self) -> WriteError {
128 let message = match self.args.len() {
129 0 => self.format.clone(),
130 1 => self.format.replace("{}", &self.args[0]),
131 _ => {
132 let mut result = self.format.clone();
133 for arg in &self.args {
134 if let Some(pos) = result.find("{}") {
135 result.replace_range(pos..pos + 2, arg);
136 }
137 }
138 result
139 }
140 };
141
142 WriteError::InvalidStructure(message)
143 }
144}
145
146pub struct CodedError {
148 message: String,
150 code: String,
152}
153
154impl CodedError {
155 pub fn new<S1: Into<String>, S2: Into<String>>(message: S1, code: S2) -> Self {
157 Self {
158 message: message.into(),
159 code: code.into(),
160 }
161 }
162}
163
164impl CustomErrorFactory for CodedError {
165 fn create_error(&self) -> WriteError {
166 WriteError::custom_with_code(&self.message, &self.code)
167 }
168}
169
170pub trait WriteResultExt<T> {
172 fn custom_error<F: CustomErrorFactory>(factory: F) -> Result<T, WriteError>;
174}
175
176impl<T> WriteResultExt<T> for Result<T, WriteError> {
177 fn custom_error<F: CustomErrorFactory>(factory: F) -> Result<T, WriteError> {
178 Err(factory.create_error())
179 }
180}