use crate::{
error::ErrorIterator,
paths::{LazyLocation, Location, RefTracker},
validator::{Validate, ValidationContext},
Json, Node, SerdeJson, ValidationError,
};
use serde_json::{Map, Value};
pub(crate) struct CustomKeyword<F: Json> {
inner: Box<dyn for<'i> Keyword<'i, F>>,
location: Location,
keyword: String,
}
impl<F: Json> CustomKeyword<F> {
pub(crate) fn new(
inner: Box<dyn for<'i> Keyword<'i, F>>,
location: Location,
keyword: String,
) -> Self {
Self {
inner,
location,
keyword,
}
}
}
impl<F: Json> Validate<F> for CustomKeyword<F> {
fn validate<'i>(
&self,
instance: &F::Node<'i>,
instance_path: &LazyLocation,
_tracker: Option<&RefTracker>,
_ctx: &mut ValidationContext,
) -> Result<(), ValidationError<'i>> {
self.inner.validate(instance.clone()).map_err(|err| {
let value = instance.to_value();
err.with_context(&value, instance_path, &self.location, &self.keyword)
.to_owned()
})
}
fn is_valid(&self, instance: &F::Node<'_>, _ctx: &mut ValidationContext) -> bool {
self.inner.is_valid(instance.clone())
}
fn iter_errors<'i>(
&self,
instance: &F::Node<'i>,
instance_path: &LazyLocation,
_tracker: Option<&RefTracker>,
_ctx: &mut ValidationContext,
) -> ErrorIterator<'i> {
let inner_errors: Vec<_> = self.inner.iter_errors(instance.clone()).collect();
if inner_errors.is_empty() {
return ErrorIterator::from_iterator(Vec::new().into_iter());
}
let value = instance.to_value();
let errors: Vec<_> = inner_errors
.into_iter()
.map(|err| {
err.with_context(&value, instance_path, &self.location, &self.keyword)
.to_owned()
})
.collect();
ErrorIterator::from_iterator(errors.into_iter())
}
}
pub trait Keyword<'i, F: Json = SerdeJson>: Send + Sync {
fn validate(&self, instance: F::Node<'i>) -> Result<(), ValidationError<'i>>;
fn is_valid(&self, instance: F::Node<'i>) -> bool;
fn iter_errors(
&self,
instance: F::Node<'i>,
) -> Box<dyn Iterator<Item = ValidationError<'i>> + 'i> {
Box::new(self.validate(instance).err().into_iter())
}
}
pub(crate) trait KeywordFactory<F: Json>: Send + Sync {
fn init<'a>(
&self,
parent: &'a Map<String, Value>,
schema: &'a Value,
schema_path: Location,
keyword: &str,
) -> Result<Box<dyn for<'i> Keyword<'i, F>>, ValidationError<'a>>;
}
impl<F: Json, Func> KeywordFactory<F> for Func
where
Func: for<'a> Fn(
&'a Map<String, Value>,
&'a Value,
Location,
) -> Result<Box<dyn for<'i> Keyword<'i, F>>, ValidationError<'a>>
+ Send
+ Sync,
{
fn init<'a>(
&self,
parent: &'a Map<String, Value>,
schema: &'a Value,
schema_path: Location,
keyword: &str,
) -> Result<Box<dyn for<'i> Keyword<'i, F>>, ValidationError<'a>> {
self(parent, schema, schema_path.clone())
.map_err(|err| err.with_schema_context(schema, schema_path, keyword))
}
}