use crate::error::RedispatchXmlError;
use crate::parse::Document;
pub mod semantic;
pub mod structural;
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
pub enum ValidationError {
#[error("document identifier must be 1–35 characters, got {0}")]
DocumentIdLength(usize),
#[error("document version must be 1–999, got {0}")]
DocumentVersionRange(u32),
#[error("market participant ID must be exactly 13 decimal digits, got {0:?}")]
MarketParticipantIdFormat(String),
#[error("timestamp must be UTC, got offset {0}")]
TimestampNotUtc(String),
#[error("time interval end must be after start")]
TimeIntervalOrder,
#[error("{0}")]
Structural(String),
#[error("{0}")]
Semantic(String),
}
#[derive(Debug, Clone, PartialEq)]
pub struct ValidationWarning(pub String);
#[derive(Debug, Default, Clone)]
pub struct ValidationResult {
pub warnings: Vec<ValidationWarning>,
pub errors: Vec<ValidationError>,
}
impl ValidationResult {
pub fn is_valid(&self) -> bool {
self.errors.is_empty()
}
pub fn into_result(mut self) -> Result<Vec<ValidationWarning>, ValidationError> {
if self.errors.is_empty() {
Ok(self.warnings)
} else {
Err(self.errors.remove(0))
}
}
pub fn into_errors(self) -> Result<Vec<ValidationWarning>, Vec<ValidationError>> {
if self.errors.is_empty() {
Ok(self.warnings)
} else {
Err(self.errors)
}
}
}
impl std::fmt::Display for ValidationResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.errors.is_empty() && self.warnings.is_empty() {
return write!(f, "ok");
}
for e in &self.errors {
writeln!(f, "error: {e}")?;
}
for w in &self.warnings {
writeln!(f, "warning: {}", w.0)?;
}
Ok(())
}
}
#[allow(unused_variables)]
pub fn validate(doc: &Document) -> ValidationResult {
let mut result = ValidationResult::default();
structural::validate(doc, &mut result);
semantic::validate(doc, &mut result);
result
}
pub fn validate_structural<T>(doc: &T) -> Result<(), RedispatchXmlError>
where
T: structural::ValidateStructural,
{
let mut result = ValidationResult::default();
doc.validate_structural(&mut result);
result
.into_result()
.map(|_| ())
.map_err(|e| RedispatchXmlError::StructuralError(e.to_string()))
}