use crate::validator::context::ValidationContext; use crate::validator::error::ValidationError; use crate::validator::result::ValidationResult; impl<'a> ValidationContext<'a> { pub(crate) fn validate_combinators( &self, result: &mut ValidationResult, ) -> Result { if let Some(ref all_of) = self.schema.all_of { for sub in all_of { let derived = self.derive_for_schema(sub, true); let res = derived.validate()?; result.merge(res); } } if let Some(ref one_of) = self.schema.one_of { let mut passed_candidates: Vec<(Option, usize, ValidationResult)> = Vec::new(); for sub in one_of { let derived = self.derive_for_schema(sub, true); let sub_res = derived.validate()?; if sub_res.is_valid() { let child_id = sub.id.clone(); let depth = child_id .as_ref() .and_then(|id| self.db.depths.get(id).copied()) .unwrap_or(0); passed_candidates.push((child_id, depth, sub_res)); } } if passed_candidates.len() == 1 { result.merge(passed_candidates.pop().unwrap().2); } else if passed_candidates.is_empty() { result.errors.push(ValidationError { code: "NO_ONEOF_MATCH".to_string(), message: "Matches none of oneOf schemas".to_string(), path: self.path.to_string(), }); } else { // Apply depth heuristic tie-breaker let mut best_depth: Option = None; let mut ambiguous = false; let mut best_res = None; for (_, depth, res) in passed_candidates.into_iter() { if let Some(current_best) = best_depth { if depth > current_best { best_depth = Some(depth); best_res = Some(res); ambiguous = false; } else if depth == current_best { ambiguous = true; } } else { best_depth = Some(depth); best_res = Some(res); } } if !ambiguous { if let Some(res) = best_res { result.merge(res); return Ok(true); } } result.errors.push(ValidationError { code: "AMBIGUOUS_ONEOF_MATCH".to_string(), message: "Matches multiple oneOf schemas without a clear depth winner".to_string(), path: self.path.to_string(), }); } } if let Some(ref not_schema) = self.schema.not { let derived = self.derive_for_schema(not_schema, true); let sub_res = derived.validate()?; if sub_res.is_valid() { result.errors.push(ValidationError { code: "NOT_VIOLATED".to_string(), message: "Matched 'not' schema".to_string(), path: self.path.to_string(), }); } } Ok(true) } }