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("integer");
19 m.insert("decimal");
20 m.insert("positiveInt");
21 m.insert("unsignedInt");
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("boolean");
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("date");
37 m.insert("dateTime");
38 m.insert("instant");
39 m.insert("time");
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("base64Binary");
50 m.insert("canonical");
51
52 m.insert("id");
53 m.insert("code");
54 m.insert("string");
55 m.insert("oid");
56 m.insert("uri");
57 m.insert("url");
58 m.insert("uuid");
59 m.insert("xhtml");
60
61 m.insert("http://hl7.org/fhirpath/System.String");
62 m
63});
64
65pub static PRIMITIVE_TYPES: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
66 let mut res = BOOLEAN_TYPES.clone();
67 res.extend(NUMBER_TYPES.iter().map(|s| *s));
68 res.extend(DATE_TIME_TYPES.iter().map(|s| *s));
69 res.extend(STRING_TYPES.iter().map(|s| *s));
70
71 res
72});
73
74pub fn downcast_bool(value: &dyn MetaValue) -> Result<bool, DowncastError> {
75 match value.fhir_type() {
76 "http://hl7.org/fhirpath/System.Boolean" => value
77 .as_any()
78 .downcast_ref::<bool>()
79 .map(|v| *v)
80 .ok_or_else(|| DowncastError::FailedDowncast(value.fhir_type().to_string())),
81 "boolean" => {
82 let fp_bool = value
83 .as_any()
84 .downcast_ref::<FHIRBoolean>()
85 .ok_or_else(|| DowncastError::FailedDowncast(value.fhir_type().to_string()))?;
86 downcast_bool(fp_bool.value.as_ref().unwrap_or(&false))
87 }
88 type_name => Err(DowncastError::FailedDowncast(type_name.to_string())),
89 }
90}
91
92pub fn downcast_string(value: &dyn MetaValue) -> Result<String, DowncastError> {
93 match value.fhir_type() {
94 "canonical" | "base64Binary" | "code" | "string" | "oid" | "uri" | "url" | "uuid"
95 | "id" | "xhtml" => downcast_string(value.get_field("value").unwrap_or(&"".to_string())),
96
97 "http://hl7.org/fhirpath/System.String" => value
98 .as_any()
99 .downcast_ref::<String>()
100 .map(|v| v.clone())
101 .ok_or_else(|| DowncastError::FailedDowncast(value.fhir_type().to_string())),
102
103 type_name => Err(DowncastError::FailedDowncast(type_name.to_string())),
104 }
105}
106
107pub fn downcast_number(value: &dyn MetaValue) -> Result<f64, DowncastError> {
108 match value.fhir_type() {
109 "integer" => {
110 let fp_integer = value
111 .as_any()
112 .downcast_ref::<FHIRInteger>()
113 .ok_or_else(|| DowncastError::FailedDowncast(value.fhir_type().to_string()))?;
114 downcast_number(fp_integer.value.as_ref().unwrap_or(&0))
115 }
116 "decimal" => {
117 let fp_decimal = value
118 .as_any()
119 .downcast_ref::<FHIRDecimal>()
120 .ok_or_else(|| DowncastError::FailedDowncast(value.fhir_type().to_string()))?;
121 downcast_number(fp_decimal.value.as_ref().unwrap_or(&0.0))
122 }
123 "positiveInt" => {
124 let fp_positive_int = value
125 .as_any()
126 .downcast_ref::<FHIRPositiveInt>()
127 .ok_or_else(|| DowncastError::FailedDowncast(value.fhir_type().to_string()))?;
128
129 downcast_number(fp_positive_int.value.as_ref().unwrap_or(&0))
130 }
131 "unsignedInt" => {
132 let fp_unsigned_int = value
133 .as_any()
134 .downcast_ref::<FHIRUnsignedInt>()
135 .ok_or_else(|| DowncastError::FailedDowncast(value.fhir_type().to_string()))?;
136
137 downcast_number(fp_unsigned_int.value.as_ref().unwrap_or(&0))
138 }
139 "http://hl7.org/fhirpath/System.Integer" => value
140 .as_any()
141 .downcast_ref::<i64>()
142 .map(|v| *v as f64)
143 .ok_or_else(|| DowncastError::FailedDowncast(value.fhir_type().to_string())),
144
145 "http://hl7.org/fhirpath/System.Decimal" => value
146 .as_any()
147 .downcast_ref::<f64>()
148 .map(|v| *v)
149 .ok_or_else(|| DowncastError::FailedDowncast(value.fhir_type().to_string())),
150 type_name => Err(DowncastError::FailedDowncast(type_name.to_string())),
151 }
152}
153
154pub fn downcast_datetime(value: &dyn MetaValue) -> Result<String, DowncastError> {
155 match value.fhir_type() {
157 "date" | "dateTime" | "instant" | "time" => {
158 downcast_datetime(value.get_field("value").unwrap_or(&"".to_string()))
159 }
160 "http://hl7.org/fhirpath/System.Date" => {
161 let fp_date = value
162 .as_any()
163 .downcast_ref::<Date>()
164 .ok_or_else(|| DowncastError::FailedDowncast(value.fhir_type().to_string()))?;
165
166 Ok(fp_date.to_string())
167 }
168 "http://hl7.org/fhirpath/System.DateTime" => {
169 let fp_datetime = value
170 .as_any()
171 .downcast_ref::<DateTime>()
172 .ok_or_else(|| DowncastError::FailedDowncast(value.fhir_type().to_string()))?;
173
174 Ok(fp_datetime.to_string())
175 }
176 "http://hl7.org/fhirpath/System.Instant" => {
177 let fp_instant = value
178 .as_any()
179 .downcast_ref::<Instant>()
180 .ok_or_else(|| DowncastError::FailedDowncast(value.fhir_type().to_string()))?;
181
182 Ok(fp_instant.to_string())
183 }
184 "http://hl7.org/fhirpath/System.Time" => {
185 let fp_time = value
186 .as_any()
187 .downcast_ref::<Time>()
188 .ok_or_else(|| DowncastError::FailedDowncast(value.fhir_type().to_string()))?;
189 Ok(fp_time.to_string())
190 }
191 type_name => Err(DowncastError::FailedDowncast(type_name.to_string())),
192 }
193}