pub struct Writer<W: Write> { /* private fields */ }Expand description
Streaming EDIFACT writer.
Wraps any Write implementation and serializes segments one at a time.
Call Writer::finish to flush and get the underlying writer back.
§What it will not write
Everything the writer emits reparses. Two cases are refused before a byte reaches the sink, so a rejected segment leaves nothing half-written:
- A segment tag that is not three ASCII uppercase letters
(
EdifactError::InvalidSegmentTag). A tag is written verbatim — EDIFACT has no way to escape one — sobgm,BGMX, orB+Mwould produce bytes that do not read back as the segment they came from. - A repeating data element when no repetition separator is declared
(
EdifactError::RepetitionSeparatorNotDeclared).
Delimiters inside a value are not a problem: those are release-escaped.
§Wrap unbuffered sinks
Writer issues a separate write for each tag, delimiter, and value chunk, so
a segment costs roughly one write per component. Against an in-memory
Vec<u8> that is free, but against a File or a socket each
one is a syscall.
The writer deliberately does not buffer internally: an internal buffer
would silently discard everything not yet flushed if the writer were dropped
without finish. Wrap the sink instead, which makes the
buffering visible and keeps the flush contract in one place:
use std::io::BufWriter;
use edifact_rs::Writer;
let sink = Vec::new(); // stands in for a File or TcpStream
let mut writer = Writer::new(BufWriter::new(sink));
writer.write_simple("BGM", &["220"])?;
// `finish` flushes the `Writer` and hands the `BufWriter` back.
let buffered = writer.finish()?;
assert_eq!(buffered.into_inner().unwrap(), b"BGM+220'".to_vec());Implementations§
Source§impl<W: Write> Writer<W>
impl<W: Write> Writer<W>
Sourcepub fn with_charset(self, charset: Charset) -> Self
pub fn with_charset(self, charset: Charset) -> Self
Bind this writer to a character repertoire.
Every value is then encoded into charset rather than emitted as UTF-8,
and a character the repertoire cannot carry is rejected with
EdifactError::CharacterNotInRepertoire instead of being written as
bytes the receiver decodes as something else.
This is the write-side counterpart of
decode_interchange: a UNOC interchange
must go out as ISO 8859-1, not UTF-8, or ü arrives as two mojibake
characters.
§Example
use edifact_rs::{Charset, Writer};
let mut writer = Writer::new(Vec::new()).with_charset(Charset::UnoC);
writer.write_composites("NAD", &[&["BY"], &["Müller"]])?;
// `ü` goes out as the single Latin-1 byte 0xFC.
assert_eq!(writer.finish()?, b"NAD+BY+M\xFCller'".to_vec());A value outside the repertoire is refused:
use edifact_rs::{Charset, EdifactError, Writer};
let mut writer = Writer::new(Vec::new()).with_charset(Charset::UnoA);
// Level A is upper-case only.
let err = writer.write_composites("NAD", &[&["BY"], &["Müller"]]).unwrap_err();
assert!(matches!(err, EdifactError::CharacterNotInRepertoire { .. }));Sourcepub fn charset(&self) -> Option<Charset>
pub fn charset(&self) -> Option<Charset>
The repertoire this writer encodes into, if it is bound to one.
Sourcepub fn with_service_string_advice(
inner: W,
ssa: ServiceStringAdvice,
) -> Result<Self, EdifactError>
pub fn with_service_string_advice( inner: W, ssa: ServiceStringAdvice, ) -> Result<Self, EdifactError>
Create a writer that uses ssa’s delimiters without emitting a UNA.
For replying on an inbound interchange’s delimiters, or round-tripping a
syntax-version-4 interchange that has repeating elements but no UNA:
the writer needs the repetition separator, and
with_una would add a header the original lacked.
§Errors
EdifactError::InvalidUna when the service characters are not mutually
distinct printable non-alphanumeric ASCII — see
ServiceStringAdvice::is_valid.
§Example
use edifact_rs::{ServiceStringAdvice, Writer, from_bytes};
// Version 4: `*` separates RFF's two occurrences, with no UNA to say so.
let input = b"UNB+UNOC:4+S+R+260101:0900+I'RFF+ON:1*ON:2'UNZ+0+I'";
let segments: Vec<_> = from_bytes(input).collect::<Result<Vec<_>, _>>()?;
let ssa = ServiceStringAdvice::for_syntax_version(Some(4));
let mut writer = Writer::with_service_string_advice(Vec::new(), ssa)?;
for segment in &segments {
writer.write_segment(segment)?;
}
// Byte-for-byte the input, with no UNA invented.
assert_eq!(writer.finish()?, input.to_vec());Sourcepub fn with_una(
inner: W,
ssa: ServiceStringAdvice,
) -> Result<Self, EdifactError>
pub fn with_una( inner: W, ssa: ServiceStringAdvice, ) -> Result<Self, EdifactError>
Create a writer with custom delimiters and write a UNA segment first.
with_service_string_advice is the
same thing without the header.
§Errors
As with_service_string_advice, plus
any write failure.
Sourcepub fn write_segment(&mut self, seg: &Segment<'_>) -> Result<(), EdifactError>
pub fn write_segment(&mut self, seg: &Segment<'_>) -> Result<(), EdifactError>
Write a single segment, including any ISO 9735-4 repetitions.
§Errors
Returns EdifactError::RepetitionSeparatorNotDeclared when the segment
carries a repeating data element but the active service string advice
declares no repetition separator. The check runs before any byte is
written, so a rejected segment leaves nothing behind in the sink — a
half-written RFF+ would otherwise corrupt the interchange for every
caller that recovers from the error and carries on.
Sourcepub fn write_simple<S: AsRef<str>>(
&mut self,
tag: &str,
elements: &[S],
) -> Result<(), EdifactError>
pub fn write_simple<S: AsRef<str>>( &mut self, tag: &str, elements: &[S], ) -> Result<(), EdifactError>
Write a segment whose data elements are all simple — one value each.
The shorthand for the commonest segment shape. Each string is one whole data element: a component separator inside a value is escaped as data, not promoted to a component boundary, so the output is correct whatever delimiters the writer uses.
Reach for write_composites when the elements
have components, or write_elements when the
segment mixes the two shapes.
§Example
use edifact_rs::Writer;
let mut w = Writer::new(Vec::new());
w.write_simple("BGM", &["220", "PO-4711", "9"])?;
// A literal `:` stays inside the value it belongs to.
w.write_simple("FTX", &["AAA", "ACME:INC"])?;
assert_eq!(w.finish()?, b"BGM+220+PO-4711+9'FTX+AAA+ACME?:INC'".to_vec());§Errors
Returns EdifactError if the underlying writer fails, or if a value
cannot be encoded in this writer’s Charset.
Sourcepub fn write_composites<E, S>(
&mut self,
tag: &str,
elements: &[E],
) -> Result<(), EdifactError>
pub fn write_composites<E, S>( &mut self, tag: &str, elements: &[E], ) -> Result<(), EdifactError>
Write a segment whose data elements are all composite — a list of components each.
Component boundaries are given explicitly rather than inferred by splitting, so a value containing the active component separator is escaped instead of being silently reinterpreted as a boundary.
The bounds accept borrowed and owned data alike — &[&[&str]],
&[Vec<String>], &[[String; 3]] — so runtime-built segments need no
conversion. A one-component element is a simple data element, which is
what makes this the general all-elements form;
write_elements is the shorthand for the mixed
shape and write_simple for the all-simple one.
§Example
use edifact_rs::Writer;
let mut w = Writer::new(Vec::new());
// Borrowed literals …
w.write_composites("NAD", &[&["MS"][..], &["ACME:INC"][..]])?;
// … and owned, runtime-built data, through the same call.
let dtm = vec![vec!["137".to_string(), "20260101".to_string()]];
w.write_composites("DTM", &dtm)?;
assert_eq!(w.finish()?, b"NAD+MS+ACME?:INC'DTM+137:20260101'".to_vec());§Errors
Returns EdifactError if the underlying writer fails, or if a value
cannot be encoded in this writer’s Charset.
Sourcepub fn write_elements(
&mut self,
tag: &str,
elements: &[DataElement<'_>],
) -> Result<(), EdifactError>
pub fn write_elements( &mut self, tag: &str, elements: &[DataElement<'_>], ) -> Result<(), EdifactError>
Write a segment whose data elements mix simple and composite shapes.
This is the general form of segment emission and the one that matches
how EDIFACT segments are actually specified: NAD takes a simple
qualifier followed by a composite party identification, DTM takes a
single composite. write_simple and
write_composites are the uniform special
cases.
Component boundaries are explicit, so a value containing the active component separator is escaped rather than silently promoted to a boundary. Nothing is allocated.
§Example
use edifact_rs::{DataElement, Writer, elements};
let mut w = Writer::new(Vec::new());
// Explicit form …
w.write_elements(
"NAD",
&[DataElement::Simple("MS"), DataElement::Composite(&["ACME:INC", "", "9"])],
)?;
// … or the `elements!` shorthand.
w.write_elements("DTM", elements![["137", "20260101", "102"]])?;
assert_eq!(
w.finish()?,
b"NAD+MS+ACME?:INC::9'DTM+137:20260101:102'".to_vec(),
);§Errors
Returns EdifactError if the underlying writer fails.
Sourcepub fn finish(self) -> Result<W, EdifactError>
pub fn finish(self) -> Result<W, EdifactError>
Flush and return the underlying writer.
Sourcepub fn finish_unt(self, message_ref: &str) -> Result<W, EdifactError>
pub fn finish_unt(self, message_ref: &str) -> Result<W, EdifactError>
Write the UNT segment and return the inner writer.
The count written into UNT DE 0074 covers the current message only:
UNH, every segment written since it, and UNT itself. Segments written
before the message’s UNH — an interchange-level UNB, or a preceding
message — are excluded, as EDIFACT requires.
If no UNH has been written, the count falls back to every segment
written so far plus one.
§Errors
Returns an error if writing fails. Do not call write_simple or
write_segment after finish_unt — the writer is consumed.
Sourcepub fn segment_count(&self) -> u64
pub fn segment_count(&self) -> u64
Returns the total number of segments written so far.
Sourcepub fn service_string_advice(&self) -> ServiceStringAdvice
pub fn service_string_advice(&self) -> ServiceStringAdvice
Returns the active ServiceStringAdvice (delimiter configuration).
Sourcepub fn escape_value<'v>(&self, value: &'v str) -> Cow<'v, str>
pub fn escape_value<'v>(&self, value: &'v str) -> Cow<'v, str>
Escape a value string for inclusion in an EDIFACT segment.
Any character in value that matches the active element separator,
component separator, release character, or segment terminator is escaped
by prefixing it with the release character (default ?).
Returns a borrowed Cow::Borrowed(value) when no escaping is needed,
avoiding an allocation on the fast path.
§Example
let writer = Writer::new(std::io::sink());
// '+' must be escaped since it is the default element separator.
assert_eq!(writer.escape_value("price+tax"), "price?+tax");Sourcepub fn begin_interchange(
&mut self,
syntax_id: &str,
syntax_version: &str,
sender: &str,
recipient: &str,
date: &str,
time: &str,
control_ref: &str,
) -> Result<(), EdifactError>
pub fn begin_interchange( &mut self, syntax_id: &str, syntax_version: &str, sender: &str, recipient: &str, date: &str, time: &str, control_ref: &str, ) -> Result<(), EdifactError>
Write a UNB interchange header segment.
Generates:
UNB+<syntax_id>:<syntax_version>+<sender>+<recipient>+<date>:<time>+<control_ref>'Composite components (S001 syntax identifier/version, S004 date/time) are
passed separately rather than pre-joined with :, so they are written
with the writer’s active component separator and so a literal separator
inside sender, recipient, or control_ref is escaped rather than
silently promoted to a component boundary.
Track the control_ref — it must be repeated in the matching
end_interchange call.
§Example
use edifact_rs::Writer;
let mut w = Writer::new(Vec::new());
w.begin_interchange("UNOA", "1", "SENDER", "RECEIVER", "200101", "0900", "IC1")?;
assert_eq!(
w.finish()?,
b"UNB+UNOA:1+SENDER+RECEIVER+200101:0900+IC1'".to_vec(),
);§Errors
Returns EdifactError if writing fails.
Sourcepub fn begin_message<'w>(
&'w mut self,
message_ref: &str,
message_type: &str,
version: &str,
release: &str,
controlling_agency: &str,
) -> Result<MessageWriter<'w, W>, EdifactError>
pub fn begin_message<'w>( &'w mut self, message_ref: &str, message_type: &str, version: &str, release: &str, controlling_agency: &str, ) -> Result<MessageWriter<'w, W>, EdifactError>
Write a UNH message header and return a MessageWriter guard.
The guard tracks the per-message segment count automatically. Call
MessageWriter::finish when all message segments have been written — this
writes the matching UNT segment with the correct count. If finish is not
called, Drop will attempt to write UNT as a best-effort fallback (errors
are silently discarded on drop; prefer explicit finish).
Generates:
UNH+<message_ref>+<message_type>:<version>:<release>:<controlling_agency>'§Errors
Returns EdifactError if writing the UNH segment fails.
Sourcepub fn end_interchange(
&mut self,
message_count: u32,
control_ref: &str,
) -> Result<(), EdifactError>
pub fn end_interchange( &mut self, message_count: u32, control_ref: &str, ) -> Result<(), EdifactError>
Write a UNZ interchange trailer segment.
message_count is the number of UNH/UNT message pairs in the
interchange. control_ref must match the value passed to
begin_interchange.
If you used begin_message for every message in the
interchange, message_count equals the number of times you called that
method.
§Errors
Returns EdifactError if writing fails.
Auto Trait Implementations§
impl<W> Freeze for Writer<W>where
W: Freeze,
impl<W> RefUnwindSafe for Writer<W>where
W: RefUnwindSafe,
impl<W> Send for Writer<W>where
W: Send,
impl<W> Sync for Writer<W>where
W: Sync,
impl<W> Unpin for Writer<W>where
W: Unpin,
impl<W> UnsafeUnpin for Writer<W>where
W: UnsafeUnpin,
impl<W> UnwindSafe for Writer<W>where
W: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<D> OwoColorize for D
impl<D> OwoColorize for D
Source§fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>where
C: Color,
fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>where
C: Color,
Source§fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>where
C: Color,
fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>where
C: Color,
Source§fn black(&self) -> FgColorDisplay<'_, Black, Self>
fn black(&self) -> FgColorDisplay<'_, Black, Self>
Source§fn on_black(&self) -> BgColorDisplay<'_, Black, Self>
fn on_black(&self) -> BgColorDisplay<'_, Black, Self>
Source§fn red(&self) -> FgColorDisplay<'_, Red, Self>
fn red(&self) -> FgColorDisplay<'_, Red, Self>
Source§fn on_red(&self) -> BgColorDisplay<'_, Red, Self>
fn on_red(&self) -> BgColorDisplay<'_, Red, Self>
Source§fn green(&self) -> FgColorDisplay<'_, Green, Self>
fn green(&self) -> FgColorDisplay<'_, Green, Self>
Source§fn on_green(&self) -> BgColorDisplay<'_, Green, Self>
fn on_green(&self) -> BgColorDisplay<'_, Green, Self>
Source§fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>
fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>
Source§fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>
fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>
Source§fn blue(&self) -> FgColorDisplay<'_, Blue, Self>
fn blue(&self) -> FgColorDisplay<'_, Blue, Self>
Source§fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>
fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>
Source§fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>
fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>
Source§fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>
fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>
Source§fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>
fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>
Source§fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>
fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>
Source§fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>
fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>
Source§fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>
fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>
Source§fn white(&self) -> FgColorDisplay<'_, White, Self>
fn white(&self) -> FgColorDisplay<'_, White, Self>
Source§fn on_white(&self) -> BgColorDisplay<'_, White, Self>
fn on_white(&self) -> BgColorDisplay<'_, White, Self>
Source§fn default_color(&self) -> FgColorDisplay<'_, Default, Self>
fn default_color(&self) -> FgColorDisplay<'_, Default, Self>
Source§fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>
fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>
Source§fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>
fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>
Source§fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>
fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>
Source§fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>
fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>
Source§fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>
fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>
Source§fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>
fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>
Source§fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>
fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>
Source§fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>
fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>
Source§fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>
fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>
Source§fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>
fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>
Source§fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>
fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>
Source§fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>
fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>
Source§fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>
fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>
Source§fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>
fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>
Source§fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>
fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>
Source§fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>
fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>
Source§fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>
fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>
Source§fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>
fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>
Source§fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>
fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>
Source§fn bold(&self) -> BoldDisplay<'_, Self>
fn bold(&self) -> BoldDisplay<'_, Self>
Source§fn dimmed(&self) -> DimDisplay<'_, Self>
fn dimmed(&self) -> DimDisplay<'_, Self>
Source§fn italic(&self) -> ItalicDisplay<'_, Self>
fn italic(&self) -> ItalicDisplay<'_, Self>
Source§fn underline(&self) -> UnderlineDisplay<'_, Self>
fn underline(&self) -> UnderlineDisplay<'_, Self>
Source§fn blink(&self) -> BlinkDisplay<'_, Self>
fn blink(&self) -> BlinkDisplay<'_, Self>
Source§fn blink_fast(&self) -> BlinkFastDisplay<'_, Self>
fn blink_fast(&self) -> BlinkFastDisplay<'_, Self>
Source§fn reversed(&self) -> ReversedDisplay<'_, Self>
fn reversed(&self) -> ReversedDisplay<'_, Self>
Source§fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>
fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>
Source§fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>where
Color: DynColor,
fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>where
Color: DynColor,
OwoColorize::fg or
a color-specific method, such as OwoColorize::green, Read moreSource§fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>where
Color: DynColor,
fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>where
Color: DynColor,
OwoColorize::bg or
a color-specific method, such as OwoColorize::on_yellow, Read more