Skip to main content

yaml_schema/schemas/
not.rs

1use std::fmt::Display;
2
3use log::debug;
4use saphyr::AnnotatedMapping;
5use saphyr::MarkedYaml;
6use saphyr::YamlData;
7
8use crate::Context;
9use crate::Result;
10use crate::Validator;
11use crate::YamlSchema;
12
13/// The `not` keyword declares that an instance validates if it doesn't validate against the given subschema.
14#[derive(Debug, PartialEq)]
15pub struct NotSchema<'r> {
16    pub not: Box<YamlSchema<'r>>,
17}
18
19impl Display for NotSchema<'_> {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        write!(f, "not: {}", self.not)
22    }
23}
24
25impl<'r> TryFrom<&MarkedYaml<'r>> for NotSchema<'r> {
26    type Error = crate::Error;
27
28    fn try_from(value: &MarkedYaml<'r>) -> Result<Self> {
29        if let YamlData::Mapping(mapping) = &value.data {
30            NotSchema::try_from(mapping)
31        } else {
32            Err(expected_mapping!(value))
33        }
34    }
35}
36
37impl<'r> TryFrom<&AnnotatedMapping<'r, MarkedYaml<'r>>> for NotSchema<'r> {
38    type Error = crate::Error;
39
40    fn try_from(mapping: &AnnotatedMapping<'r, MarkedYaml<'r>>) -> crate::Result<Self> {
41        if let Some(value) = mapping.get(&MarkedYaml::value_from_str("not")) {
42            let schema: YamlSchema<'r> = value.try_into()?;
43            Ok(NotSchema {
44                not: Box::new(schema),
45            })
46        } else {
47            Err(generic_error!("No `not` key found!"))
48        }
49    }
50}
51
52impl Validator for NotSchema<'_> {
53    fn validate(&self, context: &Context, value: &saphyr::MarkedYaml) -> crate::Result<()> {
54        debug!(
55            "Not: Validating value: {:?} against schema: {}",
56            value, self.not
57        );
58
59        // Create a sub-context to validate against the inner schema
60        let sub_context = context.get_sub_context();
61        let sub_result = self.not.validate(&sub_context, value);
62
63        match sub_result {
64            Ok(()) | Err(crate::Error::FailFast) => {
65                // If the inner schema validates successfully, then this is an error for 'not'
66                if !sub_context.has_errors() {
67                    context.add_error(value, "Value matches schema in `not`");
68                    fail_fast!(context);
69                }
70            }
71            Err(e) => return Err(e),
72        }
73
74        // If we get here, then the inner schema failed validation, which means
75        // this 'not' validation succeeds
76        Ok(())
77    }
78}