haste_fhir_model/r4/
conversion.rs1use 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
15pub 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 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}