use bitflags::bitflags;
use crate::ids::{AttributeKey, ElementKey, NameId, NotationKey, TypeKey};
use crate::types::value::XmlValue;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum SchemaValidity {
#[default]
NotKnown,
Valid,
Invalid,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ValidationAttempted {
#[default]
None,
Partial,
Full,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ContentType {
#[default]
Empty,
TextOnly,
ElementOnly,
Mixed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TypeSource {
Declaration,
XsiType,
#[cfg(feature = "xsd11")]
TypeAlternative,
}
#[cfg(feature = "xsd11")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AssertionOutcome {
Passed,
Failed,
NotEvaluated,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct NodeIdentity(pub u64);
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ValidationFlags: u32 {
const REPORT_WARNINGS = 0x0001;
const PROCESS_IDENTITY_CONSTRAINTS = 0x0002;
const ALLOW_XML_ATTRIBUTES = 0x0004;
const STRICT_MODE = 0x0008;
#[cfg(feature = "xsd11")]
const PROCESS_ASSERTIONS = 0x0010;
}
}
impl Default for ValidationFlags {
fn default() -> Self {
ValidationFlags::REPORT_WARNINGS
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ContentProcessing {
#[default]
Strict,
Lax,
Skip,
}
#[derive(Debug, Clone)]
pub struct SchemaInfo {
pub element_decl: Option<ElementKey>,
pub attribute_decl: Option<AttributeKey>,
pub schema_type: Option<TypeKey>,
pub member_type: Option<TypeKey>,
pub validity: SchemaValidity,
pub validation_attempted: ValidationAttempted,
pub is_default: bool,
pub is_nil: bool,
pub content_type: Option<ContentType>,
pub typed_value: Option<XmlValue>,
pub normalized_value: Option<String>,
pub schema_error_codes: Vec<&'static str>,
pub notation: Option<NotationKey>,
pub deferred_by_cta: bool,
pub type_source: Option<TypeSource>,
#[cfg(feature = "xsd11")]
pub cta_selected: bool,
#[cfg(feature = "xsd11")]
pub assertion_outcome: Option<AssertionOutcome>,
}
impl SchemaInfo {
pub fn empty() -> Self {
SchemaInfo {
element_decl: None,
attribute_decl: None,
schema_type: None,
member_type: None,
validity: SchemaValidity::NotKnown,
validation_attempted: ValidationAttempted::None,
is_default: false,
is_nil: false,
content_type: None,
typed_value: None,
normalized_value: None,
schema_error_codes: Vec::new(),
notation: None,
deferred_by_cta: false,
type_source: None,
#[cfg(feature = "xsd11")]
cta_selected: false,
#[cfg(feature = "xsd11")]
assertion_outcome: None,
}
}
pub fn valid_element(
element_decl: ElementKey,
schema_type: TypeKey,
content_type: ContentType,
) -> Self {
SchemaInfo {
element_decl: Some(element_decl),
attribute_decl: None,
schema_type: Some(schema_type),
member_type: None,
validity: SchemaValidity::Valid,
validation_attempted: ValidationAttempted::Full,
is_default: false,
is_nil: false,
content_type: Some(content_type),
typed_value: None,
normalized_value: None,
schema_error_codes: Vec::new(),
notation: None,
deferred_by_cta: false,
type_source: Some(TypeSource::Declaration),
#[cfg(feature = "xsd11")]
cta_selected: false,
#[cfg(feature = "xsd11")]
assertion_outcome: None,
}
}
pub fn valid_attribute(attribute_decl: AttributeKey, schema_type: TypeKey) -> Self {
SchemaInfo {
element_decl: None,
attribute_decl: Some(attribute_decl),
schema_type: Some(schema_type),
member_type: None,
validity: SchemaValidity::Valid,
validation_attempted: ValidationAttempted::Full,
is_default: false,
is_nil: false,
content_type: None,
typed_value: None,
normalized_value: None,
schema_error_codes: Vec::new(),
notation: None,
deferred_by_cta: false,
type_source: Some(TypeSource::Declaration),
#[cfg(feature = "xsd11")]
cta_selected: false,
#[cfg(feature = "xsd11")]
assertion_outcome: None,
}
}
pub fn invalid() -> Self {
SchemaInfo {
validity: SchemaValidity::Invalid,
..SchemaInfo::empty()
}
}
pub fn is_simple_type(&self) -> bool {
matches!(self.schema_type, Some(TypeKey::Simple(_)))
}
pub fn is_complex_type(&self) -> bool {
matches!(self.schema_type, Some(TypeKey::Complex(_)))
}
}
#[derive(Debug, Clone)]
pub struct ExpectedElement {
pub local_name: NameId,
pub namespace: Option<NameId>,
pub element_key: Option<ElementKey>,
}
#[derive(Debug, Clone)]
pub struct ExpectedAttribute {
pub local_name: NameId,
pub namespace: Option<NameId>,
pub attribute_key: Option<AttributeKey>,
pub required: bool,
}
#[derive(Debug, Clone)]
pub struct DefaultAttribute {
pub local_name: NameId,
pub namespace: Option<NameId>,
pub attribute_key: AttributeKey,
pub value: String,
}
#[cfg(feature = "xsd11")]
#[derive(Debug, Clone)]
pub struct InheritedAttribute {
pub local_name: NameId,
pub namespace: Option<NameId>,
pub attribute_key: Option<AttributeKey>,
pub value: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SchemaLocationHint {
pub namespace: String,
pub location: String,
pub base_uri: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NoNamespaceSchemaLocationHint {
pub location: String,
pub base_uri: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_schema_info_empty() {
let info = SchemaInfo::empty();
assert_eq!(info.validity, SchemaValidity::NotKnown);
assert!(info.element_decl.is_none());
assert!(info.attribute_decl.is_none());
assert!(info.schema_type.is_none());
assert!(info.member_type.is_none());
assert!(!info.is_default);
assert!(!info.is_nil);
assert!(info.content_type.is_none());
assert!(info.typed_value.is_none());
assert!(info.type_source.is_none());
#[cfg(feature = "xsd11")]
{
assert!(!info.cta_selected);
assert!(info.assertion_outcome.is_none());
}
}
#[test]
fn test_schema_info_invalid() {
let info = SchemaInfo::invalid();
assert_eq!(info.validity, SchemaValidity::Invalid);
assert!(info.element_decl.is_none());
}
#[test]
fn test_is_simple_type() {
let info = SchemaInfo::empty();
assert!(!info.is_simple_type());
assert!(!info.is_complex_type());
use slotmap::SlotMap;
let mut sm: SlotMap<crate::ids::SimpleTypeKey, ()> = SlotMap::with_key();
let sk = sm.insert(());
let mut info = SchemaInfo::empty();
info.schema_type = Some(TypeKey::Simple(sk));
assert!(info.is_simple_type());
assert!(!info.is_complex_type());
}
#[test]
fn test_is_complex_type() {
use slotmap::SlotMap;
let mut sm: SlotMap<crate::ids::ComplexTypeKey, ()> = SlotMap::with_key();
let ck = sm.insert(());
let mut info = SchemaInfo::empty();
info.schema_type = Some(TypeKey::Complex(ck));
assert!(info.is_complex_type());
assert!(!info.is_simple_type());
}
#[test]
fn test_schema_validity_default() {
let v = SchemaValidity::default();
assert_eq!(v, SchemaValidity::NotKnown);
}
#[test]
fn test_content_type_default() {
let ct = ContentType::default();
assert_eq!(ct, ContentType::Empty);
}
#[test]
fn test_content_processing_default() {
let cp = ContentProcessing::default();
assert_eq!(cp, ContentProcessing::Strict);
}
#[test]
fn test_validation_flags_default() {
let flags = ValidationFlags::default();
assert!(flags.contains(ValidationFlags::REPORT_WARNINGS));
assert!(!flags.contains(ValidationFlags::ALLOW_XML_ATTRIBUTES));
assert!(!flags.contains(ValidationFlags::PROCESS_IDENTITY_CONSTRAINTS));
assert!(!flags.contains(ValidationFlags::STRICT_MODE));
}
#[test]
fn test_validation_flags_bitops() {
let flags = ValidationFlags::REPORT_WARNINGS | ValidationFlags::STRICT_MODE;
assert!(flags.contains(ValidationFlags::REPORT_WARNINGS));
assert!(flags.contains(ValidationFlags::STRICT_MODE));
assert!(!flags.contains(ValidationFlags::PROCESS_IDENTITY_CONSTRAINTS));
let combined = flags | ValidationFlags::PROCESS_IDENTITY_CONSTRAINTS;
assert!(combined.contains(ValidationFlags::PROCESS_IDENTITY_CONSTRAINTS));
}
#[cfg(feature = "xsd11")]
#[test]
fn test_process_assertions_flag() {
let default_flags = ValidationFlags::default();
assert!(
!default_flags.contains(ValidationFlags::PROCESS_ASSERTIONS),
"PROCESS_ASSERTIONS must not be in defaults"
);
let with_flag = default_flags | ValidationFlags::PROCESS_ASSERTIONS;
assert!(with_flag.contains(ValidationFlags::PROCESS_ASSERTIONS));
assert!(with_flag.contains(ValidationFlags::REPORT_WARNINGS));
assert!(!with_flag.contains(ValidationFlags::ALLOW_XML_ATTRIBUTES));
let with_xml = with_flag | ValidationFlags::ALLOW_XML_ATTRIBUTES;
assert!(with_xml.contains(ValidationFlags::ALLOW_XML_ATTRIBUTES));
}
#[test]
fn test_node_identity_eq() {
let a = NodeIdentity(42);
let b = NodeIdentity(42);
let c = NodeIdentity(99);
assert_eq!(a, b);
assert_ne!(a, c);
}
}