1use haste_fhir_model::r4::generated::{
2 terminology::IssueType,
3 types::{
4 FHIRBase64Binary, FHIRBoolean, FHIRCanonical, FHIRCode, FHIRDate, FHIRDateTime,
5 FHIRDecimal, FHIRId, FHIRInstant, FHIRInteger, FHIRMarkdown, FHIROid, FHIRPositiveInt,
6 FHIRString, FHIRTime, FHIRUnsignedInt, FHIRUri, FHIRUrl, FHIRUuid,
7 },
8};
9use haste_fhir_operation_error::OperationOutcomeError;
10use haste_reflect::MetaValue;
11
12fn downcast_meta_value<T: 'static>(value: &dyn MetaValue) -> Option<&T> {
13 value.as_any().downcast_ref::<T>()
14}
15
16pub fn stringify_meta_value(value: &dyn MetaValue) -> Result<String, OperationOutcomeError> {
25 match value.fhir_type() {
26 "http://hl7.org/fhirpath/System.String" => downcast_meta_value::<String>(value)
27 .cloned()
28 .ok_or_else(|| {
29 OperationOutcomeError::fatal(
30 IssueType::invalid(),
31 "http://hl7.org/fhirpath/System.String value is missing.".to_string(),
32 )
33 }),
34 "base64Binary" => {
35 stringify_with::<FHIRBase64Binary, _>(value, "base64Binary", |v| v.value.clone())
36 }
37 "decimal" => {
38 stringify_with::<FHIRDecimal, _>(value, "decimal", |v| v.value.map(|x| x.to_string()))
39 }
40 "boolean" => {
41 stringify_with::<FHIRBoolean, _>(value, "boolean", |v| v.value.map(|x| x.to_string()))
42 }
43 "url" => stringify_with::<FHIRUrl, _>(value, "url", |v| v.value.clone()),
44 "code" => stringify_with::<FHIRCode, _>(value, "code", |v| v.value.clone()),
45 "string" => stringify_with::<FHIRString, _>(value, "string", |v| v.value.clone()),
46 "integer" => {
47 stringify_with::<FHIRInteger, _>(value, "integer", |v| v.value.map(|x| x.to_string()))
48 }
49 "uri" => stringify_with::<FHIRUri, _>(value, "uri", |v| v.value.clone()),
50 "canonical" => stringify_with::<FHIRCanonical, _>(value, "canonical", |v| v.value.clone()),
51 "markdown" => stringify_with::<FHIRMarkdown, _>(value, "markdown", |v| v.value.clone()),
52 "id" => stringify_with::<FHIRId, _>(value, "id", |v| v.value.clone()),
53 "oid" => stringify_with::<FHIROid, _>(value, "oid", |v| v.value.clone()),
54 "uuid" => stringify_with::<FHIRUuid, _>(value, "uuid", |v| v.value.clone()),
55 "unsignedInt" => stringify_with::<FHIRUnsignedInt, _>(value, "unsignedInt", |v| {
56 v.value.map(|x| x.to_string())
57 }),
58 "positiveInt" => stringify_with::<FHIRPositiveInt, _>(value, "positiveInt", |v| {
59 v.value.map(|x| x.to_string())
60 }),
61 "instant" => stringify_with::<FHIRInstant, _>(value, "instant", |v| {
62 v.value.as_ref().map(ToString::to_string)
63 }),
64 "date" => stringify_with::<FHIRDate, _>(value, "date", |v| {
65 v.value.as_ref().map(ToString::to_string)
66 }),
67 "time" => stringify_with::<FHIRTime, _>(value, "time", |v| {
68 v.value.as_ref().map(ToString::to_string)
69 }),
70 "dateTime" => stringify_with::<FHIRDateTime, _>(value, "dateTime", |v| {
71 v.value.as_ref().map(ToString::to_string)
72 }),
73 typename => Err(OperationOutcomeError::fatal(
74 IssueType::invalid(),
75 format!("Unsupported MetaValue type for stringification: '{typename}'"),
76 )),
77 }
78}
79
80fn stringify_with<T, F>(
81 value: &dyn MetaValue,
82 type_name: &str,
83 extractor: F,
84) -> Result<String, OperationOutcomeError>
85where
86 T: MetaValue + 'static,
87 F: FnOnce(&T) -> Option<String>,
88{
89 downcast_meta_value::<T>(value)
90 .and_then(extractor)
91 .ok_or_else(|| {
92 OperationOutcomeError::fatal(
93 IssueType::invalid(),
94 format!("{type_name} value is missing."),
95 )
96 })
97}