#![expect(
clippy::disallowed_types,
reason = "ODIN-to-JSON conversion targets the JSON data model by specification (LANG odin \
spec) (#1694)"
)]
use crate::v1_1::bmm_persistence::p_bmm_enumeration::PBmmEnumeration;
pub const INTEGER_UNDERLYING_TYPE_NAME: &str = "INTEGER";
pub const STRING_UNDERLYING_TYPE_NAME: &str = "STRING";
pub const DEFAULT_UNDERLYING_TYPE_NAME: &str = "Integer";
macro_rules! enumeration_field {
($value:expr, $field:ident) => {
match $value {
PBmmEnumeration::PBmmEnumerationInteger(leaf) => &leaf.$field,
PBmmEnumeration::PBmmEnumerationString(leaf) => &leaf.$field,
PBmmEnumeration::PBmmEnumeration(leaf) => &leaf.$field,
}
};
}
impl PBmmEnumeration {
#[must_use]
pub fn item_names(&self) -> &[String] {
enumeration_field!(self, item_names)
.as_deref()
.unwrap_or_default()
}
#[must_use]
pub fn item_values(&self) -> &[serde_json::Value] {
enumeration_field!(self, item_values)
.as_deref()
.unwrap_or_default()
}
#[must_use]
pub fn ancestors(&self) -> &[String] {
enumeration_field!(self, ancestors)
.as_deref()
.unwrap_or_default()
}
#[must_use]
pub fn item_documentations(&self) -> &[String] {
enumeration_field!(self, item_documentations)
.as_deref()
.unwrap_or_default()
}
#[must_use]
pub fn underlying_type_name(&self) -> &str {
match self {
Self::PBmmEnumerationInteger(_) => INTEGER_UNDERLYING_TYPE_NAME,
Self::PBmmEnumerationString(_) => STRING_UNDERLYING_TYPE_NAME,
Self::PBmmEnumeration(leaf) => leaf
.ancestors
.as_deref()
.unwrap_or_default()
.first()
.map_or(DEFAULT_UNDERLYING_TYPE_NAME, String::as_str),
}
}
}
#[cfg(test)]
mod tests {
use crate::v1_1::bmm_persistence::p_bmm_enumeration::PBmmEnumeration;
use crate::v1_1::bmm_persistence::p_bmm_enumeration::PBmmEnumerationData;
use crate::v1_1::bmm_persistence::p_bmm_enumeration_integer::PBmmEnumerationInteger;
fn proportion_kind_2() -> PBmmEnumeration {
PBmmEnumeration::PBmmEnumerationInteger(PBmmEnumerationInteger {
documentation: None,
name: "PROPORTION_KIND_2".to_owned(),
ancestors: Some(vec!["Integer".to_owned()]),
constants: None,
properties: None,
functions: None,
invariants: None,
is_abstract: None,
is_override: None,
generic_parameter_defs: None,
source_schema_id: "openehr_test_1.0.0".to_owned(),
bmm_class: None,
uid: 1,
ancestor_defs: None,
item_names: Some(vec!["pk_ratio".to_owned(), "pk_unitary".to_owned()]),
item_values: Some(vec![
serde_json::Value::from(0),
serde_json::Value::from(1001_i64),
]),
item_documentations: openehr_base::containers::present(Vec::new()),
})
}
#[test]
fn integer_enumeration_reports_its_redefined_underlying_type() {
let enumeration = proportion_kind_2();
assert_eq!(enumeration.underlying_type_name(), "INTEGER");
assert_eq!(enumeration.item_names().len(), 2);
assert_eq!(enumeration.item_values().len(), 2);
assert_eq!(enumeration.item_documentations(), Vec::<String>::new());
}
#[test]
fn un_subtyped_enumeration_falls_back_to_its_first_ancestor_then_integer() {
let mut data = PBmmEnumerationData {
documentation: None,
name: "MAGNITUDE_STATUS".to_owned(),
ancestors: Some(vec!["String".to_owned()]),
constants: None,
properties: None,
functions: None,
invariants: None,
is_abstract: None,
is_override: None,
generic_parameter_defs: None,
source_schema_id: "openehr_test_1.0.0".to_owned(),
bmm_class: None,
uid: 1,
ancestor_defs: None,
item_names: openehr_base::containers::present(Vec::new()),
item_values: openehr_base::containers::present(Vec::new()),
item_documentations: openehr_base::containers::present(Vec::new()),
};
assert_eq!(
PBmmEnumeration::PBmmEnumeration(data.clone()).underlying_type_name(),
"String"
);
data.ancestors = None;
assert_eq!(
PBmmEnumeration::PBmmEnumeration(data).underlying_type_name(),
"Integer"
);
}
}