Trait writeable::TryWriteable

source ·
pub trait TryWriteable {
    type Error;

    // Required method
    fn try_write_to_parts<S: PartsWrite + ?Sized>(
        &self,
        sink: &mut S,
    ) -> Result<Result<(), Self::Error>, Error>;

    // Provided methods
    fn try_write_to<W: Write + ?Sized>(
        &self,
        sink: &mut W,
    ) -> Result<Result<(), Self::Error>, Error> { ... }
    fn writeable_length_hint(&self) -> LengthHint { ... }
    fn try_write_to_string(
        &self,
    ) -> Result<Cow<'_, str>, (Self::Error, Cow<'_, str>)> { ... }
    fn writeable_cmp_bytes(&self, other: &[u8]) -> Ordering { ... }
}
Expand description

A writeable object that can fail while writing.

The default Writeable trait returns a fmt::Error, which originates from the sink. In contrast, this trait allows the writeable itself to trigger an error as well.

Implementations are expected to always make a best attempt at writing to the sink and should write replacement values in the error state. Therefore, the returned Result can be safely ignored to emulate a “lossy” mode.

Any error substrings should be annotated with Part::ERROR.

§Implementer Notes

This trait requires that implementers make a best attempt at writing to the sink, even in the error state, such as with a placeholder or fallback string.

In TryWriteable::try_write_to_parts(), error substrings should be annotated with Part::ERROR. Because of this, writing to parts is not default-implemented like it is on Writeable.

The trait is implemented on Result<T, E> where T and E both implement Writeable; In the Ok case, T is written, and in the Err case, E is written as a fallback value. This impl, which writes Part::ERROR, can be used as a basis for more advanced impls.

§Examples

Implementing on a custom type:

use core::fmt;
use writeable::LengthHint;
use writeable::PartsWrite;
use writeable::TryWriteable;

#[derive(Debug, PartialEq, Eq)]
enum HelloWorldWriteableError {
    MissingName,
}

#[derive(Debug, PartialEq, Eq)]
struct HelloWorldWriteable {
    pub name: Option<&'static str>,
}

impl TryWriteable for HelloWorldWriteable {
    type Error = HelloWorldWriteableError;

    fn try_write_to_parts<S: PartsWrite + ?Sized>(
        &self,
        sink: &mut S,
    ) -> Result<Result<(), Self::Error>, fmt::Error> {
        sink.write_str("Hello, ")?;
        // Use `impl TryWriteable for Result` to generate the error part:
        let err = self.name.ok_or("nobody").try_write_to_parts(sink)?.err();
        sink.write_char('!')?;
        // Return a doubly-wrapped Result.
        // The outer Result is for fmt::Error, handled by the `?`s above.
        // The inner Result is for our own Self::Error.
        if err.is_none() {
            Ok(Ok(()))
        } else {
            Ok(Err(HelloWorldWriteableError::MissingName))
        }
    }

    fn writeable_length_hint(&self) -> LengthHint {
        self.name.ok_or("nobody").writeable_length_hint() + 8
    }
}

// Success case:
writeable::assert_try_writeable_eq!(
    HelloWorldWriteable {
        name: Some("Alice")
    },
    "Hello, Alice!"
);

// Failure case, including the ERROR part:
writeable::assert_try_writeable_parts_eq!(
    HelloWorldWriteable { name: None },
    "Hello, nobody!",
    Err(HelloWorldWriteableError::MissingName),
    [(7, 13, writeable::Part::ERROR)]
);

Required Associated Types§

Required Methods§

source

fn try_write_to_parts<S: PartsWrite + ?Sized>( &self, sink: &mut S, ) -> Result<Result<(), Self::Error>, Error>

Writes the content of this writeable to a sink with parts (annotations).

For more information, see:

Provided Methods§

source

fn try_write_to<W: Write + ?Sized>( &self, sink: &mut W, ) -> Result<Result<(), Self::Error>, Error>

Writes the content of this writeable to a sink.

If the sink hits an error, writing immediately ends, Err(fmt::Error) is returned, and the sink does not contain valid output.

If the writeable hits an error, writing is continued with a replacement value, Ok(Err(TryWriteable::Error)) is returned, and the caller may continue using the sink.

§Lossy Mode

The fmt::Error should always be handled, but the TryWriteable::Error can be ignored if a fallback string is desired instead of an error.

To handle the sink error, but not the writeable error, write:

let _ = my_writeable.try_write_to(&mut sink)?;
§Examples

The following examples use Result<&str, usize>, which implements TryWriteable because both &str and usize do.

Success case:

use writeable::TryWriteable;

let w: Result<&str, usize> = Ok("success");
let mut sink = String::new();
let result = w.try_write_to(&mut sink);

assert_eq!(result, Ok(Ok(())));
assert_eq!(sink, "success");

Failure case:

use writeable::TryWriteable;

let w: Result<&str, usize> = Err(44);
let mut sink = String::new();
let result = w.try_write_to(&mut sink);

assert_eq!(result, Ok(Err(44)));
assert_eq!(sink, "44");
source

fn writeable_length_hint(&self) -> LengthHint

Returns a hint for the number of UTF-8 bytes that will be written to the sink.

This function returns the length of the “lossy mode” string; for more information, see TryWriteable::try_write_to().

source

fn try_write_to_string( &self, ) -> Result<Cow<'_, str>, (Self::Error, Cow<'_, str>)>

Writes the content of this writeable to a string.

In the failure case, this function returns the error and the best-effort string (“lossy mode”).

Examples

// use the best-effort string
let r1: Cow<str> = Ok::<&str, u8>("ok")
    .try_write_to_string()
    .unwrap_or_else(|(_, s)| s);
// propagate the error
let r2: Result<Cow<str>, u8> = Ok::<&str, u8>("ok")
    .try_write_to_string()
    .map_err(|(e, _)| e);
source

fn writeable_cmp_bytes(&self, other: &[u8]) -> Ordering

Compares the content of this writeable to a byte slice.

This function compares the “lossy mode” string; for more information, see TryWriteable::try_write_to().

For more information, see Writeable::writeable_cmp_bytes().

§Examples
use core::cmp::Ordering;
use core::fmt;
use writeable::TryWriteable;

#[derive(Debug, PartialEq, Eq)]
enum HelloWorldWriteableError {
    MissingName
}

#[derive(Debug, PartialEq, Eq)]
struct HelloWorldWriteable {
    pub name: Option<&'static str>
}

impl TryWriteable for HelloWorldWriteable {
    type Error = HelloWorldWriteableError;
    // see impl in TryWriteable docs
}

// Success case:
let writeable = HelloWorldWriteable { name: Some("Alice") };
let writeable_str = writeable.try_write_to_string().expect("name is Some");

assert_eq!(Ordering::Equal, writeable.writeable_cmp_bytes(b"Hello, Alice!"));

assert_eq!(Ordering::Greater, writeable.writeable_cmp_bytes(b"Alice!"));
assert_eq!(Ordering::Greater, (*writeable_str).cmp("Alice!"));

assert_eq!(Ordering::Less, writeable.writeable_cmp_bytes(b"Hello, Bob!"));
assert_eq!(Ordering::Less, (*writeable_str).cmp("Hello, Bob!"));

// Failure case:
let writeable = HelloWorldWriteable { name: None };
let mut writeable_str = String::new();
let _ = writeable.try_write_to(&mut writeable_str).expect("write to String is infallible");

assert_eq!(Ordering::Equal, writeable.writeable_cmp_bytes(b"Hello, nobody!"));

assert_eq!(Ordering::Greater, writeable.writeable_cmp_bytes(b"Hello, alice!"));
assert_eq!(Ordering::Greater, (*writeable_str).cmp("Hello, alice!"));

assert_eq!(Ordering::Less, writeable.writeable_cmp_bytes(b"Hello, zero!"));
assert_eq!(Ordering::Less, (*writeable_str).cmp("Hello, zero!"));

Object Safety§

This trait is not object safe.

Implementations on Foreign Types§

source§

impl<T, E> TryWriteable for Result<T, E>
where T: Writeable, E: Writeable + Clone,

source§

type Error = E

source§

fn try_write_to<W: Write + ?Sized>( &self, sink: &mut W, ) -> Result<Result<(), Self::Error>, Error>

source§

fn try_write_to_parts<S: PartsWrite + ?Sized>( &self, sink: &mut S, ) -> Result<Result<(), Self::Error>, Error>

source§

fn writeable_length_hint(&self) -> LengthHint

source§

fn try_write_to_string( &self, ) -> Result<Cow<'_, str>, (Self::Error, Cow<'_, str>)>

source§

fn writeable_cmp_bytes(&self, other: &[u8]) -> Ordering

Implementors§