Skip to main content

haste_fhir_model/r4/
conversion.rs

1use crate::r4::{
2    datetime::{Date, DateTime, Instant, Time},
3    generated::types::{FHIRBoolean, FHIRDecimal, FHIRInteger, FHIRPositiveInt, FHIRUnsignedInt},
4};
5use haste_reflect::MetaValue;
6use std::{collections::HashSet, sync::LazyLock};
7use thiserror::Error;
8
9#[derive(Error, Debug)]
10pub enum DowncastError {
11    #[error("Failed to downcast value to type '{0}'")]
12    FailedDowncast(String),
13}
14
15/// Number types to use in FHIR evaluation
16pub static NUMBER_TYPES: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
17    let mut m = HashSet::new();
18    m.insert("FHIRInteger");
19    m.insert("FHIRDecimal");
20    m.insert("FHIRPositiveInt");
21    m.insert("FHIRUnsignedInt");
22    m.insert("http://hl7.org/fhirpath/System.Decimal");
23    m.insert("http://hl7.org/fhirpath/System.Integer");
24    m
25});
26
27pub static BOOLEAN_TYPES: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
28    let mut m = HashSet::new();
29    m.insert("FHIRBoolean");
30    m.insert("http://hl7.org/fhirpath/System.Boolean");
31    m
32});
33
34pub static DATE_TIME_TYPES: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
35    let mut m = HashSet::new();
36    m.insert("FHIRDate");
37    m.insert("FHIRDateTime");
38    m.insert("FHIRInstant");
39    m.insert("FHIRTime");
40    m.insert("http://hl7.org/fhirpath/System.DateTime");
41    m.insert("http://hl7.org/fhirpath/System.Instant");
42    m.insert("http://hl7.org/fhirpath/System.Date");
43    m.insert("http://hl7.org/fhirpath/System.Time");
44    m
45});
46
47pub static STRING_TYPES: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
48    let mut m = HashSet::new();
49    m.insert("FHIRBase64Binary");
50    m.insert("FHIRCanonical");
51
52    m.insert("FHIRCode");
53    m.insert("FHIRString");
54    m.insert("FHIROid");
55    m.insert("FHIRUri");
56    m.insert("FHIRUrl");
57    m.insert("FHIRUuid");
58    m.insert("FHIRXhtml");
59
60    m.insert("http://hl7.org/fhirpath/System.String");
61    m
62});
63
64pub static PRIMITIVE_TYPES: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
65    let mut res = BOOLEAN_TYPES.clone();
66    res.extend(NUMBER_TYPES.iter().map(|s| *s));
67    res.extend(DATE_TIME_TYPES.iter().map(|s| *s));
68    res.extend(STRING_TYPES.iter().map(|s| *s));
69
70    res
71});
72
73pub fn downcast_bool(value: &dyn MetaValue) -> Result<bool, DowncastError> {
74    match value.typename() {
75        "http://hl7.org/fhirpath/System.Boolean" => value
76            .as_any()
77            .downcast_ref::<bool>()
78            .map(|v| *v)
79            .ok_or_else(|| DowncastError::FailedDowncast(value.typename().to_string())),
80        "FHIRBoolean" => {
81            let fp_bool = value
82                .as_any()
83                .downcast_ref::<FHIRBoolean>()
84                .ok_or_else(|| DowncastError::FailedDowncast(value.typename().to_string()))?;
85            downcast_bool(fp_bool.value.as_ref().unwrap_or(&false))
86        }
87        type_name => Err(DowncastError::FailedDowncast(type_name.to_string())),
88    }
89}
90
91pub fn downcast_string(value: &dyn MetaValue) -> Result<String, DowncastError> {
92    match value.typename() {
93        "FHIRCanonical" | "FHIRBase64Binary" | "FHIRCode" | "FHIRString" | "FHIROid"
94        | "FHIRUri" | "FHIRUrl" | "FHIRUuid" | "FHIRXhtml" => {
95            downcast_string(value.get_field("value").unwrap_or(&"".to_string()))
96        }
97
98        "http://hl7.org/fhirpath/System.String" => value
99            .as_any()
100            .downcast_ref::<String>()
101            .map(|v| v.clone())
102            .ok_or_else(|| DowncastError::FailedDowncast(value.typename().to_string())),
103
104        type_name => Err(DowncastError::FailedDowncast(type_name.to_string())),
105    }
106}
107
108pub fn downcast_number(value: &dyn MetaValue) -> Result<f64, DowncastError> {
109    match value.typename() {
110        "FHIRInteger" => {
111            let fp_integer = value
112                .as_any()
113                .downcast_ref::<FHIRInteger>()
114                .ok_or_else(|| DowncastError::FailedDowncast(value.typename().to_string()))?;
115            downcast_number(fp_integer.value.as_ref().unwrap_or(&0))
116        }
117        "FHIRDecimal" => {
118            let fp_decimal = value
119                .as_any()
120                .downcast_ref::<FHIRDecimal>()
121                .ok_or_else(|| DowncastError::FailedDowncast(value.typename().to_string()))?;
122            downcast_number(fp_decimal.value.as_ref().unwrap_or(&0.0))
123        }
124        "FHIRPositiveInt" => {
125            let fp_positive_int = value
126                .as_any()
127                .downcast_ref::<FHIRPositiveInt>()
128                .ok_or_else(|| DowncastError::FailedDowncast(value.typename().to_string()))?;
129
130            downcast_number(fp_positive_int.value.as_ref().unwrap_or(&0))
131        }
132        "FHIRUnsignedInt" => {
133            let fp_unsigned_int = value
134                .as_any()
135                .downcast_ref::<FHIRUnsignedInt>()
136                .ok_or_else(|| DowncastError::FailedDowncast(value.typename().to_string()))?;
137
138            downcast_number(fp_unsigned_int.value.as_ref().unwrap_or(&0))
139        }
140        "http://hl7.org/fhirpath/System.Integer" => value
141            .as_any()
142            .downcast_ref::<i64>()
143            .map(|v| *v as f64)
144            .ok_or_else(|| DowncastError::FailedDowncast(value.typename().to_string())),
145
146        "http://hl7.org/fhirpath/System.Decimal" => value
147            .as_any()
148            .downcast_ref::<f64>()
149            .map(|v| *v)
150            .ok_or_else(|| DowncastError::FailedDowncast(value.typename().to_string())),
151        type_name => Err(DowncastError::FailedDowncast(type_name.to_string())),
152    }
153}
154
155pub fn downcast_datetime(value: &dyn MetaValue) -> Result<String, DowncastError> {
156    // For simplicity, we will just downcast to string for date and datetime types, as FHIRPath evaluation only requires string representation of dates.
157    match value.typename() {
158        "FHIRDate" | "FHIRDateTime" | "FHIRInstant" | "FHIRTime" => {
159            downcast_datetime(value.get_field("value").unwrap_or(&"".to_string()))
160        }
161        "http://hl7.org/fhirpath/System.Date" => {
162            let fp_date = value
163                .as_any()
164                .downcast_ref::<Date>()
165                .ok_or_else(|| DowncastError::FailedDowncast(value.typename().to_string()))?;
166
167            Ok(fp_date.to_string())
168        }
169        "http://hl7.org/fhirpath/System.DateTime" => {
170            let fp_datetime = value
171                .as_any()
172                .downcast_ref::<DateTime>()
173                .ok_or_else(|| DowncastError::FailedDowncast(value.typename().to_string()))?;
174
175            Ok(fp_datetime.to_string())
176        }
177        "http://hl7.org/fhirpath/System.Instant" => {
178            let fp_instant = value
179                .as_any()
180                .downcast_ref::<Instant>()
181                .ok_or_else(|| DowncastError::FailedDowncast(value.typename().to_string()))?;
182
183            Ok(fp_instant.to_string())
184        }
185        "http://hl7.org/fhirpath/System.Time" => {
186            let fp_time = value
187                .as_any()
188                .downcast_ref::<Time>()
189                .ok_or_else(|| DowncastError::FailedDowncast(value.typename().to_string()))?;
190            Ok(fp_time.to_string())
191        }
192        type_name => Err(DowncastError::FailedDowncast(type_name.to_string())),
193    }
194}