use std::collections::BTreeMap;
use crate::bmm_persistence::p_bmm_class::PBmmClass;
use crate::bmm_persistence::p_bmm_constant::PBmmConstant;
use crate::bmm_persistence::p_bmm_enumeration::PBmmEnumeration;
use crate::bmm_persistence::p_bmm_function::PBmmFunction;
use crate::bmm_persistence::p_bmm_generic_parameter::PBmmGenericParameter;
use crate::bmm_persistence::p_bmm_generic_type::PBmmGenericType;
use crate::bmm_persistence::p_bmm_property::PBmmProperty;
macro_rules! every_leaf {
($value:expr, |$leaf:ident| $body:expr) => {
match $value {
PBmmClass::PBmmEnumeration(PBmmEnumeration::PBmmEnumerationInteger($leaf)) => $body,
PBmmClass::PBmmEnumeration(PBmmEnumeration::PBmmEnumerationString($leaf)) => $body,
PBmmClass::PBmmEnumeration(PBmmEnumeration::PBmmEnumeration($leaf)) => $body,
PBmmClass::PBmmClass($leaf) => $body,
PBmmClass::PBmmInterface($leaf) => $body,
}
};
}
macro_rules! class_leaf {
($value:expr, |$leaf:ident| $body:expr, $absent:expr) => {
match $value {
PBmmClass::PBmmEnumeration(PBmmEnumeration::PBmmEnumerationInteger($leaf)) => $body,
PBmmClass::PBmmEnumeration(PBmmEnumeration::PBmmEnumerationString($leaf)) => $body,
PBmmClass::PBmmEnumeration(PBmmEnumeration::PBmmEnumeration($leaf)) => $body,
PBmmClass::PBmmClass($leaf) => $body,
PBmmClass::PBmmInterface(_) => $absent,
}
};
}
impl PBmmClass {
#[must_use]
pub fn name(&self) -> &str {
every_leaf!(self, |leaf| leaf.name.as_str())
}
#[must_use]
pub fn documentation(&self) -> Option<&str> {
every_leaf!(self, |leaf| leaf.documentation.as_deref())
}
#[must_use]
pub fn ancestors(&self) -> &[String] {
class_leaf!(
self,
|leaf| leaf.ancestors.as_deref().unwrap_or_default(),
&[]
)
}
#[must_use]
pub fn ancestor_defs(&self) -> &[PBmmGenericType] {
class_leaf!(
self,
|leaf| leaf.ancestor_defs.as_deref().unwrap_or_default(),
&[]
)
}
#[must_use]
pub fn properties(&self) -> Option<&BTreeMap<String, PBmmProperty>> {
class_leaf!(self, |leaf| leaf.properties.as_ref(), None)
}
#[must_use]
pub fn functions(&self) -> Option<&BTreeMap<String, PBmmFunction>> {
every_leaf!(self, |leaf| leaf.functions.as_ref())
}
#[must_use]
pub fn constants(&self) -> Option<&BTreeMap<String, PBmmConstant>> {
class_leaf!(self, |leaf| leaf.constants.as_ref(), None)
}
#[must_use]
pub fn invariants(&self) -> Option<&BTreeMap<String, String>> {
class_leaf!(self, |leaf| leaf.invariants.as_ref(), None)
}
#[must_use]
pub fn generic_parameter_defs(&self) -> Option<&BTreeMap<String, PBmmGenericParameter>> {
class_leaf!(self, |leaf| leaf.generic_parameter_defs.as_ref(), None)
}
#[must_use]
pub fn is_abstract(&self) -> bool {
class_leaf!(self, |leaf| leaf.is_abstract.unwrap_or(false), true)
}
#[must_use]
pub fn is_override(&self) -> bool {
class_leaf!(self, |leaf| leaf.is_override.unwrap_or(false), false)
}
pub fn set_is_override(&mut self, value: bool) {
class_leaf!(self, |leaf| leaf.is_override = Some(value), ());
}
#[must_use]
pub fn source_schema_id(&self) -> Option<&str> {
class_leaf!(self, |leaf| Some(leaf.source_schema_id.as_str()), None)
}
#[must_use]
pub fn uid(&self) -> Option<i32> {
class_leaf!(self, |leaf| Some(leaf.uid), None)
}
#[must_use]
pub fn is_generic(&self) -> bool {
self.generic_parameter_defs()
.is_some_and(|parameters| !parameters.is_empty())
}
}
#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
use crate::bmm_persistence::p_bmm_class::PBmmClass;
use crate::bmm_persistence::p_bmm_class::PBmmClassData;
use crate::bmm_persistence::p_bmm_generic_parameter::PBmmGenericParameter;
use crate::bmm_persistence::p_bmm_interface::PBmmInterface;
fn class(
name: &str,
generic_parameter_defs: Option<BTreeMap<String, PBmmGenericParameter>>,
) -> PBmmClass {
PBmmClass::PBmmClass(PBmmClassData {
documentation: None,
name: name.to_owned(),
ancestors: openehr_base::containers::present(Vec::new()),
constants: None,
properties: None,
functions: None,
invariants: None,
is_abstract: None,
is_override: None,
generic_parameter_defs,
source_schema_id: "openehr_test_1.0.0".to_owned(),
bmm_class: None,
uid: 1,
ancestor_defs: openehr_base::containers::present(Vec::new()),
})
}
fn ordered_t() -> BTreeMap<String, PBmmGenericParameter> {
[(
"T".to_owned(),
PBmmGenericParameter {
documentation: None,
name: "T".to_owned(),
conforms_to_type: Some("Ordered".to_owned()),
bmm_generic_parameter: None,
},
)]
.into_iter()
.collect()
}
#[test]
fn absent_flags_read_as_false() {
let class = class("ELEMENT", None);
assert!(!class.is_abstract());
assert!(!class.is_override());
assert!(!class.is_generic());
assert_eq!(class.name(), "ELEMENT");
assert_eq!(class.source_schema_id(), Some("openehr_test_1.0.0"));
assert_eq!(class.uid(), Some(1));
assert!(class.ancestors().is_empty());
assert!(class.ancestor_defs().is_empty());
assert!(class.properties().is_none());
assert!(class.functions().is_none());
assert!(class.constants().is_none());
assert!(class.invariants().is_none());
assert!(class.documentation().is_none());
}
#[test]
fn is_generic_needs_at_least_one_formal_parameter() {
assert!(!class("Interval", Some(BTreeMap::new())).is_generic());
assert!(class("Interval", Some(ordered_t())).is_generic());
}
#[test]
fn set_is_override_marks_the_including_definition() {
let mut class = class("DV_TEXT", None);
class.set_is_override(true);
assert!(class.is_override());
}
#[test]
fn an_interface_leaf_reads_its_own_three_attributes_and_absents_the_rest() {
let mut interface = PBmmClass::PBmmInterface(PBmmInterface {
documentation: Some("a pure operation interface".to_owned()),
name: "TERMINOLOGY_ACCESS".to_owned(),
functions: Some(BTreeMap::new()),
});
assert_eq!(interface.name(), "TERMINOLOGY_ACCESS");
assert_eq!(
interface.documentation(),
Some("a pure operation interface")
);
assert!(interface.functions().is_some());
assert!(interface.ancestors().is_empty());
assert!(interface.ancestor_defs().is_empty());
assert!(interface.properties().is_none());
assert!(interface.constants().is_none());
assert!(interface.invariants().is_none());
assert!(interface.generic_parameter_defs().is_none());
assert!(!interface.is_generic());
assert!(interface.is_abstract());
assert_eq!(interface.source_schema_id(), None);
assert_eq!(interface.uid(), None);
interface.set_is_override(true);
assert!(!interface.is_override());
}
}