usesuper::*; usecrate::parts_write_adapter::CoreWriteAsPartsWrite; use core::{cmp::Ordering, convert::Infallible};
/// 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)] /// ); /// ``` pubtrait TryWriteable { type 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: /// /// ``` /// # use writeable::TryWriteable; /// # let my_writeable: Result<&str, &str> = Ok(""); /// # let mut sink = String::new(); /// let _ = my_writeable.try_write_to(&mut sink)?; /// # Ok::<(), core::fmt::Error>(()) /// ``` /// /// # 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"); /// ``` fn try_write_to<W: fmt::Write + ?Sized>(
&self,
sink: &mut W,
) -> Result<Result<(), Self::Error>, fmt::Error> { self.try_write_to_parts(&mut CoreWriteAsPartsWrite(sink))
}
/// 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. fn try_write_to_parts<S: PartsWrite + ?Sized>(
&self,
sink: &mut S,
) -> Result<Result<(), Self::Error>, fmt::Error>;
/// 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()`]. fn writeable_length_hint(&self) -> LengthHint {
LengthHint::undefined()
}
/// 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 std::borrow::Cow; /// # use writeable::TryWriteable; /// // 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); /// ``` fn try_write_to_string(&self) -> Result<Cow<str>, (Self::Error, Cow<str>)> { let hint = self.writeable_length_hint(); if hint.is_zero() { return Ok(Cow::Borrowed(""));
} letmut output = String::with_capacity(hint.capacity()); matchself
.try_write_to(&mut output)
.unwrap_or_else(|fmt::Error| Ok(()))
{
Ok(()) => Ok(Cow::Owned(output)),
Err(e) => Err((e, Cow::Owned(output))),
}
}
/// 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; /// # use writeable::PartsWrite; /// # use writeable::LengthHint; /// /// #[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 /// # 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 _ = self.name.ok_or("nobody").try_write_to_parts(sink)?; /// # 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 self.name.is_some() { /// # Ok(Ok(())) /// # } else { /// # Ok(Err(HelloWorldWriteableError::MissingName)) /// # } /// # } /// } /// /// // 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!")); /// ``` fn writeable_cmp_bytes(&self, other: &[u8]) -> Ordering { letmut wc = cmp::WriteComparator::new(other); let _ = self
.try_write_to(&mut wc)
.unwrap_or_else(|fmt::Error| Ok(()));
wc.finish().reverse()
}
}
impl<T, E> TryWriteable for Result<T, E> where
T: Writeable,
E: Writeable + Clone,
{ type Error = E;
/// A wrapper around [`Writeable`] that implements [`TryWriteable`] /// with [`TryWriteable::Error`] set to [`Infallible`]. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] #[allow(clippy::exhaustive_structs)] // transparent newtype pubstruct WriteableAsTryWriteableInfallible<T>(pub T);
impl<T> TryWriteable for WriteableAsTryWriteableInfallible<T> where
T: Writeable,
{ type Error = Infallible;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.