hl7_parser/builder/
component.rs

1use crate::{
2    datetime::TimeStamp,
3    message::{Component, Separators},
4};
5use display::ComponentBuilderDisplay;
6use std::{collections::HashMap, fmt::Display};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub enum ComponentBuilder {
11    Value(String),
12    Subcomponents(HashMap<usize, String>),
13}
14
15impl Default for ComponentBuilder {
16    fn default() -> Self {
17        ComponentBuilder::Value(String::new())
18    }
19}
20
21impl ComponentBuilder {
22    pub fn with_value(value: String) -> Self {
23        ComponentBuilder::Value(value)
24    }
25
26    pub fn with_subcomponents(subcomponents: HashMap<usize, String>) -> Self {
27        ComponentBuilder::Subcomponents(subcomponents)
28    }
29
30    pub fn value(&self) -> Option<&String> {
31        match self {
32            ComponentBuilder::Value(value) => Some(value),
33            _ => None,
34        }
35    }
36
37    pub fn subcomponents(&self) -> Option<&HashMap<usize, String>> {
38        match self {
39            ComponentBuilder::Subcomponents(subcomponents) => Some(subcomponents),
40            _ => None,
41        }
42    }
43
44    pub fn value_mut(&mut self) -> Option<&mut String> {
45        match self {
46            ComponentBuilder::Value(value) => Some(value),
47            _ => None,
48        }
49    }
50
51    pub fn subcomponents_mut(&mut self) -> Option<&mut HashMap<usize, String>> {
52        match self {
53            ComponentBuilder::Subcomponents(subcomponents) => Some(subcomponents),
54            _ => None,
55        }
56    }
57
58    pub fn has_subcomponents(&self) -> bool {
59        matches!(self, ComponentBuilder::Subcomponents(_))
60    }
61
62    pub fn into_value(self) -> Option<String> {
63        match self {
64            ComponentBuilder::Value(value) => Some(value),
65            _ => None,
66        }
67    }
68
69    pub fn into_subcomponents(self) -> Option<HashMap<usize, String>> {
70        match self {
71            ComponentBuilder::Subcomponents(subcomponents) => Some(subcomponents),
72            _ => None,
73        }
74    }
75
76    pub fn set_value<S: ToString>(&mut self, value: S) {
77        *self = ComponentBuilder::Value(value.to_string());
78    }
79
80    pub fn set_timestamp<T: Into<TimeStamp>>(&mut self, timestamp: T) {
81        *self = ComponentBuilder::Value(timestamp.into().to_string());
82    }
83
84    pub fn set_subcomponents(&mut self, subcomponents: HashMap<usize, String>) {
85        *self = ComponentBuilder::Subcomponents(subcomponents);
86    }
87
88    pub fn set_subcomponent<S: ToString>(&mut self, index: usize, value: S) {
89        debug_assert!(index > 0, "Subcomponent index must be greater than 0");
90        match self {
91            ComponentBuilder::Subcomponents(subcomponents) => {
92                subcomponents.insert(index, value.to_string());
93            }
94            _ => {
95                let mut subcomponents = HashMap::new();
96                subcomponents.insert(index, value.to_string());
97                *self = ComponentBuilder::Subcomponents(subcomponents);
98            }
99        }
100    }
101
102    pub fn with_subcomponent<S: ToString>(mut self, index: usize, value: S) -> Self {
103        self.set_subcomponent(index, value);
104        self
105    }
106
107    pub fn set_subcomponent_timestamp<T: Into<TimeStamp>>(&mut self, index: usize, timestamp: T) {
108        self.set_subcomponent(index, timestamp.into().to_string());
109    }
110
111    pub fn with_subcomponent_timestamp<T: Into<TimeStamp>>(
112        mut self,
113        index: usize,
114        timestamp: T,
115    ) -> Self {
116        self.set_subcomponent_timestamp(index, timestamp);
117        self
118    }
119
120    pub fn subcomponent(&self, index: usize) -> Option<&String> {
121        debug_assert!(index > 0, "Subcomponent index must be greater than 0");
122        match self {
123            ComponentBuilder::Subcomponents(subcomponents) => subcomponents.get(&index),
124            _ => None,
125        }
126    }
127
128    pub fn subcomponent_mut(&mut self, index: usize) -> Option<&mut String> {
129        debug_assert!(index > 0, "Subcomponent index must be greater than 0");
130        match self {
131            ComponentBuilder::Subcomponents(subcomponents) => subcomponents.get_mut(&index),
132            _ => None,
133        }
134    }
135
136    pub fn remove_subcomponent(&mut self, index: usize) -> Option<String> {
137        debug_assert!(index > 0, "Subcomponent index must be greater than 0");
138        match self {
139            ComponentBuilder::Subcomponents(subcomponents) => subcomponents.remove(&index),
140            _ => None,
141        }
142    }
143
144    pub fn clear(&mut self) {
145        *self = ComponentBuilder::Value(String::new());
146    }
147
148    pub fn is_empty(&self) -> bool {
149        match self {
150            ComponentBuilder::Value(value) => value.is_empty(),
151            ComponentBuilder::Subcomponents(subcomponents) => subcomponents.is_empty(),
152        }
153    }
154
155    pub fn display<'a>(&'a self, separators: &'a Separators) -> ComponentBuilderDisplay<'a> {
156        ComponentBuilderDisplay {
157            component: self,
158            separators,
159        }
160    }
161}
162
163mod display {
164    use super::*;
165
166    pub struct ComponentBuilderDisplay<'a> {
167        pub(super) component: &'a ComponentBuilder,
168        pub(super) separators: &'a Separators,
169    }
170
171    impl Display for ComponentBuilderDisplay<'_> {
172        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
173            match self.component {
174                ComponentBuilder::Value(value) => self.separators.encode(value).fmt(f),
175                ComponentBuilder::Subcomponents(subcomponents) => {
176                    if subcomponents.is_empty() {
177                        return Ok(());
178                    }
179                    let max_index = subcomponents.keys().max().unwrap();
180                    for i in 1..=*max_index {
181                        if let Some(value) = subcomponents.get(&i) {
182                            self.separators.encode(value).fmt(f)?;
183                        }
184                        if i < *max_index {
185                            write!(f, "{}", self.separators.subcomponent)?;
186                        }
187                    }
188                    Ok(())
189                }
190            }
191        }
192    }
193}
194
195impl<S: ToString> From<S> for ComponentBuilder {
196    fn from(value: S) -> Self {
197        ComponentBuilder::Value(value.to_string())
198    }
199}
200
201impl<'m> From<&'m Component<'m>> for ComponentBuilder {
202    fn from(component: &'m Component<'m>) -> Self {
203        if component.subcomponents.len() <= 1 {
204            ComponentBuilder::Value(component.source.to_string())
205        } else {
206            let subcomponents = component
207                .subcomponents
208                .iter()
209                .enumerate()
210                .map(|(i, subcomponent)| (i + 1, subcomponent.value.to_string()))
211                .collect();
212            ComponentBuilder::Subcomponents(subcomponents)
213        }
214    }
215}
216
217#[cfg(test)]
218mod tests {
219    use super::*;
220    use crate::message::Subcomponent;
221    use pretty_assertions_sorted::assert_eq;
222
223    #[test]
224    fn can_display_component_builder() {
225        let separators = Separators::default();
226        let component = ComponentBuilder::with_value("foo".to_string());
227        let display = component.display(&separators).to_string();
228        assert_eq!(display, "foo");
229
230        let mut subcomponents = HashMap::new();
231        subcomponents.insert(1, "bar".to_string());
232        subcomponents.insert(3, "baz".to_string());
233        let component = ComponentBuilder::with_subcomponents(subcomponents);
234        let display = component.display(&separators).to_string();
235        assert_eq!(display, "bar&&baz");
236    }
237
238    #[test]
239    fn can_convert_component_to_component_builder() {
240        let component = Component {
241            source: "foo&bar",
242            subcomponents: vec![
243                Subcomponent {
244                    value: "foo",
245                    range: 0..1, // ignore
246                },
247                Subcomponent {
248                    value: "bar",
249                    range: 0..1, // ignore
250                },
251            ],
252            range: 0..1, // ignore
253        };
254
255        let component_builder: ComponentBuilder = (&component).into();
256        assert_eq!(
257            component_builder,
258            ComponentBuilder::with_subcomponents(
259                vec![(1, "foo".to_string()), (2, "bar".to_string())]
260                    .into_iter()
261                    .collect()
262            )
263        );
264    }
265
266    #[test]
267    fn can_convert_with_singular_value() {
268        let component = crate::parser::parse_component("foo").expect("Can parse component");
269        let component_builder = ComponentBuilder::from(&component);
270        assert_eq!(
271            component_builder,
272            ComponentBuilder::with_value("foo".to_string())
273        );
274    }
275}