hl7-parser 0.3.0

Parses the structure of HL7v2 messages, but does not validate the correctness of the messages.
Documentation
use super::{ComponentBuilder, RepeatBuilder};
use crate::{
    datetime::TimeStamp,
    message::{Field, Separators},
};
use display::FieldBuilderDisplay;
use std::{collections::HashMap, fmt::Display};

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum FieldBuilder {
    Value(String),
    Repeats(Vec<RepeatBuilder>),
}

impl Default for FieldBuilder {
    fn default() -> Self {
        FieldBuilder::Value(String::new())
    }
}

impl FieldBuilder {
    pub fn with_value(value: String) -> Self {
        FieldBuilder::Value(value)
    }

    pub fn with_repeats(repeats: Vec<RepeatBuilder>) -> Self {
        FieldBuilder::Repeats(repeats)
    }

    pub fn value(&self) -> Option<&String> {
        match self {
            FieldBuilder::Value(value) => Some(value),
            _ => None,
        }
    }

    pub fn repeats(&self) -> Option<&Vec<RepeatBuilder>> {
        match self {
            FieldBuilder::Repeats(repeats) => Some(repeats),
            _ => None,
        }
    }

    pub fn value_mut(&mut self) -> Option<&mut String> {
        match self {
            FieldBuilder::Value(value) => Some(value),
            _ => None,
        }
    }

    pub fn repeats_mut(&mut self) -> Option<&mut Vec<RepeatBuilder>> {
        match self {
            FieldBuilder::Repeats(repeats) => Some(repeats),
            _ => None,
        }
    }

    pub fn into_value(self) -> Option<String> {
        match self {
            FieldBuilder::Value(value) => Some(value),
            _ => None,
        }
    }

    pub fn into_repeats(self) -> Option<Vec<RepeatBuilder>> {
        match self {
            FieldBuilder::Repeats(repeats) => Some(repeats),
            _ => None,
        }
    }

    pub fn has_repeats(&self) -> bool {
        matches!(self, FieldBuilder::Repeats(_))
    }

    pub fn is_empty(&self) -> bool {
        match self {
            FieldBuilder::Value(value) => value.is_empty(),
            FieldBuilder::Repeats(repeats) => repeats.is_empty(),
        }
    }

    pub fn set_value(&mut self, value: String) {
        *self = FieldBuilder::Value(value);
    }

    pub fn set_timestamp<T: Into<TimeStamp>>(&mut self, timestamp: T) {
        *self = FieldBuilder::Value(timestamp.into().to_string());
    }

    pub fn set_repeats(&mut self, repeats: Vec<RepeatBuilder>) {
        *self = FieldBuilder::Repeats(repeats);
    }

    pub fn set_component<C: Into<ComponentBuilder>>(&mut self, index: usize, component: C) {
        let component = component.into();
        match self {
            FieldBuilder::Repeats(repeats) => {
                if let Some(repeat) = repeats.last_mut() {
                    repeat.set_component(index, component);
                } else {
                    let mut repeat = RepeatBuilder::default();
                    repeat.set_component(index, component);
                    repeats.push(repeat);
                }
            }
            _ => {
                let mut repeat = RepeatBuilder::default();
                repeat.set_component(index, component);
                *self = FieldBuilder::Repeats(vec![repeat]);
            }
        }
    }

    pub fn with_component<C: Into<ComponentBuilder>>(mut self, index: usize, component: C) -> Self {
        self.set_component(index, component);
        self
    }

    pub fn with_component_value<S: ToString>(self, index: usize, value: S) -> Self {
        self.with_component(index, ComponentBuilder::Value(value.to_string()))
    }

    pub fn push_repeat(&mut self, repeat: RepeatBuilder) {
        match self {
            FieldBuilder::Repeats(repeats) => repeats.push(repeat),
            _ => *self = FieldBuilder::Repeats(vec![repeat]),
        }
    }

    pub fn clear(&mut self) {
        *self = FieldBuilder::Value(String::new());
    }

    pub fn repeat(&self, index: usize) -> Option<&RepeatBuilder> {
        match self {
            FieldBuilder::Repeats(repeats) => repeats.get(index),
            _ => None,
        }
    }

    pub fn repeat_mut(&mut self, index: usize) -> Option<&mut RepeatBuilder> {
        match self {
            FieldBuilder::Repeats(repeats) => repeats.get_mut(index),
            _ => None,
        }
    }

    pub fn remove_repeat(&mut self, index: usize) -> Option<RepeatBuilder> {
        match self {
            FieldBuilder::Repeats(repeats) => {
                if index < repeats.len() {
                    Some(repeats.remove(index))
                } else {
                    None
                }
            }
            _ => None,
        }
    }

    pub fn display<'a>(&'a self, separators: &'a Separators) -> FieldBuilderDisplay<'a> {
        FieldBuilderDisplay {
            field: self,
            separators,
        }
    }

    pub fn from_component_map<I: Into<usize>, C: Into<ComponentBuilder>>(
        components: HashMap<I, C>,
    ) -> Self {
        let repeat = RepeatBuilder::from_component_map(components);
        FieldBuilder::Repeats(vec![repeat])
    }

    pub fn from_repeats_map<
        I: Into<usize>,
        C: Into<ComponentBuilder>,
        V: IntoIterator<Item = HashMap<I, C>>,
    >(
        repeats: V,
    ) -> Self {
        let repeats = repeats
            .into_iter()
            .map(|components| RepeatBuilder::from_component_map(components))
            .collect();
        FieldBuilder::Repeats(repeats)
    }
}

mod display {
    use super::*;

    pub struct FieldBuilderDisplay<'a> {
        pub(super) field: &'a FieldBuilder,
        pub(super) separators: &'a Separators,
    }

    impl<'a> Display for FieldBuilderDisplay<'a> {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            match self.field {
                FieldBuilder::Value(value) => self.separators.encode(value).fmt(f),
                FieldBuilder::Repeats(repeats) => {
                    let mut first = true;
                    for repeat in repeats {
                        if first {
                            first = false;
                        } else {
                            write!(f, "{}", self.separators.repetition)?;
                        }
                        write!(f, "{}", repeat.display(self.separators))?;
                    }
                    Ok(())
                }
            }
        }
    }
}

impl<S: ToString> From<S> for FieldBuilder {
    fn from(value: S) -> Self {
        FieldBuilder::Value(value.to_string())
    }
}

impl<'m> From<&'m Field<'m>> for FieldBuilder {
    fn from(field: &'m Field) -> Self {
        if field.has_repeats()
            || (!field.repeats.is_empty()
                && (field.repeats[0].has_components()
                    || (!field.repeats[0].components.is_empty()
                        && field.repeats[0].components[0].has_subcomponents())))
        {
            FieldBuilder::Repeats(field.repeats().map(RepeatBuilder::from).collect())
        } else {
            FieldBuilder::Value(field.raw_value().to_string())
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use pretty_assertions_sorted::assert_eq;

    #[test]
    fn can_display_field_builder() {
        let separators = Separators::default();
        let field = crate::parser::parse_field("foo~bar").unwrap();
        let field = FieldBuilder::from(&field);
        let display = field.display(&separators).to_string();
        assert_eq!(display, "foo~bar");
    }
}