pub mod mathml;
pub mod parser;
pub mod root;
pub mod xml;
use std::fmt;
pub const TYPE_START: char = '[';
pub const TYPE_STOP: char = ']';
pub const NAMESPACE_SEPARATOR: char = '/';
pub const PARAMETER_SEPARATOR: char = ' ';
pub const STRING_START: char = '“';
pub const STRING_STOP: char = '”';
pub const BOOLEAN_TRUE: char = 't';
pub const BOOLEAN_FALSE: char = 'f';
#[derive(Debug)]
pub enum Argument {
None,
Bool(bool),
String(String),
Type(Type),
}
#[derive(Clone, Debug)]
pub enum Type {
And(Vec<Type>),
Boolean(bool),
ErrorMessage(String),
False,
Name(String),
Namespace(String),
Not(Box<Type>),
QualifiedName(String),
True,
MathMLMarkup(mathml::markup::Markup),
MathMLSerializeAsContentMarkup(Box<Type>),
MathMLSerializeAsParallelMarkup(Box<Type>),
MathMLSerializeAsPresentationMarkup(Box<Type>),
}
impl Type {
fn new(qname: &str, args: Vec<Argument>) -> Result<Type, Type> {
match qname {
root::and::QNAME => root::and::new(args),
root::boolean::QNAME => root::boolean::new(args),
root::boolean_false::QNAME => root::boolean_false::new(args),
root::boolean_true::QNAME => root::boolean_true::new(args),
root::error_message::QNAME => root::error_message::new(args),
root::name::QNAME => root::name::new(args),
root::namespace::QNAME => root::namespace::new(args),
root::not::QNAME => root::not::new(args),
root::qualified_name::QNAME => root::qualified_name::new(args),
mathml::markup::QNAME => mathml::markup::new(args),
mathml::serialize_as_content_markup::QNAME => {
mathml::serialize_as_content_markup::new(args)
}
mathml::serialize_as_parallel_markup::QNAME => {
mathml::serialize_as_parallel_markup::new(args)
}
mathml::serialize_as_presentation_markup::QNAME => {
mathml::serialize_as_presentation_markup::new(args)
}
_ => Err(Type::ErrorMessage(format!(
"Unknown type qname '{}' in Type::new(qname, args).",
qname,
))),
}
}
pub fn evaluate(&self) -> Type {
match self {
Type::And(args) => root::and::evaluate(args),
Type::Boolean(args) => root::boolean::evaluate(args),
Type::Not(args) => root::not::evaluate(args),
Type::MathMLSerializeAsContentMarkup(args) => {
mathml::serialize_as_content_markup::evaluate(args)
}
Type::MathMLSerializeAsParallelMarkup(args) => {
mathml::serialize_as_parallel_markup::evaluate(args)
}
Type::MathMLSerializeAsPresentationMarkup(args) => {
mathml::serialize_as_presentation_markup::evaluate(args)
}
_ => self.clone(),
}
}
fn fmt(&self, s: &mut String, namespace: &str) {
s.push(TYPE_START);
if self.namespace() == namespace {
s.push_str(self.name());
} else {
s.push_str(self.qualified_name());
}
self.parameters().fmt(s, namespace);
s.push(TYPE_STOP);
}
fn name(&self) -> &str {
let qname = self.qualified_name();
if let Some(i) = qname.rfind(NAMESPACE_SEPARATOR) {
return &qname[i + 1..];
} else {
unreachable!();
}
}
fn namespace(&self) -> &str {
let qname = self.qualified_name();
if let Some(i) = qname.rfind(NAMESPACE_SEPARATOR) {
return &qname[0..=i];
} else {
unreachable!();
}
}
fn parameters(&self) -> Parameters {
match self {
Type::And(rvt) => Parameters::RefVecType(rvt),
Type::Boolean(rb) => Parameters::RefBool(rb),
Type::ErrorMessage(rstr) => Parameters::RefStr(rstr),
Type::False => Parameters::None,
Type::Name(rstr) => Parameters::RefStr(rstr),
Type::Namespace(rstr) => Parameters::RefStr(rstr),
Type::Not(rbt) => Parameters::RefBoxType(rbt),
Type::QualifiedName(rstr) => Parameters::RefStr(rstr),
Type::True => Parameters::None,
Type::MathMLMarkup(markup) => markup.parameters(),
Type::MathMLSerializeAsContentMarkup(rbt) => Parameters::RefBoxType(rbt),
Type::MathMLSerializeAsParallelMarkup(rbt) => Parameters::RefBoxType(rbt),
Type::MathMLSerializeAsPresentationMarkup(rbt) => Parameters::RefBoxType(rbt),
}
}
fn qualified_name(&self) -> &str {
match self {
Type::And(_) => root::and::QNAME,
Type::Boolean(_) => root::boolean::QNAME,
Type::ErrorMessage(_) => root::error_message::QNAME,
Type::False => root::boolean_false::QNAME,
Type::Name(_) => root::name::QNAME,
Type::Namespace(_) => root::namespace::QNAME,
Type::Not(_) => root::not::QNAME,
Type::QualifiedName(_) => root::qualified_name::QNAME,
Type::True => root::boolean_true::QNAME,
Type::MathMLMarkup(_) => mathml::markup::QNAME,
Type::MathMLSerializeAsContentMarkup(_) => mathml::serialize_as_content_markup::QNAME,
Type::MathMLSerializeAsParallelMarkup(_) => mathml::serialize_as_parallel_markup::QNAME,
Type::MathMLSerializeAsPresentationMarkup(_) => {
mathml::serialize_as_presentation_markup::QNAME
}
}
}
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = String::with_capacity(8);
self.fmt(&mut s, root::NAMESPACE);
f.write_str(&s)
}
}
pub enum Parameters<'a> {
None,
RefBool(&'a bool),
RefStr(&'a str),
RefBoxType(&'a Box<Type>),
RefVecType(&'a Vec<Type>),
}
impl<'a> Parameters<'a> {
fn fmt_bool(s: &mut String, rb: &bool) {
s.push(PARAMETER_SEPARATOR);
if *rb {
s.push(BOOLEAN_TRUE);
} else {
s.push(BOOLEAN_FALSE);
}
}
fn fmt_str(s: &mut String, rstr: &str) {
s.push(PARAMETER_SEPARATOR);
s.push(STRING_START);
s.push_str(rstr);
s.push(STRING_STOP);
}
fn fmt_box_type(s: &mut String, rbt: &Box<Type>, namespace: &str) {
s.push(PARAMETER_SEPARATOR);
rbt.fmt(s, namespace);
}
fn fmt_vec_type(s: &mut String, rvt: &Vec<Type>, namespace: &str) {
for t in rvt {
s.push(PARAMETER_SEPARATOR);
t.fmt(s, namespace);
}
}
fn fmt(&self, s: &mut String, namespace: &str) {
match self {
Parameters::None => (),
Parameters::RefBool(rb) => Parameters::fmt_bool(s, rb),
Parameters::RefStr(rstr) => Parameters::fmt_str(s, rstr),
Parameters::RefBoxType(rbt) => Parameters::fmt_box_type(s, rbt, namespace),
Parameters::RefVecType(rvt) => Parameters::fmt_vec_type(s, rvt, namespace),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
let mytrue = Type::True;
assert_eq!(mytrue.qualified_name(), "/True");
assert_eq!(mytrue.namespace(), "/");
assert_eq!(mytrue.name(), "True");
let mynot = Type::Not(Box::new(Type::True));
assert_eq!(mynot.to_string(), "[Not [True]]");
let myname = Type::Name("myname".to_string());
assert_eq!(myname.to_string(), "[Name “myname”]");
assert_eq!(std::mem::size_of::<Type>(), 32);
assert_eq!(std::mem::size_of::<Parameters>(), 24);
assert_eq!(std::mem::size_of::<Argument>(), 40);
}
}