use std::collections::BTreeMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Occurs {
pub min: usize,
pub max: Option<usize>,
}
impl Default for Occurs {
fn default() -> Self {
Self {
min: 1,
max: Some(1),
}
}
}
impl Occurs {
#[must_use]
pub fn permits(self, count: usize) -> bool {
count >= self.min && self.max.is_none_or(|m| count <= m)
}
#[must_use]
pub fn describe(self) -> String {
match (self.min, self.max) {
(1, Some(1)) => "exactly once".to_owned(),
(0, Some(1)) => "at most once".to_owned(),
(0, None) => "any number of times".to_owned(),
(n, None) => format!("at least {n} times"),
(a, Some(b)) if a == b => format!("exactly {a} times"),
(a, Some(b)) => format!("between {a} and {b} times"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BuiltIn {
String,
Boolean,
Decimal,
Integer,
NonNegativeInteger,
Double,
Date,
DateTime,
AnyUri,
}
impl BuiltIn {
#[must_use]
pub fn from_name(name: &str) -> Option<Self> {
let local = name.rsplit(':').next().unwrap_or(name);
Some(match local {
"string" | "normalizedString" | "token" | "NMTOKEN" | "Name"
| "NCName" | "ID" | "IDREF" | "language" => Self::String,
"boolean" => Self::Boolean,
"decimal" => Self::Decimal,
"integer" | "int" | "long" | "short" | "byte" => Self::Integer,
"nonNegativeInteger" | "positiveInteger" | "unsignedInt"
| "unsignedLong" | "unsignedShort" => Self::NonNegativeInteger,
"double" | "float" => Self::Double,
"date" => Self::Date,
"dateTime" => Self::DateTime,
"anyURI" => Self::AnyUri,
_ => return None,
})
}
}
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Facets {
pub enumeration: Vec<String>,
pub pattern: Option<String>,
pub min_length: Option<usize>,
pub max_length: Option<usize>,
pub length: Option<usize>,
pub min_inclusive: Option<f64>,
pub max_inclusive: Option<f64>,
pub min_exclusive: Option<f64>,
pub max_exclusive: Option<f64>,
}
impl Facets {
#[must_use]
pub fn is_empty(&self) -> bool {
*self == Self::default()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct SimpleType {
pub base: BuiltIn,
pub facets: Facets,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Content {
Simple(SimpleType),
Sequence(Vec<Particle>),
Choice(Vec<Particle>),
Any,
Empty,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Particle {
pub name: String,
pub occurs: Occurs,
pub content: Box<Content>,
pub attributes: Vec<AttributeDecl>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct AttributeDecl {
pub name: String,
pub required: bool,
pub simple_type: SimpleType,
}
#[derive(Debug, Clone)]
pub struct Schema {
pub target_namespace: Option<String>,
pub elements: BTreeMap<String, Particle>,
pub named_simple_types: BTreeMap<String, SimpleType>,
}
impl Schema {
#[must_use]
pub fn element(&self, name: &str) -> Option<&Particle> {
self.elements.get(name)
}
}