hl7_parser/component.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
use crate::SubComponent;
use std::{
num::NonZeroUsize,
ops::{Index, Range},
};
/// Represents an HL7v2 sub-component
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Component {
/// The range (in char indices) in the original message where the component is located
pub range: Range<usize>,
/// The sub-components found within the component
pub sub_components: Vec<SubComponent>,
}
impl Component {
/// Access a sub-component via the 1-based HL7 sub-component index
///
/// # Returns
///
/// A reference to the sub-component
#[inline]
pub fn sub_component(&self, sub_component: NonZeroUsize) -> Option<&SubComponent> {
self.sub_components.get(sub_component.get() - 1)
}
/// Mutably access a sub-component via the 1-based HL7 sub-component index
///
/// # Returns
///
/// A mutable reference to the sub-component
#[inline]
pub fn sub_component_mut(&mut self, sub_component: NonZeroUsize) -> Option<&mut SubComponent> {
self.sub_components.get_mut(sub_component.get() - 1)
}
/// Given the source for the original message, extract the (raw) string for this component
///
/// # Arguments
///
/// * `message_source` - A string slice representing the original message source that was parsed
///
/// # Examples
///
/// ```
/// # use std::num::NonZeroUsize;
/// # use hl7_parser::ParsedMessage;
/// let message = include_str!("../test_assets/sample_oru_r01_generic.hl7");
/// let message = ParsedMessage::parse(&message, true).expect("can parse message");
///
/// let segment = message.segment("PID").expect("can get PID segment");
/// let field = segment.field(NonZeroUsize::new(3).unwrap()).expect("can get field 3");
/// let repeat = field.repeat(NonZeroUsize::new(1).unwrap()).expect("can get repeat 1");
/// let component = repeat.component(NonZeroUsize::new(4).unwrap()).expect("can get component 4");
///
/// assert_eq!(component.source(message.source), "MIE&1.2.840.114398.1.100&ISO");
/// ```
#[inline]
pub fn source<'s>(&self, message_source: &'s str) -> &'s str {
&message_source[self.range.clone()]
}
/// Locate a sub-component at the cursor position
///
/// # Arguments
///
/// * `cursor` - The cursor location (0-based character index of the original message)
///
/// # Returns
///
/// A tuple containing the HL7 sub-component index (1-based) and a reference to the sub-component.
/// If the component doesn't contain the cursor, returns `None`
pub fn sub_component_at_cursor(&self, cursor: usize) -> Option<(NonZeroUsize, &SubComponent)> {
if !self.range.contains(&cursor) {
return None;
}
self.sub_components
.iter()
.enumerate()
.find(|(_, sub_component)| {
sub_component.range.contains(&cursor) || sub_component.range.start == cursor
})
.map(|(i, sc)| (NonZeroUsize::new(i + 1).unwrap(), sc))
}
}
impl<I: Into<usize>> Index<I> for &Component {
type Output = SubComponent;
fn index(&self, index: I) -> &Self::Output {
&self.sub_components[index.into()]
}
}
/// A trait for accessing sub-components on fields, to extend Option<&Component> with short-circuit access
pub trait SubComponentAccessor {
/// Access the sub-component given by 1-based indexing
fn sub_component(&self, sub_component: NonZeroUsize) -> Option<&SubComponent>;
}
impl SubComponentAccessor for Option<&Component> {
#[inline]
fn sub_component(&self, sub_component: NonZeroUsize) -> Option<&SubComponent> {
match self {
None => None,
Some(component) => component.sub_component(sub_component),
}
}
}
/// A trait for accessing sub-components on fields, to extend Option<&mut Component> with short-circuit access
pub trait SubComponentAccessorMut {
/// Access the sub-component given by 1-based indexing
fn sub_component_mut(&mut self, sub_component: NonZeroUsize) -> Option<&mut SubComponent>;
}
impl SubComponentAccessorMut for Option<&mut Component> {
#[inline]
fn sub_component_mut(&mut self, sub_component: NonZeroUsize) -> Option<&mut SubComponent> {
match self {
None => None,
Some(component) => component.sub_component_mut(sub_component),
}
}
}