ISO 9735 · Rust
EDIFACT for Rust that refuses to guess.
Zero-copy parsing, streaming deserialization, typed derive macros, and composable validation — built so that malformed input produces an error, never a plausible-looking wrong value.
cargo add edifact-rs
Parse, address, validate
Borrow straight from the bytes
use edifact_rs::from_bytes;
let input = b"UNA:+.? 'BGM+220+PO-4711+9'";
let segments: Vec<_> = from_bytes(input).collect::<Result<_, _>>()?;
assert_eq!(segments[0].tag, "BGM");
assert_eq!(segments[0].element_str(1), Some("PO-4711"));
Address fields by identifier, not index
// A stale or mistyped identifier is a compile error,
// not a quiet read of the neighbouring element.
#[derive(EdifactDeserialize)]
#[edifact(segment = "NAD", layout = NAD_DEF)]
struct Nad {
#[edifact(element = "3035")] qualifier: String,
#[edifact(element = "3039")] party_id: String,
}
Why edifact-rs
-
Zero-copy by default
Tags and component values borrow from the input slice. The only per-segment allocation is the element vector; owned strings appear solely where a release escape had to be resolved.
-
Constant-memory streaming
Reader iterators yield one segment at a time and message windows group them into
UNH…UNTunits, so a multi-gigabyte interchange costs one message of peak memory. -
Identifiers over indices
Address data elements by their UN/EDIFACT identifier. Resolution happens during const evaluation, so a wrong identifier fails the build instead of silently reading the element next door.
-
Syntax v4 repetitions
When a
UNAdeclares a repetition separator, repeating data elements are split into real occurrences — not left glued into the value as literal text. -
Limits that speak up
Segment, message, and byte budgets report a violation. A budget that quietly ended iteration would be indistinguishable from clean end-of-input, and a caller would accept a truncated interchange as a whole one.
-
Layered, composable validation
Envelope, structure, code-list, and profile layers write into one report with stable error codes, byte spans, and rule identifiers you can filter on.
Frequently asked
What is EDIFACT?
EDIFACT — Electronic Data Interchange For Administration, Commerce and Transport — is the UN standard for structured business messages, defined in ISO 9735. An interchange is flat text: segments separated by a terminator, each carrying data elements, each of those optionally split into components. It is used across supply chain, logistics, energy, healthcare, and banking. See Core Concepts.
How is this different from writing a split-on-delimiters parser?
Delimiters can be redefined per interchange by the UNA service
string advice, any delimiter can appear inside a value when release-escaped, and
syntax version 4 adds a repetition separator that changes an element's shape
rather than its text. A naive split silently merges or truncates values in all
three cases.
Is it safe against hostile input?
The crate forbids unsafe. Parsing is guarded by a per-segment size
limit plus optional segment-count, message-count, and byte budgets, and the
parser, writer, and validators are exercised by property and fuzz tests on every
commit. See Parsing.
Does it ship UN/EDIFACT directories?
No — directory data is versioned, large, and licensed separately. The crate provides the validation engine and the table types; supply your own definitions at compile time or load them at startup. See Validation.
Start reading
- Getting Started Install edifact-rs, parse your first EDIFACT interchange, and choose the feature flags you need.
- Core Concepts The EDIFACT wire format — segments, data elements, components, the UNA service string advice, release characters, and repetition — mapped onto the Rust types.
- Character Sets Decode UNOA-UNOK and UNOY interchanges, encode them back, and validate a payload against the repertoire its own UNB declares.
- Parsing Zero-copy slice parsing, streaming readers, byte spans, UNA handling, and the ReaderConfig budgets that guard against oversized input.
- Writing Serialize segments back to the EDIFACT wire format with Writer, automatic delimiter escaping, custom UNA service strings, and repeating data elements.
- Typed Derive Map EDIFACT segments and messages onto Rust structs with #[derive(EdifactDeserialize, EdifactSerialize)] and address fields by UN/EDIFACT data element identifier.