Skip to main content

Writer

Struct Writer 

Source
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:

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>

Source

pub fn new(inner: W) -> Self

Create a new writer with default EDIFACT delimiters.

Source

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 { .. }));
Source

pub fn charset(&self) -> Option<Charset>

The repertoire this writer encodes into, if it is bound to one.

Source

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());
Source

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.

Source

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.

Source

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.

Source

pub fn write_composites<E, S>( &mut self, tag: &str, elements: &[E], ) -> Result<(), EdifactError>
where E: AsRef<[S]>, S: AsRef<str>,

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.

Source

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.

Source

pub fn finish(self) -> Result<W, EdifactError>

Flush and return the underlying writer.

Source

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.

Source

pub fn segment_count(&self) -> u64

Returns the total number of segments written so far.

Source

pub fn service_string_advice(&self) -> ServiceStringAdvice

Returns the active ServiceStringAdvice (delimiter configuration).

Source

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");
Source

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.

Source

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.

Source

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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<D> OwoColorize for D

Source§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where C: Color,

Set the foreground color generically Read more
Source§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where C: Color,

Set the background color generically. Read more
Source§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
Source§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
Source§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
Source§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
Source§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
Source§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
Source§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
Source§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
Source§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
Source§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
Source§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
Source§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
Source§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
Source§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
Source§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
Source§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
Source§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
Source§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
Source§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
Source§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
Source§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
Source§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
Source§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
Source§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
Source§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
Source§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
Source§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
Source§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
Source§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
Source§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
Source§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
Source§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
Source§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
Source§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
Source§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
Source§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
Source§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
Source§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
Source§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
Source§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
Source§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
Source§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text underlined
Make the text blink
Make the text blink (but fast!)
Source§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
Source§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
Source§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
Source§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at compile-time. If the color is constant, use either OwoColorize::fg or a color-specific method, such as OwoColorize::green, Read more
Source§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at compile-time. If the color is constant, use either OwoColorize::bg or a color-specific method, such as OwoColorize::on_yellow, Read more
Source§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( &self, ) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
Source§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( &self, ) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
Source§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
Source§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
Source§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.