use crate::encoding::HL7Encoding;
use crate::error::Hl7Error;
use crate::field::Field;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Segment {
raw: String,
pub name: String,
pub fields: Vec<Field>,
pub(crate) sequence_no: usize,
}
impl Segment {
pub fn new(name: impl Into<String>) -> Self {
Self {
raw: String::new(),
name: name.into(),
fields: Vec::new(),
sequence_no: 0,
}
}
pub fn parse(raw: &str, enc: &HL7Encoding) -> Result<Self, Hl7Error> {
if raw.chars().count() < 3 {
return Err(Hl7Error::with_code(
format!("Invalid segment (too short): {raw}"),
Hl7Error::BAD_MESSAGE,
));
}
let name: String = raw.chars().take(3).collect();
let is_msh = name == "MSH";
let parts: Vec<&str> = raw.split(enc.field_delimiter).collect();
let mut fields = Vec::with_capacity(parts.len());
for (i, part) in parts.iter().enumerate().skip(1) {
let field = if is_msh && i == 1 {
Field::new_delimiters(part)
} else {
Field::parse(part, enc)
};
fields.push(field);
}
if is_msh {
fields.insert(0, Field::new_delimiters(&enc.field_delimiter.to_string()));
}
Ok(Self { raw: raw.to_string(), name, fields, sequence_no: 0 })
}
pub fn deep_copy(&self) -> Segment {
self.clone()
}
pub fn raw(&self, enc: &HL7Encoding) -> Option<&str> {
if self.raw == enc.present_but_null {
None
} else {
Some(&self.raw)
}
}
pub fn value(&self, enc: &HL7Encoding) -> Option<String> {
if self.raw == enc.present_but_null {
None
} else {
Some(enc.decode(&self.raw))
}
}
pub fn sequence_no(&self) -> usize {
self.sequence_no
}
pub fn add_empty_field(&mut self, enc: &HL7Encoding) {
self.add_new_field(Field::parse("", enc));
}
pub fn add_new_field_value(&mut self, content: &str, enc: &HL7Encoding) {
self.add_new_field(Field::parse(content, enc));
}
pub fn add_new_field(&mut self, field: Field) {
self.fields.push(field);
}
pub fn add_new_field_at(&mut self, field: Field, position: usize, enc: &HL7Encoding) {
let index = position.saturating_sub(1);
if index < self.fields.len() {
self.fields[index] = field;
} else {
while self.fields.len() < index {
self.fields.push(Field::parse("", enc));
}
self.fields.push(field);
}
}
pub fn field(&self, position: usize) -> Result<&Field, Hl7Error> {
position
.checked_sub(1)
.and_then(|i| self.fields.get(i))
.ok_or_else(|| Hl7Error::new("Field not available"))
}
pub fn serialize(&self, out: &mut String, enc: &HL7Encoding) {
out.push_str(&self.name);
if !self.fields.is_empty() {
out.push(enc.field_delimiter);
}
let start = if self.name == "MSH" { 1 } else { 0 };
for i in start..self.fields.len() {
if i > start {
out.push(enc.field_delimiter);
}
self.fields[i].serialize(out, enc);
}
out.push_str(&enc.segment_delimiter);
}
}