fhirbolt_element/
lib.rs

1//! Generic element model.
2//!
3//! As deserialization differs slightly between FHIR releases,
4//! `Element` is generic over a FHIR release.
5//!
6//! # Example
7//! ```
8//! use fhirbolt::FhirReleases;
9//! use fhirbolt::element::{Element, Value, Primitive};
10//!
11//! let mut element = Element::<{ FhirReleases:: R4B }>::new();
12//! element.insert(
13//!     "resourceType".to_string(),
14//!     Value::Primitive(
15//!         Primitive::String("Observation".to_string())
16//!     )
17//! );
18//! // ...
19//! ```
20use std::{
21    fmt,
22    ops::{Deref, DerefMut},
23};
24
25pub use fhirbolt_shared::{FhirRelease, FhirReleases};
26
27/// Macro for creating [`Element`].
28///
29/// # Examples
30///
31/// ```rust
32/// use fhirbolt::FhirReleases;
33/// use fhirbolt::element::{Element, Value, Primitive};
34///
35/// let element: Element<{ FhirReleases::R4 }> = Element! {
36///     "value" => Value::Primitive(Primitive::String("123".into())),
37/// };
38/// ```
39#[macro_export]
40macro_rules! Element {
41    {$($k: expr => $v: expr),* $(,)?} => {
42        fhirbolt_element::Element::from([$(($k, $v),)*])
43    };
44}
45
46/// Generic element in a FHIR resource.
47///
48/// As deserialization differs slightly between FHIR releases,
49/// `Element` is generic over a FHIR release.
50///
51/// It is recommended to use the `Element!` macro for creating
52/// new element.
53///
54/// # Example
55/// ## With macro
56/// ```rust
57/// use fhirbolt::FhirReleases;
58/// use fhirbolt::element::{Element, Value, Primitive};
59///
60/// let element: Element<{ FhirReleases::R4 }> = Element! {
61///     "value" => Value::Primitive(Primitive::String("123".into())),
62/// };
63/// ```
64///
65/// ## Without macro
66/// ```rust
67/// use fhirbolt::FhirReleases;
68/// use fhirbolt::element::{Element, Value, Primitive};
69///
70/// let mut element = Element::<{ FhirReleases:: R4B }>::new();
71/// element.insert(
72///     "value".to_string(),
73///     Value::Primitive(
74///         Primitive::String("123".to_string())
75///     )
76/// );
77/// // ...
78/// ```
79#[derive(Default, Clone, PartialEq)]
80pub struct Element<const R: FhirRelease> {
81    map: indexmap::IndexMap<String, Value<R>>,
82}
83
84impl<const R: FhirRelease> Element<R> {
85    /// Create a new element.
86    #[inline]
87    pub fn new() -> Self {
88        Self {
89            map: indexmap::IndexMap::new(),
90        }
91    }
92
93    /// Create a new element wit preallocated capacity.
94    #[inline]
95    pub fn with_capacity(n: usize) -> Self {
96        Self {
97            map: indexmap::IndexMap::with_capacity(n),
98        }
99    }
100}
101
102impl<const R: FhirRelease> Deref for Element<R> {
103    type Target = indexmap::IndexMap<String, Value<R>>;
104
105    #[inline]
106    fn deref(&self) -> &Self::Target {
107        &self.map
108    }
109}
110
111impl<const R: FhirRelease> DerefMut for Element<R> {
112    #[inline]
113    fn deref_mut(&mut self) -> &mut Self::Target {
114        &mut self.map
115    }
116}
117
118impl<const R: FhirRelease, const N: usize> From<[(String, Value<R>); N]> for Element<R> {
119    fn from(arr: [(String, Value<R>); N]) -> Self {
120        Element {
121            map: indexmap::IndexMap::from(arr),
122        }
123    }
124}
125
126impl<const R: FhirRelease, const N: usize> From<[(&str, Value<R>); N]> for Element<R> {
127    fn from(arr: [(&str, Value<R>); N]) -> Self {
128        Element::from_iter(arr.map(|(k, v)| (k.into(), v)))
129    }
130}
131
132impl<const R: FhirRelease> FromIterator<(String, Value<R>)> for Element<R> {
133    #[inline]
134    fn from_iter<I: IntoIterator<Item = (String, Value<R>)>>(iter: I) -> Self {
135        Element {
136            map: indexmap::IndexMap::from_iter(iter),
137        }
138    }
139}
140
141impl<'a, const R: FhirRelease> IntoIterator for &'a Element<R> {
142    type Item = (&'a String, &'a Value<R>);
143    type IntoIter = indexmap::map::Iter<'a, String, Value<R>>;
144
145    #[inline]
146    fn into_iter(self) -> Self::IntoIter {
147        self.iter()
148    }
149}
150
151impl<'a, const R: FhirRelease> IntoIterator for &'a mut Element<R> {
152    type Item = (&'a String, &'a mut Value<R>);
153    type IntoIter = indexmap::map::IterMut<'a, String, Value<R>>;
154
155    #[inline]
156    fn into_iter(self) -> Self::IntoIter {
157        self.iter_mut()
158    }
159}
160
161impl<const R: FhirRelease> IntoIterator for Element<R> {
162    type Item = (String, Value<R>);
163    type IntoIter = indexmap::map::IntoIter<String, Value<R>>;
164
165    #[inline]
166    fn into_iter(self) -> Self::IntoIter {
167        indexmap::IndexMap::into_iter(self.map)
168    }
169}
170
171impl<const R: FhirRelease> fmt::Debug for Element<R> {
172    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
173        let mut s = f.debug_struct(&format!("Element<{}>", R));
174
175        for (key, value) in self {
176            s.field(key, value);
177        }
178
179        s.finish()
180    }
181}
182
183/// Generic value in a FHIR resource.
184#[derive(Clone, PartialEq)]
185pub enum Value<const R: FhirRelease> {
186    Element(Element<R>),
187    Sequence(Vec<Element<R>>),
188    Primitive(Primitive),
189}
190
191impl<const R: FhirRelease> fmt::Debug for Value<R> {
192    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
193        match self {
194            Value::Element(e) => e.fmt(f),
195            Value::Sequence(s) => s.fmt(f),
196            Value::Primitive(p) => write!(f, "{:?}", p),
197        }
198    }
199}
200
201/// Primitive value in a FHIR resource.
202#[derive(Clone, Debug, PartialEq)]
203pub enum Primitive {
204    Bool(bool),
205    Integer(i32),
206    Integer64(i64),
207    Decimal(String),
208    String(String),
209}