use alloc::boxed::Box;
use alloc::vec::Vec;
use crate::error::{ErrorIterator, ValidationError};
use crate::keywords::{BoxedValidator, ValidationContext};
use crate::paths::{LazyLocation, Location};
use foundation_errstacks::IntoErrorTrace;
use serde_json::Value;
pub enum SchemaNode {
AlwaysValid,
#[allow(dead_code)]
AlwaysInvalid { schema_path: Location },
Validators {
validators: Vec<BoxedValidator>,
#[allow(dead_code)]
schema_path: Location,
},
}
impl SchemaNode {
pub fn is_valid(&self, instance: &Value, ctx: &mut ValidationContext) -> bool {
match self {
Self::AlwaysValid => true,
Self::AlwaysInvalid { .. } => false,
Self::Validators { validators, .. } => {
validators.iter().all(|v| v.is_valid(instance, ctx))
}
}
}
pub fn validate(
&self,
instance: &Value,
path: &LazyLocation<'_>,
ctx: &mut ValidationContext,
) -> Result<(), ValidationError> {
match self {
Self::AlwaysValid => Ok(()),
Self::AlwaysInvalid { schema_path: _ } => {
Err(crate::error::ValidationErrorKind::FalseSchema.into_error_trace())
}
Self::Validators { validators, .. } => {
for v in validators {
v.validate(instance, path, ctx)?;
}
Ok(())
}
}
}
pub fn iter_errors(
&self,
instance: &Value,
path: &LazyLocation<'_>,
ctx: &mut ValidationContext,
) -> ErrorIterator {
let errors: ErrorIterator = match self {
Self::AlwaysValid => Box::new(core::iter::empty::<ValidationError>()),
Self::AlwaysInvalid { schema_path: _ } => Box::new(core::iter::once(
crate::error::ValidationErrorKind::FalseSchema.into_error_trace(),
)),
Self::Validators { validators, .. } => {
let mut errors: Vec<ValidationError> = Vec::new();
for v in validators {
for e in v.iter_errors(instance, path, ctx) {
errors.push(e);
}
}
Box::new(errors.into_iter())
}
};
errors
}
}