hl7_parser/segment.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 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
use std::{
num::NonZeroUsize,
ops::{Deref, DerefMut, Index, Range},
};
use crate::{Field, Msh};
/// Represents an HL7v2 segment
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Segment {
/// The range (in char indices) in the original message where the segment is located
pub range: Range<usize>,
/// The fields found within the component
pub fields: Vec<Field>,
}
impl Segment {
/// Access a field via the 1-based HL7 field index
///
/// # Returns
///
/// A reference to the field
#[inline]
pub fn field(&self, field: NonZeroUsize) -> Option<&Field> {
self.fields.get(field.get() - 1)
}
/// Mutably access a field via the 1-based HL7 field indexing
///
/// # Returns
///
/// A mutable reference to the field
#[inline]
pub fn field_mut(&mut self, field: NonZeroUsize) -> Option<&mut Field> {
self.fields.get_mut(field.get() - 1)
}
/// Given the source for the original message, extract the (raw) string for this segment
///
/// # 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");
///
/// assert_eq!(segment.source(message.source), "PID|1|12345|12345^^^MIE&1.2.840.114398.1.100&ISO^MR||MOUSE^MINNIE^S||19240101|F|||123 MOUSEHOLE LN^^FORT WAYNE^IN^46808|||||||||||||||||||");
/// ```
#[inline]
pub fn source<'s>(&self, message_source: &'s str) -> &'s str {
&message_source[self.range.clone()]
}
/// Locate a field at the cursor position
///
/// # Arguments
///
/// * `cursor` - The cursor location (0-based character index of the original message)
///
/// # Returns
///
/// A tuple containing the HL7 field index (1-based) and a reference to the field.
/// If the segment doesn't contain the cursor, returns `None`
pub fn field_at_cursor(&self, cursor: usize) -> Option<(NonZeroUsize, &Field)> {
if !self.range.contains(&cursor) {
return None;
}
self.fields
.iter()
.enumerate()
.find(|(_, field)| field.range.contains(&cursor) || field.range.start == cursor)
.map(|(i, sc)| (NonZeroUsize::new(i + 1).unwrap(), sc))
}
}
impl<I: Into<usize>> Index<I> for &Segment {
type Output = Field;
fn index(&self, index: I) -> &Self::Output {
&self.fields[index.into()]
}
}
/// A trait for accessing fields on segments, to extend Option<&Segment> with short-circuit access
pub trait FieldAccessor {
/// Access the field given by 1-based indexing
fn field(&self, field: NonZeroUsize) -> Option<&Field>;
}
impl FieldAccessor for Option<&Segment> {
#[inline]
fn field(&self, field: NonZeroUsize) -> Option<&Field> {
match self {
None => None,
Some(seg) => seg.field(field),
}
}
}
/// A trait for accessing fields on segments, to extend Option<&mut Segment> with short-circuit access
pub trait FieldAccessorMut {
/// Access the field given by 1-based indexing
fn field_mut(&mut self, field: NonZeroUsize) -> Option<&mut Field>;
}
impl FieldAccessorMut for Option<&mut Segment> {
#[inline]
fn field_mut(&mut self, field: NonZeroUsize) -> Option<&mut Field> {
match self {
None => None,
Some(seg) => seg.field_mut(field),
}
}
}
impl From<Msh> for Segment {
fn from(msh: Msh) -> Self {
let Msh {
range, mut fields, ..
} = msh;
fields.insert(
0,
Field {
range: 3..4,
repeats: Vec::with_capacity(0),
},
);
fields.insert(
1,
Field {
range: 4..8,
repeats: Vec::with_capacity(0),
},
);
Segment { range, fields }
}
}
/// Wrapper around segments; HL7 messages can contain multiple segments of the same type
/// (ex: ORU messages often contain multiple OBX segments)
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Segments(pub Vec<Segment>);
impl Deref for Segments {
type Target = Vec<Segment>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Segments {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Segments {
/// Locate a field at the cursor position
///
/// # Arguments
///
/// * `cursor` - The cursor location (0-based character index of the original message)
///
/// # Returns
///
/// A tuple containing the segment index number (0-based), HL7 field index (1-based),
/// and a reference to the field. If the segment(s) don't contain the cursor, returns `None`
pub fn field_at_cursor(&self, cursor: usize) -> Option<(usize, NonZeroUsize, &Field)> {
self.iter()
.enumerate()
.find_map(|(i, seg)| seg.field_at_cursor(cursor).map(|(n, f)| (i, n, f)))
}
/// Locate a segment at the cursor position
///
/// # Arguments
///
/// * `cursor` - The cursor location (0-based character index of the original message)
///
/// # Returns
///
/// A tuple containing the segment index number (0-based) and a reference to the field.
/// If the segment(s) don't contain the cursor, returns `None`
pub fn segment_at_cursor(&self, cursor: usize) -> Option<(usize, &Segment)> {
self.iter()
.enumerate()
.find(|(_, seg)| seg.range.contains(&cursor))
.map(|(i, seg)| (i, seg))
}
}
impl From<Segment> for Segments {
fn from(value: Segment) -> Self {
Segments(vec![value])
}
}
impl From<Vec<Segment>> for Segments {
fn from(value: Vec<Segment>) -> Self {
Segments(value)
}
}