sbml 0.2.2

A parser for SBML
Documentation
use mathml::MathNode;
use roxmltree;
use roxmltree::Attribute;
use roxmltree::Node;
use serde_derive::Deserialize;
use serde_plain;
use std::collections::HashMap;
#[derive(Debug, Deserialize, PartialEq)]
pub enum UnitSidRef {
    SIUnit(UnitSId),
    CustomUnit(String),
}
impl<T: AsRef<str> + ToString> From<&T> for UnitSidRef {
    fn from(r: &T) -> Self {
        match serde_plain::from_str(r.as_ref()) {
            Ok(r) => Self::SIUnit(r),
            Err(_) => Self::CustomUnit(r.to_string()),
        }
    }
}
#[derive(Debug, Hash, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum UnitSId {
    Ampere,
    Avogadro,
    Coulomb,
    Gray,
    Joule,
    Litre,
    Mole,
    Radian,
    Steradian,
    Weber,
    Dimensionless,
    Henry,
    Katal,
    Lumen,
    Newton,
    Tesla,
    Becquerel,
    Farad,
    Hertz,
    Kelvin,
    Lux,
    Ohm,
    Siemens,
    Volt,
    Candela,
    Gram,
    Item,
    Kilogram,
    Metre,
    Pascal,
    Sievert,
    Watt,
    Second,
}
#[derive(Debug, Default, PartialEq)]

pub struct ModelUnits {
    pub substance_units: Option<UnitSidRef>,
    pub time_units: Option<UnitSidRef>,
    pub extent_units: Option<UnitSidRef>,
    pub volume_units: Option<UnitSidRef>,
    pub area_units: Option<UnitSidRef>,
    pub length_units: Option<UnitSidRef>,
    pub conversion_factor: Option<UnitSidRef>,
}

impl From<&[Attribute<'_>]> for ModelUnits {
    fn from(value: &[Attribute<'_>]) -> Self {
        let hmap: HashMap<String, String> = value
            .iter()
            .map(|a| (a.name().to_owned(), a.value().to_owned()))
            .collect();
        ModelUnits {
            substance_units: hmap.get("substanceUnits").map(|p| p.into()),
            time_units: hmap.get("timeUnits").map(|p| p.into()),
            extent_units: hmap.get("extentUnits").map(|p| p.into()),
            volume_units: hmap.get("volumeUnits").map(|p| p.into()),
            area_units: hmap.get("areaUnits").map(|p| p.into()),
            length_units: hmap.get("lengthUnits").map(|p| p.into()),
            conversion_factor: hmap.get("conversionFactor").map(|p| p.into()),
        }
    }
}
#[derive(Debug, PartialEq)]
pub struct Unit {
    exponent: f64,
    scale: i64,
    multiplier: f64,
}
impl From<Node<'_, '_>> for Unit {
    fn from(value: Node<'_, '_>) -> Self {
        Unit {
            exponent: value.attribute("exponent").unwrap().parse().unwrap(),
            scale: value.attribute("scale").unwrap().parse().unwrap(),
            multiplier: value.attribute("multiplier").unwrap().parse().unwrap(),
        }
    }
}
#[derive(Debug, PartialEq)]
pub struct Compartment {
    units: Option<UnitSidRef>,
    spatial_dimensions: Option<f64>,
    size: Option<f64>,
    constant: bool,
}
impl From<Node<'_, '_>> for Compartment {
    fn from(value: Node<'_, '_>) -> Self {
        Compartment {
            spatial_dimensions: value
                .attribute("spatialDimensions")
                .map(|p| p.parse().unwrap()),
            size: value.attribute("size").map(|p| p.parse().unwrap()),
            constant: value.attribute("constant").unwrap().parse().unwrap(),
            units: value.attribute("units").map(|p| UnitSidRef::from(&p)),
        }
    }
}
#[derive(Debug, PartialEq)]
pub struct Specie {
    compartment: String,
    initial_concentration: Option<f64>,
    initial_amount: Option<f64>,
    substance_units: Option<UnitSidRef>,
    has_only_substance_units: bool,
    boundary_condition: bool,
    constant: bool,
    conversion_factor: Option<String>,
}
impl<'a> From<Node<'a, 'a>> for Specie {
    fn from(value: Node<'a, 'a>) -> Self {
        Specie {
            compartment: value.attribute("compartment").unwrap().to_owned(),
            initial_concentration: value
                .attribute("initialConcentration")
                .map(|p| p.parse().unwrap()),
            initial_amount: value.attribute("initialAmount").map(|p| p.parse().unwrap()),
            substance_units: value
                .attribute("substanceUnits")
                .map(|p| UnitSidRef::from(&p)),
            has_only_substance_units: value
                .attribute("hasOnlySubstanceUnits")
                .unwrap()
                .parse()
                .unwrap(),
            boundary_condition: value
                .attribute("boundaryCondition")
                .unwrap()
                .parse()
                .unwrap(),
            constant: value.attribute("constant").unwrap().parse().unwrap(),
            conversion_factor: value.attribute("conversionFactor").map(|r| r.to_owned()),
        }
    }
}
#[derive(Debug, PartialEq)]
pub struct Parameter {
    value: Option<f64>,
    units: Option<UnitSidRef>,
    constant: bool,
}
impl<'a> From<Node<'a, 'a>> for Parameter {
    fn from(value: Node<'a, 'a>) -> Self {
        Parameter {
            value: value.attribute("value").map(|p| p.parse().unwrap()),
            units: value.attribute("units").map(|p| UnitSidRef::from(&p)),
            constant: value.attribute("constant").unwrap().parse().unwrap(),
        }
    }
}
#[derive(Debug, PartialEq)]
pub struct InitialAssignment {
    pub symbol: String,
}
type HL<T> = HashMap<String, T>;
#[derive(Debug, Default, PartialEq)]
pub struct Model {
    pub model_units: ModelUnits,
    pub initial_assignments: HL<InitialAssignment>,
    pub parameters: HL<Parameter>,
    pub species: HL<Specie>,
    pub compartments: HL<Compartment>,
    pub unit_definitions: HL<HashMap<UnitSId, Unit>>,
    pub constraints: Vec<Constraint>,
}

#[derive(Debug, PartialEq)]
pub struct Function {
    math: MathNode,
}
#[derive(Debug, PartialEq)]
pub enum Rule<'a> {
    AlgebraicRule { math: MathNode },
    AssignmentRule { math: MathNode, variable: &'a str },
    RateRule { math: MathNode, variable: &'a str },
}
#[derive(Debug, PartialEq)]
pub struct Constraint {
    pub(crate) math: Option<MathNode>,
    pub(crate) message: String,
}