1use std::collections::BTreeMap;
9use std::sync::Arc;
10
11pub trait Definitions {
13 fn structure(&self, url: &str) -> Option<Arc<Structure>>;
17
18 fn covers(&self, url: &str) -> bool {
22 let _ = url;
23 false
24 }
25}
26
27#[derive(Debug, Default, Clone, Copy)]
29pub struct NoDefinitions;
30
31impl Definitions for NoDefinitions {
32 fn structure(&self, _url: &str) -> Option<Arc<Structure>> {
33 None
34 }
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38pub enum Kind {
39 PrimitiveType,
40 ComplexType,
41 Resource,
42 Logical,
43}
44
45#[derive(Debug, Clone, PartialEq)]
47pub struct Structure {
48 pub url: String,
49 pub name: String,
50 pub type_name: String,
52 pub kind: Kind,
53 pub is_abstract: bool,
54 pub base: Option<String>,
56 pub elements: BTreeMap<String, Element>,
58}
59
60#[derive(Debug, Clone, Default, PartialEq)]
62pub struct Element {
63 pub types: Vec<String>,
65 pub choices: Vec<String>,
67 pub array: bool,
69 pub children: Arc<BTreeMap<String, Element>>,
71 pub content_reference: Option<(String, Vec<String>)>,
73 pub choice_of: Option<String>,
75 pub index: Option<usize>,
77}
78
79impl Element {
80 pub fn is_choice(&self) -> bool {
81 !self.choices.is_empty() || self.types.len() > 1
82 }
83}
84
85pub fn type_url(code: &str, context_url: &str) -> String {
90 if code.contains("://") || code.starts_with("urn:") {
91 return code.to_owned();
92 }
93 match versioned_core(context_url) {
94 Some(prefix) => format!("{prefix}/StructureDefinition/{code}"),
95 None => format!("http://hl7.org/fhir/StructureDefinition/{code}"),
96 }
97}
98
99pub fn versioned_core(url: &str) -> Option<&str> {
101 let url = url.split('|').next().unwrap_or(url);
102 let version = url
103 .strip_prefix("http://hl7.org/fhir/")?
104 .split_once("/StructureDefinition/")?
105 .0;
106 let is_version = !version.is_empty() && version.chars().all(|c| c.is_ascii_digit() || c == '.');
107 is_version.then(|| &url[.."http://hl7.org/fhir/".len() + version.len()])
108}
109
110pub fn same_primitive(a: &str, b: &str) -> bool {
112 let system = |code: &str| -> String {
113 match code {
114 "String" | "string" | "code" | "id" | "markdown" | "uri" | "url" | "canonical"
115 | "oid" | "uuid" | "base64Binary" | "xhtml" => "String".into(),
116 "Integer" | "integer" | "positiveInt" | "unsignedInt" => "Integer".into(),
117 "Integer64" | "integer64" => "Long".into(),
118 "Decimal" | "decimal" => "Decimal".into(),
119 "Boolean" | "boolean" => "Boolean".into(),
120 "Date" | "date" => "Date".into(),
121 "DateTime" | "dateTime" | "instant" => "DateTime".into(),
122 "Time" | "time" => "Time".into(),
123 other => other.into(),
124 }
125 };
126 system(a) == system(b)
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 #[test]
134 fn type_codes_resolve_in_the_release_of_the_structure() {
135 let core = "http://hl7.org/fhir/StructureDefinition/HumanName";
136 assert_eq!(
137 type_url(
138 "HumanName",
139 "http://hl7.org/fhir/StructureDefinition/Patient"
140 ),
141 core
142 );
143 assert_eq!(
144 type_url(
145 "HumanName",
146 "http://hl7.org/fhir/4.0/StructureDefinition/Patient|4.0.1"
147 ),
148 "http://hl7.org/fhir/4.0/StructureDefinition/HumanName"
149 );
150 assert_eq!(
152 type_url(
153 "HumanName",
154 "http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
155 ),
156 core
157 );
158 assert_eq!(
159 type_url("HumanName", "http://example.org/StructureDefinition/P"),
160 core
161 );
162 assert_eq!(
163 type_url("http://example.org/T", core),
164 "http://example.org/T"
165 );
166 }
167}