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§
Sourcefn try_write_to_parts<S: PartsWrite + ?Sized>(
&self,
sink: &mut S,
) -> Result<Result<(), Self::Error>, Error>
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:
TryWriteable::try_write_to()
for the general behavior.TryWriteable
for an example with parts.Part
for more about parts.
Provided Methods§
Sourcefn try_write_to<W: Write + ?Sized>(
&self,
sink: &mut W,
) -> Result<Result<(), Self::Error>, Error>
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");
Sourcefn writeable_length_hint(&self) -> LengthHint
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()
.
Sourcefn try_write_to_string(
&self,
) -> Result<Cow<'_, str>, (Self::Error, Cow<'_, str>)>
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);
Sourcefn writeable_cmp_bytes(&self, other: &[u8]) -> Ordering
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!"));
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.