use crate::error::{VldError, format_value_short};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct FieldResult {
pub name: String,
pub input: serde_json::Value,
pub result: Result<serde_json::Value, VldError>,
}
impl FieldResult {
pub fn is_ok(&self) -> bool {
self.result.is_ok()
}
pub fn is_err(&self) -> bool {
self.result.is_err()
}
}
impl std::fmt::Display for FieldResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.result {
Ok(v) => write!(f, "✔ {}: {}", self.name, format_value_short(v)),
Err(e) => {
let received = format_value_short(&self.input);
for (i, issue) in e.issues.iter().enumerate() {
if i > 0 {
writeln!(f)?;
}
write!(
f,
"✖ {}: {} (received: {})",
self.name, issue.message, received
)?;
}
Ok(())
}
}
}
}
#[derive(Debug)]
pub struct ParseResult<T> {
pub value: T,
field_results: Vec<FieldResult>,
}
impl<T> ParseResult<T> {
pub fn new(value: T, field_results: Vec<FieldResult>) -> Self {
Self {
value,
field_results,
}
}
pub fn fields(&self) -> &[FieldResult] {
&self.field_results
}
pub fn field(&self, name: &str) -> Option<&FieldResult> {
self.field_results.iter().find(|f| f.name == name)
}
pub fn valid_fields(&self) -> Vec<&FieldResult> {
self.field_results.iter().filter(|f| f.is_ok()).collect()
}
pub fn error_fields(&self) -> Vec<&FieldResult> {
self.field_results.iter().filter(|f| f.is_err()).collect()
}
pub fn is_valid(&self) -> bool {
self.field_results.iter().all(|f| f.is_ok())
}
pub fn has_errors(&self) -> bool {
self.field_results.iter().any(|f| f.is_err())
}
pub fn valid_count(&self) -> usize {
self.field_results.iter().filter(|f| f.is_ok()).count()
}
pub fn error_count(&self) -> usize {
self.field_results.iter().filter(|f| f.is_err()).count()
}
pub fn into_value(self) -> T {
self.value
}
pub fn into_parts(self) -> (T, Vec<FieldResult>) {
(self.value, self.field_results)
}
}
impl<T: serde::Serialize> ParseResult<T> {
pub fn save_to_file(&self, path: &std::path::Path) -> std::io::Result<()> {
let json = serde_json::to_string_pretty(&self.value)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
if let Some(parent) = path.parent() {
if !parent.as_os_str().is_empty() {
std::fs::create_dir_all(parent)?;
}
}
std::fs::write(path, json)
}
pub fn to_json_string(&self) -> Result<String, serde_json::Error> {
serde_json::to_string_pretty(&self.value)
}
pub fn to_json_value(&self) -> Result<serde_json::Value, serde_json::Error> {
serde_json::to_value(&self.value)
}
}
impl<T: std::fmt::Debug> std::fmt::Display for ParseResult<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(
f,
"ParseResult ({} valid, {} errors):",
self.valid_count(),
self.error_count()
)?;
for field in &self.field_results {
writeln!(f, " {}", field)?;
}
Ok(())
}
}