Expand description
Derive macros for EdifactSerialize and EdifactDeserialize.
§Segment struct (single segment)
#[derive(EdifactSerialize, EdifactDeserialize)]
#[edifact(segment = "BGM")]
pub struct BgmSegment {
#[edifact(element = 0)]
pub doc_name_code: String,
#[edifact(element = 1)]
pub doc_id: String,
#[edifact(element = 2)]
pub msg_function: Option<String>,
}§Segment struct with qualifier
#[derive(EdifactSerialize, EdifactDeserialize)]
#[edifact(segment = "NAD", qualifier = "MS")]
pub struct NadMs {
#[edifact(element = 1)]
pub party_id: String,
}§Message struct (multiple segments)
#[derive(EdifactSerialize, EdifactDeserialize)]
pub struct OrdersMessage {
pub bgm: BgmSegment,
pub buyer: NadMs,
#[edifact(group)]
pub lines: Vec<LinSegment>,
}§#[edifact(group)] and Vec<T> fields
The #[edifact(group)] attribute marks a Vec<T> field as a contiguous group of
repeated segments. Without the attribute, Vec<T> on a segment struct collects
all matching segments from the window into the Vec.
Note: #[edifact(group)] enforces two compile-time structural constraints:
- The annotated field must be of type
Vec<T>— any other type is rejected with a clear error message. #[edifact(group)]cannot be combined with#[edifact(element = ...)]or#[edifact(component = ...)]— positional placement and group semantics are mutually exclusive.
At runtime the generated deserialization code collects contiguous occurrences of
the inner segment type T into the Vec using
edifact_rs::contiguous_groups_by_qualifier.
This is behaviorally different from a bare Vec<T> without #[edifact(group)],
which uses edifact_rs::find_segments_typed and does
not enforce contiguity.
§#[edifact(required)] on Option<T> fields
By default, Option<T> fields produce None when the element is absent.
Annotating an Option<T> field with #[edifact(required)] changes this:
instead of None, deserialization returns
edifact_rs::EdifactError::MissingRequiredElement
when the element is absent or empty. The Rust type stays Option<T>, which
is useful when the EDIFACT specification mandates the element but your domain
model treats it as optional for other reasons.
#[derive(EdifactSerialize, EdifactDeserialize)]
#[edifact(segment = "DTM")]
pub struct DtmSegment {
#[edifact(element = 0)]
qualifier: String,
/// Required by the spec but kept as Option in the domain model.
#[edifact(element = 1, required)]
date_time: Option<String>,
#[edifact(element = 2)]
format_code: Option<String>,
}§Non-String fields and Display / FromStr
Non-String field types (e.g. u32, bool, your own newtype) are serialized via
Display and deserialized via FromStr. The derive macro does not add a
compile-time bound; if the type does not implement both traits the generated code
will fail to compile with a standard “trait not satisfied” error.
To avoid surprises, ensure any non-String field type implements both:
impl std::fmt::Display for MyCode { ... }
impl std::str::FromStr for MyCode { ... }Derive Macros§
- Edifact
Deserialize - Derive
edifact_rs::EdifactDeserializefor segment or message structs. - Edifact
Serialize - Derive
edifact_rs::EdifactSerializefor segment or message structs.