use ::serde::{Deserialize, Serialize};
use crate::r5::validate::{Validate, ValidationIssue};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Coded<E> {
Known(E),
Unknown(String),
}
impl<E: Default> Default for Coded<E> {
fn default() -> Self {
Coded::Known(E::default())
}
}
impl<E> Coded<E> {
pub fn known(&self) -> Option<&E> {
match self {
Coded::Known(e) => Some(e),
Coded::Unknown(_) => None,
}
}
#[must_use]
pub fn is_unknown(&self) -> bool {
matches!(self, Coded::Unknown(_))
}
}
impl<E: Serialize> Coded<E> {
#[must_use]
pub fn code(&self) -> String {
match self {
Coded::Known(e) => ::serde_json::to_value(e)
.ok()
.and_then(|v| v.as_str().map(str::to_string))
.unwrap_or_default(),
Coded::Unknown(s) => s.clone(),
}
}
}
impl<E> Validate for Coded<E> {
fn validate(&self) -> Vec<ValidationIssue> {
match self {
Coded::Known(_) => Vec::new(),
Coded::Unknown(code) => vec![ValidationIssue::new(
"code",
format!("code {code:?} is not in the required value set"),
)],
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::r5::codes::AdministrativeGender;
#[test]
fn known_and_unknown_roundtrip() {
for (json, expect) in [
(serde_json::json!("male"), Coded::Known(AdministrativeGender::Male)),
(serde_json::json!("xyz"), Coded::Unknown("xyz".to_string())),
] {
let parsed: Coded<AdministrativeGender> =
serde_json::from_value(json.clone()).unwrap();
assert_eq!(parsed, expect);
assert_eq!(serde_json::to_value(&parsed).unwrap(), json);
}
}
#[test]
fn default_is_known() {
assert_eq!(
Coded::<AdministrativeGender>::default(),
Coded::Known(AdministrativeGender::default())
);
}
}