#![allow(non_camel_case_types)]
#![allow(unused_variables)]
#![allow(dead_code)]
#![allow(unused_imports)]
#![allow(private_bounds)]
#![allow(private_interfaces)]
#[cfg(feature = "xmelt_derive")]
#[doc(hidden)]
pub use xmelt_derive::*;
mod qname; pub use qname::*;
mod context; pub use context::*;
mod item; pub use item::*;
mod container; pub use container::*;
mod from_value; pub use from_value::*;
mod freeze; pub use freeze::*;
#[cfg(feature = "xmelt_derive")]
extern crate self as xmelt;
#[derive(Debug)]
pub enum Error {
MissingValue(String),
DuplicateValue(String),
UnexpectedValue(String),
ParseError(String),
Message(String),
InvalidVariant(String),
InvalidVariants(String, Vec<Error>),
}
impl From<String> for Error {
fn from(a: String) -> Self {
Self::Message(a)
}
}
impl From<&str> for Error {
fn from(a: &str) -> Self {
Self::Message(a.to_owned())
}
}
#[derive(Debug, Clone, Copy)]
pub enum Value<'a> {
Text(&'a str),
Node(roxmltree::Node<'a, 'a>),
}
impl<'a> Value<'a> {
pub fn as_node(&self) -> Option<roxmltree::Node<'a, 'a>> {
if let Self::Node(value) = self {
if let roxmltree::NodeType::Element = value.node_type() {
Some(*value)
} else {
None
}
} else {
None
}
}
pub fn as_text(&self) -> Option<&'a str> {
match self {
Self::Text(text) => Some(text),
Self::Node(node) => {
if let roxmltree::NodeType::Text = node.node_type() {
node.text()
} else {
None
}
},
}
}
pub fn normalise(&mut self) {
if let Self::Node(node) = self {
if let roxmltree::NodeType::Text = node.node_type() {
let mut text_value = Self::Text(node.text().unwrap());
std::mem::swap(self, &mut text_value);
}
}
}
}
impl<'a> From<&'a str> for Value<'a> {
fn from(text: &'a str) -> Self {
Self::Text(text)
}
}
impl<'a> From<roxmltree::Node<'a, 'a>> for Value<'a> {
fn from(node: roxmltree::Node<'a, 'a>) -> Self {
Self::Node(node)
}
}
#[derive(Debug)]
pub struct Node {
attributes: Vec<(String, String)>,
children: Vec<Any>,
}
impl Node {
fn new(node: roxmltree::Node<'_, '_>) -> Result<Self, Error> {
let attributes: Vec<(String, String)> = node
.attributes()
.map(|attribute| {
let name = node.document().input_text()[attribute.range_qname()].to_owned();
let value = attribute.value().to_owned();
(name, value)
})
.collect();
let children: Vec<Any> = node
.children()
.map(|child| {
match child.node_type() {
roxmltree::NodeType::Element => Ok(Any::Node(Node::new(child)?)),
roxmltree::NodeType::Text => Ok(Any::Text(child.text().ok_or_else(|| "Text node has to contain text.")?.to_owned())),
_ => Err(Error::Message(format!("Node of type `{:?}` cannot be made into `xmelt::Node`.", child.node_type())))
}
})
.collect::<Result<_, Error>>()?;
Ok(Self {
attributes,
children,
})
}
}
impl<'freeze> Freeze<'freeze> for Node {
type Kind = ComplexType;
fn de<I>(value: I, restrictions: &Vec<DynRestriction<'freeze, Self>>, context: Context) -> Result<Self, Error>
where
Self: Sized + 'freeze,
I: Into<Value<'freeze>>
{
let node = value.into().as_node().ok_or_else(|| Error::Message(format!("Struct `xmelt::Node` can only be built from a node in {}.", context.path())))?;
Node::new(node)
}
}
#[derive(Debug)]
pub enum Any {
Node(Node),
Text(String),
}
impl<'freeze> Freeze<'freeze> for Any {
type Kind = ComplexType;
fn de<I>(value: I, restrictions: &Vec<DynRestriction<'freeze, Self>>, context: Context) -> Result<Self, Error>
where
Self: Sized + 'freeze,
I: Into<Value<'freeze>>
{
let mut value = value.into();
value.normalise();
let any = match value {
Value::Node(node) => Any::Node(Node::new(node)?),
Value::Text(text) => Any::Text(text.to_owned()),
};
Ok(any)
}
}
#[derive(Debug)]
pub struct List<T> {
storage: Vec<T>
}
impl<'freeze, T> Freeze<'freeze> for List<T>
where T: 'freeze + Freeze<'freeze>
{
type Kind = <T as Freeze<'freeze>>::Kind;
fn de<I>(value: I, restrictions: &Vec<DynRestriction<'freeze, T>>, context: Context) -> Result<Self, Error>
where
Self: Sized + 'freeze,
I: Into<Value<'freeze>>
{
let text = value.into().as_text().ok_or_else(|| Error::Message(format!("Struct `List` can only be built from text, instead got node.")))?;
let list = text
.split(" ")
.map(|p| {
Freeze::de(Value::Text(p), restrictions, context.clone())
})
.collect::<Result<_, _>>()?;
Ok(Self {
storage: list
})
}
}
pub trait Builder<'builder> {
type Output;
const TYPE_NAME: &'static str;
fn new() -> Self;
fn visit_attribute<'qname, IQ: Into<QName<'qname>>>(&mut self, qname: IQ, value: &'builder str, context: Context) -> Result<(), crate::Error>;
fn visit_element<'qname, IQ: Into<QName<'qname>>, IV: Into<Value<'builder>>>(&mut self, qname: IQ, value: IV, context: Context) -> Result<(), crate::Error>;
fn visit_text<IV: Into<Value<'builder>>>(&mut self, value: IV, context: Context) -> Result<(), crate::Error>;
fn build(self, context: Context) -> Result<Self::Output, crate::Error>;
fn accept_element<'qname, IQ: Into<QName<'qname>>>(qname: IQ) -> bool;
fn accept_attribute<'qname, IQ: Into<QName<'qname>>>(qname: IQ) -> bool;
fn accept_text() -> bool;
}
#[derive(Debug)]
#[derive(Freeze)]
#[cfg(feature = "xmelt_derive")]
#[xmelt(namespaces = ["xsi", "http://www.w3.org/2001/XMLSchema-instance"])]
pub struct DocumentAttributes {
#[xmelt(attribute, prefix = "xsi", rename = "schemaLocation")]
schema_location: Option<String>,
}
pub trait Restriction {}
pub trait Storage<'c> {
type Inner;
}
macro_rules! xsd_type {
($type:ident, $inner:ty) => {
pub struct $type;
impl Restriction for $type {}
impl<'c> Storage<'c> for $type {
type Inner = $inner;
}
};
(ref, $type:ident, $inner:ty) => {
pub struct $type;
impl Restriction for $type {}
impl<'c> Storage<'c> for $type {
type Inner = &'c $inner;
}
};
}
xsd_type!(ref, TextType, str);
xsd_type!(NumericType, f64);
xsd_type!(SimpleType, ());
xsd_type!(ComplexType, ());
#[derive(Debug)]
pub struct Pattern {
pattern: String,
regex: regexml::Regex,
}
impl Pattern {
pub fn new(pattern: &str) -> Self {
Self {
regex: regexml::Regex::xsd(pattern, "").unwrap(),
pattern: pattern.to_owned(),
}
}
}
pub trait Restriction2<T: for<'s> Storage<'s>> {
fn validate<'s>(&self, item: <T as Storage<'s>>::Inner) -> Result<(), String>;
}
impl Restriction2<TextType> for Pattern {
fn validate<'s>(&self, item: <TextType as Storage<'s>>::Inner) -> Result<(), String> {
if self.regex.is_match(&item) {
Ok(())
} else {
Err(format!("Unable to match pattern `{}` to text `{}`.", self.pattern, item))
}
}
}