pub mod xs;
mod namespace;
mod namespace_prefix;
mod occurs;
mod qname;
use std::borrow::Cow;
use std::collections::btree_map::{BTreeMap, Entry, Iter};
use self::xs::Schema;
pub use namespace::Namespace;
pub use namespace_prefix::NamespacePrefix;
pub use occurs::{MaxOccurs, MinOccurs};
pub use qname::QName;
#[derive(Default, Debug)]
pub struct Schemas {
schemas: SchemaFiles,
namespace_infos: NamespaceInfos,
known_prefixes: NamespacePrefixes,
known_namespaces: Namespaces,
next_schema_id: usize,
next_namespace_id: usize,
}
#[derive(Debug)]
pub struct NamespaceInfo {
pub prefix: Option<NamespacePrefix>,
pub namespace: Option<Namespace>,
pub schemas: Vec<SchemaId>,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct SchemaId(pub usize);
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct NamespaceId(pub usize);
pub type SchemaFiles = BTreeMap<SchemaId, Schema>;
pub type NamespaceInfos = BTreeMap<NamespaceId, NamespaceInfo>;
pub type Namespaces = BTreeMap<Option<Namespace>, NamespaceId>;
pub type NamespacePrefixes = BTreeMap<NamespacePrefix, NamespaceId>;
impl Schemas {
pub fn add_schema(
&mut self,
prefix: Option<NamespacePrefix>,
namespace: Option<Namespace>,
schema: Schema,
) {
let schema_id = SchemaId(self.next_schema_id);
let schema_info = self.get_or_create_namespace_info_mut(prefix, namespace);
schema_info.schemas.push(schema_id);
self.next_schema_id = self.next_schema_id.wrapping_add(1);
match self.schemas.entry(schema_id) {
Entry::Vacant(e) => e.insert(schema),
Entry::Occupied(_) => crate::unreachable!(),
};
}
pub fn get_or_create_namespace_info_mut(
&mut self,
prefix: Option<NamespacePrefix>,
namespace: Option<Namespace>,
) -> &mut NamespaceInfo {
let (ns, id) = match self.known_namespaces.entry(namespace) {
Entry::Occupied(e) => {
let id = *e.get();
let ns = self.namespace_infos.get_mut(&id).unwrap();
(ns, id)
}
Entry::Vacant(e) => {
let id = NamespaceId(self.next_namespace_id);
self.next_namespace_id = self.next_namespace_id.wrapping_add(1);
let namespace = e.key().clone();
e.insert(id);
let ns = match self.namespace_infos.entry(id) {
Entry::Vacant(e) => e.insert(NamespaceInfo::new(namespace)),
Entry::Occupied(_) => crate::unreachable!(),
};
(ns, id)
}
};
if let Some(mut prefix) = prefix {
if matches!(self.known_prefixes.get(&prefix), Some(x) if *x != id) {
let ext = format!("_{}", id.0);
let ext = ext.as_bytes();
let mut p = prefix.0.into_owned();
p.extend_from_slice(ext);
prefix = NamespacePrefix(Cow::Owned(p));
}
self.known_prefixes.insert(prefix.clone(), id);
if ns.prefix.is_none() {
ns.prefix = Some(prefix);
}
}
ns
}
pub fn schemas(&self) -> Iter<'_, SchemaId, Schema> {
self.schemas.iter()
}
pub fn namespaces(&self) -> Iter<'_, NamespaceId, NamespaceInfo> {
self.namespace_infos.iter()
}
#[must_use]
pub fn get_schema(&self, id: &SchemaId) -> Option<&Schema> {
self.schemas.get(id)
}
#[must_use]
pub fn get_namespace_info(&self, id: &NamespaceId) -> Option<&NamespaceInfo> {
self.namespace_infos.get(id)
}
#[must_use]
pub fn get_namespace_info_by_namespace(
&self,
ns: &Option<Namespace>,
) -> Option<&NamespaceInfo> {
let id = self.resolve_namespace(ns)?;
self.get_namespace_info(&id)
}
#[must_use]
pub fn resolve_prefix(&self, prefix: &NamespacePrefix) -> Option<NamespaceId> {
Some(*self.known_prefixes.get(prefix)?)
}
#[must_use]
pub fn resolve_namespace(&self, ns: &Option<Namespace>) -> Option<NamespaceId> {
Some(*self.known_namespaces.get(ns)?)
}
}
impl NamespaceInfo {
#[must_use]
pub fn new(namespace: Option<Namespace>) -> Self {
Self {
prefix: None,
namespace,
schemas: Vec::new(),
}
}
}