use super::*;
use crate::error::{Error, Result};
use serde::{Deserialize, Serialize};
use std::default::Default;
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct EnumValidator(pub BTreeMap<String, Option<Validator>>);
impl EnumValidator {
pub fn new() -> Self {
Self::default()
}
pub fn insert(mut self, variant: impl Into<String>, validator: Option<Validator>) -> Self {
self.0.insert(variant.into(), validator);
self
}
pub fn build(self) -> Validator {
Validator::Enum(self)
}
pub fn iter(&self) -> std::collections::btree_map::Iter<String, Option<Validator>> {
self.0.iter()
}
pub fn values(&self) -> std::collections::btree_map::Values<String, Option<Validator>> {
self.0.values()
}
pub(crate) fn validate<'de, 'c>(
&'c self,
types: &'c BTreeMap<String, Validator>,
mut parser: Parser<'de>,
checklist: Option<Checklist<'c>>,
) -> Result<(Parser<'de>, Option<Checklist<'c>>)> {
let elem = parser
.next()
.ok_or_else(|| Error::FailValidate("expected a enum".to_string()))??;
let (key, has_value) = match elem {
Element::Str(v) => (v, false),
Element::Map(1) => {
let key = parser
.next()
.ok_or_else(|| Error::FailValidate("expected a string".to_string()))??;
if let Element::Str(key) = key {
(key, true)
} else {
return Err(Error::FailValidate("expected a string".to_string()));
}
}
_ => return Err(Error::FailValidate("expected an enum".to_string())),
};
let validator = self
.0
.get(key)
.ok_or_else(|| Error::FailValidate(format!("{} is not in enum list", key)))?;
match (validator, has_value) {
(None, false) => Ok((parser, checklist)),
(None, true) => Err(Error::FailValidate(format!(
"enum {} shouldn't have any associated value",
key
))),
(Some(_), false) => Err(Error::FailValidate(format!(
"enum {} should have an associated value",
key
))),
(Some(validator), true) => validator.validate(types, parser, checklist),
}
}
pub(crate) fn query_check(
&self,
types: &BTreeMap<String, Validator>,
other: &Validator,
) -> bool {
match other {
Validator::Enum(other) => {
other
.0
.iter()
.all(|(other_k, other_v)| match (self.0.get(other_k), other_v) {
(Some(Some(validator)), Some(other_v)) => {
validator.query_check(types, other_v)
}
(Some(None), None) => true,
_ => false,
})
}
Validator::Any => true,
_ => false,
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn example_schema() {
use crate::schema::{Schema, SchemaBuilder};
let entry_validator = EnumValidator::new()
.insert("Empty", None)
.insert("Integer", Some(IntValidator::new().build()))
.insert("String", Some(StrValidator::new().build()))
.build();
let schema_doc = SchemaBuilder::new(Validator::Null)
.entry_add("item", entry_validator, None)
.build()
.unwrap();
Schema::from_doc(&schema_doc).unwrap();
}
}