use haste_fhir_model::r4::generated::types::{
FHIRBoolean, FHIRDecimal, FHIRInteger, FHIRPositiveInt, FHIRUnsignedInt,
};
use haste_reflect::MetaValue;
#[derive(Debug, PartialEq)]
pub enum ConvertedValue {
String(String),
Boolean(bool),
Number(f64),
}
impl std::fmt::Display for ConvertedValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ConvertedValue::String(s) => write!(f, "{s}"),
ConvertedValue::Boolean(b) => write!(f, "{b}"),
ConvertedValue::Number(n) => write!(f, "{n}"),
}
}
}
fn downcast_string(value: &dyn MetaValue) -> Option<String> {
match value.fhir_type() {
"canonical" | "base64Binary" | "code" | "string" | "oid" | "id" | "uri" | "url"
| "uuid" | "xhtml" => downcast_string(value.get_field("value").unwrap_or(&String::new())),
"date" => value
.as_any()
.downcast_ref::<haste_fhir_model::r4::generated::types::FHIRDate>()
.and_then(|dt| dt.value.as_ref())
.map(std::string::ToString::to_string),
"dateTime" => value
.as_any()
.downcast_ref::<haste_fhir_model::r4::generated::types::FHIRDateTime>()
.and_then(|dt| dt.value.as_ref())
.map(std::string::ToString::to_string),
"instant" => value
.as_any()
.downcast_ref::<haste_fhir_model::r4::generated::types::FHIRInstant>()
.and_then(|dt| dt.value.as_ref())
.map(std::string::ToString::to_string),
"http://hl7.org/fhirpath/System.String" => value.as_any().downcast_ref::<String>().cloned(),
_ => None,
}
}
fn downcast_number(value: &dyn MetaValue) -> Option<f64> {
match value.fhir_type() {
"integer" => value
.as_any()
.downcast_ref::<FHIRInteger>()
.and_then(|fp_int| downcast_number(fp_int.value.as_ref().unwrap_or(&0))),
"decimal" => value
.as_any()
.downcast_ref::<FHIRDecimal>()
.and_then(|fp_dec| downcast_number(fp_dec.value.as_ref().unwrap_or(&f64::from(0)))),
"positiveInt" => value
.as_any()
.downcast_ref::<FHIRPositiveInt>()
.and_then(|fp_pint| downcast_number(fp_pint.value.as_ref().unwrap_or(&0_u64))),
"unsignedInt" => value
.as_any()
.downcast_ref::<FHIRUnsignedInt>()
.and_then(|fp_uint| downcast_number(fp_uint.value.as_ref().unwrap_or(&0_u64))),
"http://hl7.org/fhirpath/System.Integer" =>
{
#[allow(clippy::cast_precision_loss)]
value.as_any().downcast_ref::<i64>().map(|v| *v as f64)
}
"http://hl7.org/fhirpath/System.Decimal" => value.as_any().downcast_ref::<f64>().copied(),
_ => None,
}
}
fn downcast_bool(value: &dyn MetaValue) -> Option<bool> {
match value.fhir_type() {
"http://hl7.org/fhirpath/System.Boolean" => value.as_any().downcast_ref::<bool>().copied(),
"boolean" => value
.as_any()
.downcast_ref::<FHIRBoolean>()
.and_then(|fp_bool| downcast_bool(fp_bool.value.as_ref().unwrap_or(&false))),
_ => None,
}
}
pub fn convert_meta_value(value: &dyn MetaValue) -> ConvertedValue {
if let Some(s) = downcast_string(value) {
return ConvertedValue::String(s);
} else if let Some(i) = downcast_number(value) {
return ConvertedValue::Number(i);
} else if let Some(b) = downcast_bool(value) {
return ConvertedValue::Boolean(b);
}
ConvertedValue::String(format!("{value:?}"))
}
pub fn convert_string_value(value: &str) -> Option<ConvertedValue> {
if value == "true" || value == "false" {
if let Ok(b) = value.parse::<bool>() {
return Some(ConvertedValue::Boolean(b));
}
None
} else if let Ok(i) = value.parse::<f64>() {
Some(ConvertedValue::Number(i))
} else {
Some(ConvertedValue::String(value.to_string()))
}
}