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 fn templates(&self, url: &str) -> Vec<TemplateId> {
30 let _ = url;
31 Vec::new()
32 }
33}
34
35#[derive(Debug, Clone, PartialEq, Eq, Hash)]
38pub struct TemplateId {
39 pub root: String,
40 pub extension: Option<String>,
41}
42
43impl TemplateId {
44 pub fn parse(identifier: &str) -> Option<TemplateId> {
46 if let Some(rest) = identifier.strip_prefix("urn:hl7ii:") {
47 let (root, extension) = match rest.split_once(':') {
48 Some((root, extension)) => (root, Some(extension.to_owned())),
49 None => (rest, None),
50 };
51 return (!root.is_empty()).then(|| TemplateId {
52 root: root.to_owned(),
53 extension,
54 });
55 }
56 let root = identifier.strip_prefix("urn:oid:")?;
57 (!root.is_empty()).then(|| TemplateId {
58 root: root.to_owned(),
59 extension: None,
60 })
61 }
62
63 pub fn matches(&self, root: &str, extension: Option<&str>) -> bool {
66 self.root == root
67 && match &self.extension {
68 Some(wanted) => extension == Some(wanted.as_str()),
69 None => true,
70 }
71 }
72}
73
74#[derive(Debug, Default, Clone, Copy)]
76pub struct NoDefinitions;
77
78impl Definitions for NoDefinitions {
79 fn structure(&self, _url: &str) -> Option<Arc<Structure>> {
80 None
81 }
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
85pub enum Kind {
86 PrimitiveType,
87 ComplexType,
88 Resource,
89 Logical,
90}
91
92#[derive(Debug, Clone, PartialEq)]
94pub struct Structure {
95 pub url: String,
96 pub name: String,
97 pub type_name: String,
99 pub kind: Kind,
100 pub is_abstract: bool,
101 pub base: Option<String>,
103 pub elements: BTreeMap<String, Element>,
105}
106
107#[derive(Debug, Clone, Default, PartialEq)]
109pub struct Element {
110 pub types: Vec<String>,
112 pub choices: Vec<String>,
114 pub array: bool,
116 pub children: Arc<BTreeMap<String, Element>>,
118 pub content_reference: Option<(String, Vec<String>)>,
120 pub choice_of: Option<String>,
122 pub index: Option<usize>,
124}
125
126impl Element {
127 pub fn is_choice(&self) -> bool {
128 !self.choices.is_empty() || self.types.len() > 1
129 }
130
131 pub fn is_polymorphic(&self) -> bool {
134 self.choices.is_empty() && self.types.len() > 1
135 }
136}
137
138pub fn type_url(code: &str, context_url: &str) -> String {
143 if code.contains("://") || code.starts_with("urn:") {
144 return code.to_owned();
145 }
146 match versioned_core(context_url) {
147 Some(prefix) => format!("{prefix}/StructureDefinition/{code}"),
148 None => format!("http://hl7.org/fhir/StructureDefinition/{code}"),
149 }
150}
151
152pub fn versioned_core(url: &str) -> Option<&str> {
154 let url = url.split('|').next().unwrap_or(url);
155 let version = url
156 .strip_prefix("http://hl7.org/fhir/")?
157 .split_once("/StructureDefinition/")?
158 .0;
159 let is_version = !version.is_empty() && version.chars().all(|c| c.is_ascii_digit() || c == '.');
160 is_version.then(|| &url[.."http://hl7.org/fhir/".len() + version.len()])
161}
162
163pub fn same_primitive(a: &str, b: &str) -> bool {
165 let system = |code: &str| -> String {
166 match code {
167 "String" | "string" | "code" | "id" | "markdown" | "uri" | "url" | "canonical"
168 | "oid" | "uuid" | "base64Binary" | "xhtml" => "String".into(),
169 "Integer" | "integer" | "positiveInt" | "unsignedInt" => "Integer".into(),
170 "Integer64" | "integer64" => "Long".into(),
171 "Decimal" | "decimal" => "Decimal".into(),
172 "Boolean" | "boolean" => "Boolean".into(),
173 "Date" | "date" => "Date".into(),
174 "DateTime" | "dateTime" | "instant" => "DateTime".into(),
175 "Time" | "time" => "Time".into(),
176 other => other.into(),
177 }
178 };
179 system(a) == system(b)
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185
186 #[test]
187 fn type_codes_resolve_in_the_release_of_the_structure() {
188 let core = "http://hl7.org/fhir/StructureDefinition/HumanName";
189 assert_eq!(
190 type_url(
191 "HumanName",
192 "http://hl7.org/fhir/StructureDefinition/Patient"
193 ),
194 core
195 );
196 assert_eq!(
197 type_url(
198 "HumanName",
199 "http://hl7.org/fhir/4.0/StructureDefinition/Patient|4.0.1"
200 ),
201 "http://hl7.org/fhir/4.0/StructureDefinition/HumanName"
202 );
203 assert_eq!(
205 type_url(
206 "HumanName",
207 "http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
208 ),
209 core
210 );
211 assert_eq!(
212 type_url("HumanName", "http://example.org/StructureDefinition/P"),
213 core
214 );
215 assert_eq!(
216 type_url("http://example.org/T", core),
217 "http://example.org/T"
218 );
219 }
220}