1use std::{fmt::Display, path::PathBuf};
7
8use edit_xml::{Document, EditXMLError, Element};
9use thiserror::Error;
10use utils::MissingElementError;
11
12use crate::{
13 pom::{
14 DependencyBuilderError, DeveloperBuilderError, DistributionRepositoryBuilderError,
15 ParentBuilderError, PluginBuilderError, RepositoryBuilderError, ScmBuilderError,
16 SubRepositoryRulesBuilderError,
17 },
18 settings::{MirrorBuilderError, ServerBuilderError},
19};
20pub mod utils;
21
22#[derive(Debug, Error)]
23pub enum XMLEditorError {
24 #[error(transparent)]
25 MissingElement(#[from] MissingElementError),
26 #[error("Unexpected Element Type. Expected {expected}, found {found}")]
27 UnexpectedElementType {
28 expected: &'static str,
29 found: String,
30 },
31 #[error(transparent)]
32 InvalidValue(#[from] InvalidValueError),
33 #[error(transparent)]
34 EditXMLError(#[from] EditXMLError),
35 #[error("Error During Validation of type {pom_type} {error}")]
36 ValidationError {
37 pom_type: &'static str,
38 error: String,
39 },
40}
41macro_rules! builder_err {
42 ($error_type:ident, $pom_type:literal) => {
43 impl From<$error_type> for XMLEditorError {
44 fn from(value: $error_type) -> Self {
45 match value {
46 $error_type::UninitializedField(missing_field) => {
47 XMLEditorError::MissingElement(MissingElementError(missing_field))
48 }
49 $error_type::ValidationError(other) => XMLEditorError::ValidationError {
50 pom_type: $pom_type,
51 error: other,
52 },
53 }
54 }
55 }
56 };
57 [
58 $(
59 ($error_type:ident, $pom_type:literal)
60 ),*
61 ] => {
62 $(
63 builder_err!($error_type, $pom_type);
64 )*
65 };
66
67}
68
69builder_err![
70 (DependencyBuilderError, "Dependency"),
71 (PluginBuilderError, "Plugin"),
72 (ParentBuilderError, "Parent"),
73 (ServerBuilderError, "Server"),
74 (MirrorBuilderError, "Mirror"),
75 (SubRepositoryRulesBuilderError, "SubRepositoryRules"),
76 (RepositoryBuilderError, "Repository"),
77 (ScmBuilderError, "Scm"),
78 (DeveloperBuilderError, "Developer"),
79 (DistributionRepositoryBuilderError, "DistributionRepository")
80];
81
82pub trait HasElementName {
84 fn element_name() -> &'static str;
86}
87
88pub trait ElementConverter: Sized {
90 fn from_element(element: Element, document: &Document) -> Result<Self, XMLEditorError>;
92 fn into_element(self, document: &mut Document) -> Result<Element, XMLEditorError>
97 where
98 Self: HasElementName,
99 {
100 let element = Element::new(document, Self::element_name());
101 let children = self.into_children(document)?;
102 for child in children {
103 element.push_child(document, child)?;
104 }
105 Ok(element)
106 }
107 fn into_children(self, document: &mut Document) -> Result<Vec<Element>, XMLEditorError>;
109}
110pub trait ComparableElement {
111 fn is_same_item(&self, other: &Self) -> bool;
114}
115pub trait UpdatableElement: ElementConverter {
117 fn update_element(
119 &self,
120 element: Element,
121 document: &mut Document,
122 ) -> Result<(), XMLEditorError>;
123 fn replace_all_elements(
125 self,
126 element: Element,
127 document: &mut Document,
128 ) -> Result<(), XMLEditorError> {
129 element.clear_children(document);
130 let children = self.into_children(document)?;
131 for child in children {
132 element.push_child(document, child)?;
133 }
134 Ok(())
135 }
136}
137pub trait ChildOfListElement: ElementConverter {
139 fn parent_element_name() -> &'static str;
140}
141#[derive(Debug, Error)]
142pub enum InvalidValueError {
143 InvalidValue {
144 expected: &'static str,
145 found: String,
146 },
147 InvalidFormattedValue {
148 error: String,
149 },
150}
151impl Display for InvalidValueError {
152 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153 match self {
154 InvalidValueError::InvalidValue { expected, found } => {
155 write!(f, "Expected {} found {}", expected, found)
156 }
157 InvalidValueError::InvalidFormattedValue { error } => {
158 write!(f, "Invalid Value: {}", error)
159 }
160 }
161 }
162}
163
164pub trait PomValue: Sized {
165 fn from_string_for_editor(value: String) -> Result<Self, InvalidValueError> {
166 Self::from_str_for_editor(&value)
167 }
168
169 fn from_str_for_editor(value: &str) -> Result<Self, InvalidValueError>;
170
171 fn to_string_for_editor(&self) -> String;
172
173 fn from_element(element: Element, document: &Document) -> Result<Self, XMLEditorError>
174 where
175 Self: Sized,
176 {
177 let value = element.text_content(document);
178 Self::from_str_for_editor(&value).map_err(|e| e.into())
179 }
180}
181
182impl PomValue for bool {
183 fn from_str_for_editor(value: &str) -> Result<Self, InvalidValueError> {
184 match value {
185 "true" => Ok(true),
186 "false" => Ok(false),
187 _ => Err(InvalidValueError::InvalidValue {
188 expected: "true or false",
189 found: value.to_string(),
190 }),
191 }
192 }
193
194 fn to_string_for_editor(&self) -> String {
195 self.to_string()
196 }
197}
198
199impl PomValue for String {
200 fn from_str_for_editor(value: &str) -> Result<Self, InvalidValueError> {
201 Ok(value.to_string())
202 }
203 fn from_string_for_editor(value: String) -> Result<Self, InvalidValueError> {
204 Ok(value)
205 }
206 fn to_string_for_editor(&self) -> String {
207 self.clone()
208 }
209}
210macro_rules! pom_value_num {
211 (
212 $(
213 $type:ty
214 ),*
215 ) => {
216 $(
217 impl PomValue for $type {
218 fn from_str_for_editor(value: &str) -> Result<Self, InvalidValueError> {
219 value.parse().map_err(|_| InvalidValueError::InvalidValue {
220 expected: "A number",
221 found: value.to_string(),
222 })
223 }
224
225 fn to_string_for_editor(&self) -> String {
226 self.to_string()
227 }
228 }
229 )*
230 };
231}
232pom_value_num!(usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64);
233
234impl PomValue for PathBuf {
235 fn from_str_for_editor(value: &str) -> Result<Self, InvalidValueError> {
236 Ok(PathBuf::from(value))
237 }
238
239 fn to_string_for_editor(&self) -> String {
240 self.to_string_lossy().to_string()
242 }
243}