Skip to main content

Crate edifact_rs

Crate edifact_rs 

Source
Expand description

edifact-rs — zero-copy EDIFACT (ISO 9735) tokenizer, parser, writer, typed (de)serialization, validation engine, and extensible directory support.

§Quick start

use edifact_rs::from_bytes;
let input = b"UNB+UNOA:1+SENDER+RECEIVER+200101:0900+1'UNZ+0+1'";
let segments: Vec<_> = from_bytes(input).collect::<Result<_, _>>().unwrap();
assert_eq!(segments[0].tag, "UNB");

§One segment type, borrowed or owned

Segment<'a> holds its text as Cow<'a, str>, which is what lets a single type cover both parsing modes:

  • from_bytes borrows straight out of the input — no allocation for segment data — and yields Segment<'input>.
  • from_reader has no buffer to borrow from and yields Segment<'static>, aliased as OwnedSegment.

Segment is covariant in 'a, so &[OwnedSegment] is accepted anywhere &[Segment<'_>] is wanted. Every API in this crate therefore takes one shape and serves both paths — there are no _owned twins, and no conversion step.

use edifact_rs::{OwnedSegment, Segment};

fn count_bgm(segments: &[Segment<'_>]) -> usize {
    segments.iter().filter(|s| s.tag == "BGM").count()
}

let borrowed: Vec<Segment<'_>> =
    edifact_rs::from_bytes(b"BGM+220'").collect::<Result<_, _>>()?;
let owned: Vec<OwnedSegment> =
    edifact_rs::from_reader(std::io::Cursor::new(b"BGM+220'")).collect::<Result<_, _>>()?;

assert_eq!(count_bgm(&borrowed), 1);
assert_eq!(count_bgm(&owned), 1);

§Crate features

Features are additive and independent: each changes only which trait impls and re-exports exist, never parsing or validation behaviour.

§Parse and text contracts

Parsing in edifact-rs is strict and deterministic:

  • A byte order mark and any whitespace before the first service segment are skipped — ISO 9735 authorises neither, but both arrive constantly.
  • A segment that ends without its terminator is a truncation (E010): accepting it would let a file cut off mid-transfer parse as complete.
  • Segment and element text must decode as UTF-8 (E003).
  • A release character must escape exactly one following byte; a trailing ? at end-of-input is rejected (E019).
  • Every ReaderConfig budget reports a violation (E020, E036) rather than ending the iterator, which would be indistinguishable from a clean end of input.
  • The service characters are discovered the way ISO 9735-1 says a receiver should discover them: from a leading UNA if there is one, otherwise the §5.1 defaults with the repetition separator resolved from the syntax version in UNB S001 DE 0002 — active as * for version 4, inactive for versions 1–3, where * is ordinary data. Override both with ReaderConfig::with_service_string_advice when parsing a fragment that carries neither header.
  • When the repetition separator is active, repeating data elements are split into Element::repetitions rather than left glued into the value (ISO 9735-1 §8.6).

Every one of these contracts applies identically to slice-based parsing (from_bytes) and reader-based parsing (from_reader); the two are held to byte-for-byte agreement by a test that runs the same inputs through both.

use edifact_rs::from_reader;
use std::io::Cursor;

let input = b"UNA:;.? 'BGM;220;test?;value'";
let segments: Vec<_> = from_reader(Cursor::new(&input[..]))
    .collect::<Result<Vec<_>, _>>()
    .unwrap();
assert_eq!(segments.len(), 1);
assert_eq!(segments[0].tag, "BGM");
assert_eq!(segments[0].element_str(0), Some("220"));
assert_eq!(segments[0].element_str(1), Some("test;value"));

§Validation

ValidationContext runs four layers — envelope, structure, code-list and profile — into one ValidationReport:

use edifact_rs::{ProfileRulePack, ValidationContext, ValidationIssue, ValidationSeverity, from_bytes};

let pack = ProfileRulePack::new("ORDERS-DEMO")
    .for_message_type("ORDERS")
    .with_rule_fn(|segments, issues| {
        if !segments.iter().any(|s| s.tag == "BGM") {
            issues.push(
                ValidationIssue::new(ValidationSeverity::Error, "ORDERS requires a BGM")
                    .with_rule_id("DEMO-P001"),
            );
        }
    });

let segments: Vec<_> = from_bytes(b"UNH+1+ORDERS:D:96A:UN'DTM+137:1:102'UNT+3+1'")
    .collect::<Result<_, _>>()?;
let report = ValidationContext::builder().with_profile_pack(pack).build().validate(&segments);

assert_eq!(report.filter_by_rule_prefix("DEMO-").total_issues(), 1);

See the validation and profile pack guides for the layers, group-scoped rules, and directory validation.

§Async usage

There is deliberately no native async API: parsing is CPU work over a buffer, not I/O, so an async parser would add a runtime dependency and a second copy of every code path to wrap work that never awaits. Read with your runtime, parse synchronously — see the async integration guide for the three patterns, including spawn_blocking for multi-gigabyte files.

let mut buf = Vec::new();
reader.read_to_end(&mut buf).await?;
let segments: Vec<_> = edifact_rs::from_bytes(&buf).collect::<Result<Vec<_>, _>>()?;

Re-exports§

pub use charset::Charset;
pub use charset::DecodingReader;
pub use charset::decode_interchange;
pub use charset::decode_reader;
pub use charset::sniff_charset;
pub use contrl::Action;
pub use contrl::Contrl;
pub use contrl::ReportingLevel;
pub use contrl::SyntaxError;
pub use group::Descendants;
pub use group::GroupDef;
pub use group::SegmentGroupIndexed;
pub use group::group_segments_indexed;
pub use report::severity_for_error;
pub use report::ValidationIssue;
pub use report::ValidationReport;
pub use report::ValidationSeverity;
pub use de::CompositeElement;
pub use de::EdifactCompositeDeserialize;
pub use de::EdifactDeserialize;
pub use de::EdifactSegmentTag;
pub use de::MessageWindow;
pub use de::MessageWindows;
pub use de::OwnedMessageWindow;
pub use de::composite_element;
pub use de::contiguous_groups;
pub use de::deserialize;
pub use de::deserialize_each;
pub use de::deserialize_each_from_reader;
pub use de::deserialize_messages;
pub use de::deserialize_messages_from_reader;
pub use de::deserialize_str;
pub use de::find_qualified_segment;
pub use de::find_segment;
pub use de::find_segments;
pub use de::find_segments_typed;
pub use de::message_windows;
pub use de::message_windows_from_reader;
pub use de::qualifier_matches_pattern;
pub use directory_validator::ComponentRef;
pub use directory_validator::DirectoryValidator;
pub use directory_validator::DirectoryValidatorBuilder;
pub use directory_validator::ElementPath;
pub use directory_validator::ElementRef;
pub use directory_validator::LayoutAudit;
pub use directory_validator::LayoutFinding;
pub use directory_validator::LayoutSlot;
pub use directory_validator::OwnedComponentRef;
pub use directory_validator::OwnedElementRef;
pub use directory_validator::OwnedSegmentDef;
pub use directory_validator::Repr;
pub use directory_validator::ReprKind;
pub use directory_validator::SegmentDefinition;
pub use directory_validator::SegmentLayout;
pub use directory_validator::Status;
pub use directory_validator::audit_directory;
pub use ser::DecimalFloat;
pub use ser::EdifactCompositeSerialize;
pub use ser::EdifactSerialize;
pub use ser::emit_sparse_segment;
pub use ser::to_bytes;
pub use ser::to_edifact_string;

Modules§

charset
EDIFACT character repertoires (UNB S001 DE 0001) and transcoding. EDIFACT character repertoires — the UNB S001 DE 0001 syntax identifier.
contrl
CONTRL — the ISO 9735-4 syntax and service report message. CONTRL — the syntax and service report message (ISO 9735-4).
de
Typed deserialization: EDIFACT segments to Rust values.
directory_validator
Shared UN/EDIFACT directory validation engine used by D.11A, D.01B and D.96A.
group
Segment group tree model for structured EDIFACT message navigation.
report
Validation report types: ValidationSeverity, ValidationIssue, ValidationReport.
ser
Custom serialization trait for EDIFACT.
service
ISO 9735 service-segment definitions (UNB, UNH, UNT, UNZ, UNG, UNE, UNS). Segment definitions for the ISO 9735 service segments.

Macros§

elements
Build a &[DataElement] from a mix of simple values and component lists.

Structs§

CharsetValidator
Checks that every value in the message is expressible in the interchange’s declared character repertoire (UNB S001 DE 0001).
DecodingSegmentStream
Lazy iterator returned by from_reader_decoded.
Element
A data element, which may have one or more component values.
EnvelopeValidator
Built-in validator for EDIFACT interchange envelope structure.
FromBytesIter
Iterator returned by from_bytes.
FromReaderIter
Iterator returned by from_reader.
FunctionalGroupEnvelope
Extracted data from a single UNG / UNE functional group envelope.
GroupIdentifier
Parsed identifier fields from a UNG segment.
InterchangeEnvelope
Extracted data from the UNB / UNZ interchange envelope.
IoError
Wrapper around std::io::Error that implements PartialEq by comparing std::io::ErrorKind.
LenientResult
Result of a lenient envelope validation — carries both a (possibly partial) interchange and the full list of collected errors.
MessageEnvelope
Extracted data from a single UNH / UNT message envelope.
MessageIdentifier
Parsed identifier fields from a UNH segment.
MessageWriter
RAII guard for a single EDIFACT message within an interchange.
OwnedSegmentStream
Streaming iterator over owned segments from a buffered reader.
Parser
Streaming parser over a Tokenizer.
ProfileRulePack
A profile/MIG rule pack that can be plugged into ValidationContext.
ReaderConfig
Configuration for reader-based EDIFACT parsers.
Segment
A single EDIFACT segment.
ServiceStringAdvice
EDIFACT service string advice — the six characters of the UNA (ISO 9735-1 Annex B).
Span
A half-open byte span within an EDIFACT payload.
SyntaxValidator
Checks the ISO 9735-1 rules that hold for every interchange, whatever directory or profile it claims.
Tokenizer
Zero-copy tokenizer over a byte slice.
ValidatedInterchange
Fully validated interchange structure returned by validate_envelope.
ValidationContext
Runs the four validation layers over one segment slice, collecting every issue into a single ValidationReport.
ValidationContextBuilder
Builder for ValidationContext.
ValidationRuleContext
Typed context injected into profile rule closures at validation time.
VecEmitter
Collects events into a Vec<EdifactEvent<'static>>.
Writer
Streaming EDIFACT writer.
WriterEmitter
Writes EDIFACT events directly to any Write implementation.

Enums§

DataElement
One data element of a segment being written: simple or composite.
EdifactError
All errors produced by edifact-rs.
EdifactEvent
A borrowed EDIFACT event emitted during serialization.
Insignificant
Which rule of ISO 9735-1 §9.1 a value violates.
Token
Token produced by Tokenizer.
ValidationLayer
Validation layers used by ValidationContext.

Traits§

AsDataElement
Borrow a value as a DataElement, choosing simple or composite by type.
EventEmitter
Trait for any sink that can consume EdifactEvents.
ProfileRule
A profile rule that can be added to a ProfileRulePack.
Validator
Pluggable validator for parsed EDIFACT segments.

Functions§

from_bufread
Parse an already-buffered reader into a lazy iterator of OwnedSegments.
from_bufread_with_config
from_bufread with explicit ReaderConfig limits.
from_bytes
Parse input bytes into an iterator of Segments.
from_bytes_decoded
Parse a byte slice, decoding it from the repertoire its own UNB declares.
from_bytes_decoded_with_config
from_bytes_decoded with explicit ReaderConfig limits.
from_bytes_with_config
Parse input bytes into an iterator of Segments with explicit configuration.
from_reader
Parse a reader into a lazy iterator of OwnedSegments.
from_reader_decoded
Parse a reader, decoding it from the repertoire the stream’s own UNB declares — lazily.
from_reader_decoded_with_config
from_reader_decoded with explicit ReaderConfig limits.
from_reader_with_config
Parse EDIFACT from an arbitrary reader as a streaming iterator with custom config.
parse_ung
Extract identifier fields from a UNG segment (zero allocation).
parse_unh
Extract identifier fields from a UNH segment (zero allocation).
segments_to_bytes
Serialize segments to an owned Vec<u8>.
to_writer
Serialize segments to an std::io::Write implementation.
validate_each
Helper for per-segment validators: iterates segments, calls f for each one, and converts any Err into report entries.
validate_envelope
Validate the EDIFACT interchange envelope, failing at the first violation.
validate_envelope_lenient
Validate the EDIFACT envelope and collect all errors rather than stopping at the first failure (borrowed-segment path).

Type Aliases§

Components
Components of one occurrence of a data element, each paired with its span.
OwnedElement
An Element that owns all of its text. See OwnedSegment.
OwnedSegment
A Segment that owns all of its text.

Derive Macros§

EdifactCompositeDeserializederive
Derive edifact_rs::EdifactCompositeDeserialize for a composite-element struct.
EdifactCompositeSerializederive
Derive edifact_rs::EdifactCompositeSerialize for a composite-element struct.
EdifactDeserializederive
Derive edifact_rs::EdifactDeserialize for segment or message structs.
EdifactSerializederive
Derive edifact_rs::EdifactSerialize for segment or message structs.