use edifact_rs::{MessageWindows, OwnedSegment, ReaderConfig};
use crate::{error::Error, message::DvgwMessage, report::DvgwReport, validate};
#[derive(Debug, Clone)]
pub struct DvgwPlatform {
config: ReaderConfig,
}
impl Default for DvgwPlatform {
fn default() -> Self {
Self::new()
}
}
impl DvgwPlatform {
#[must_use]
pub fn new() -> Self {
Self {
config: ReaderConfig::default(),
}
}
#[must_use]
pub fn with_config(config: ReaderConfig) -> Self {
Self { config }
}
pub fn parse(&self, input: &[u8]) -> Result<DvgwMessage, Error> {
#[cfg(feature = "tracing")]
let _span = tracing::debug_span!("dvgw_parse", input_len = input.len()).entered();
self.parse_interchange(input)
.next()
.unwrap_or(Err(Error::MissingSegment("UNH")))
}
pub fn parse_interchange(
&self,
input: &[u8],
) -> impl Iterator<Item = Result<DvgwMessage, Error>> + use<> {
let tokenized: Result<Vec<OwnedSegment>, Error> =
edifact_rs::from_reader_with_config(input, self.config)
.collect::<Result<_, _>>()
.map_err(Error::Parse);
let (segments, fatal) = match tokenized {
Ok(segments) => (Some(segments), None),
Err(e) => (None, Some(e)),
};
fatal.map(Err).into_iter().chain(
segments
.into_iter()
.flat_map(|segments| {
MessageWindows::new(segments.into_iter().map(Ok::<_, edifact_rs::EdifactError>))
})
.map(|window| {
let window = window.map_err(Error::Parse)?;
DvgwMessage::from_segments(window.segments)
}),
)
}
pub fn validate(&self, input: &[u8]) -> Result<DvgwReport, Error> {
#[cfg(feature = "tracing")]
let _span = tracing::debug_span!("dvgw_validate", input_len = input.len()).entered();
let message = self.parse(input)?;
Ok(Self::validate_message(&message))
}
#[must_use]
pub fn validate_message(message: &DvgwMessage) -> DvgwReport {
DvgwReport::new(
message.message_type,
message.document,
message.message_ref.clone(),
validate::check(message),
)
}
}
#[must_use]
pub fn sniff(input: &[u8]) -> Option<crate::document::DvgwDocument> {
let segments: Vec<OwnedSegment> =
edifact_rs::from_reader_with_config(input, ReaderConfig::default())
.take_while(Result::is_ok)
.map_while(Result::ok)
.take(8)
.collect();
segments
.iter()
.find(|s| s.tag == "BGM")
.and_then(|bgm| bgm.component_str(0, 0))
.and_then(crate::document::DvgwDocument::from_code)
}