use yog_data::Schema;
#[derive(Debug, Clone, Default, PartialEq, Schema)]
pub struct ServiceError {
pub message: String,
#[data(default)]
pub problems: Vec<Problem>,
pub file: Option<String>,
}
#[derive(Debug, Clone, Default, PartialEq, Schema)]
pub struct Problem {
pub code: String,
pub message: String,
#[data(default)]
pub path: String,
pub line: Option<u32>,
pub col: Option<u32>,
}
impl ServiceError {
pub fn of(code: &str, message: impl Into<String>) -> Self {
let message = message.into();
ServiceError {
problems: vec![Problem {
code: code.to_string(),
message: message.clone(),
..Problem::default()
}],
message,
file: None,
}
}
pub fn at(code: &str, message: impl Into<String>, line: u32, col: Option<u32>) -> Self {
let mut e = Self::of(code, message);
e.problems[0].line = Some(line);
e.problems[0].col = col;
e
}
pub fn syntax(e: &yog_data::SyntaxError) -> Self {
Self::at(
yog_ids::problem_code::SYNTAX,
e.message.clone(),
e.at.line,
Some(e.at.col),
)
}
pub fn not_found(message: impl Into<String>) -> Self {
Self::of(yog_ids::problem_code::NOT_FOUND, message)
}
pub fn param(name: &str, problems: Vec<yog_data::schema::Problem>) -> Self {
let problems: Vec<Problem> = problems
.into_iter()
.map(|p| Problem {
code: p.code.to_string(),
path: if p.path.is_root() {
name.to_string()
} else {
format!("{name}.{}", p.path)
},
message: p.message,
..Problem::default()
})
.collect();
let message = match problems.as_slice() {
[one] => format!("`{}`: {}", one.path, one.message),
_ => format!("`{name}` has {} problems", problems.len()),
};
ServiceError {
message,
problems,
file: None,
}
}
}
impl From<String> for ServiceError {
fn from(message: String) -> Self {
Self::of(yog_ids::problem_code::FAILED, message)
}
}
impl From<&str> for ServiceError {
fn from(message: &str) -> Self {
message.to_string().into()
}
}