use super::*;
use crate::parts_write_adapter::CoreWriteAsPartsWrite;
use core::convert::Infallible;
pub trait TryWriteable {
type Error;
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))
}
fn try_write_to_parts<S: PartsWrite + ?Sized>(
&self,
sink: &mut S,
) -> Result<Result<(), Self::Error>, fmt::Error>;
fn writeable_length_hint(&self) -> LengthHint {
LengthHint::undefined()
}
#[cfg(feature = "alloc")]
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(""));
}
let mut output = String::with_capacity(hint.capacity());
match self
.try_write_to(&mut output)
.unwrap_or_else(|fmt::Error| Ok(()))
{
Ok(()) => Ok(Cow::Owned(output)),
Err(e) => Err((e, Cow::Owned(output))),
}
}
}
impl<T, E> TryWriteable for Result<T, E>
where
T: Writeable,
E: Writeable + Clone,
{
type Error = E;
#[inline]
fn try_write_to<W: fmt::Write + ?Sized>(
&self,
sink: &mut W,
) -> Result<Result<(), Self::Error>, fmt::Error> {
match self {
Ok(t) => t.write_to(sink).map(Ok),
Err(e) => e.write_to(sink).map(|()| Err(e.clone())),
}
}
#[inline]
fn try_write_to_parts<S: PartsWrite + ?Sized>(
&self,
sink: &mut S,
) -> Result<Result<(), Self::Error>, fmt::Error> {
match self {
Ok(t) => t.write_to_parts(sink).map(Ok),
Err(e) => sink
.with_part(Part::ERROR, |sink| e.write_to_parts(sink))
.map(|()| Err(e.clone())),
}
}
#[inline]
fn writeable_length_hint(&self) -> LengthHint {
match self {
Ok(t) => t.writeable_length_hint(),
Err(e) => e.writeable_length_hint(),
}
}
#[inline]
#[cfg(feature = "alloc")]
fn try_write_to_string(&self) -> Result<Cow<'_, str>, (Self::Error, Cow<'_, str>)> {
match self {
Ok(t) => Ok(t.write_to_string()),
Err(e) => Err((e.clone(), e.write_to_string())),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
#[allow(clippy::exhaustive_structs)] pub struct TryWriteableInfallibleAsWriteable<T>(pub T);
impl<T> Writeable for TryWriteableInfallibleAsWriteable<T>
where
T: TryWriteable<Error = Infallible>,
{
#[inline]
fn write_to<W: fmt::Write + ?Sized>(&self, sink: &mut W) -> fmt::Result {
match self.0.try_write_to(sink) {
Ok(Ok(())) => Ok(()),
Ok(Err(infallible)) => match infallible {},
Err(e) => Err(e),
}
}
#[inline]
fn write_to_parts<S: PartsWrite + ?Sized>(&self, sink: &mut S) -> fmt::Result {
match self.0.try_write_to_parts(sink) {
Ok(Ok(())) => Ok(()),
Ok(Err(infallible)) => match infallible {},
Err(e) => Err(e),
}
}
#[inline]
fn writeable_length_hint(&self) -> LengthHint {
self.0.writeable_length_hint()
}
#[inline]
#[cfg(feature = "alloc")]
fn write_to_string(&self) -> Cow<'_, str> {
match self.0.try_write_to_string() {
Ok(s) => s,
Err((infallible, _)) => match infallible {},
}
}
}
impl<T> fmt::Display for TryWriteableInfallibleAsWriteable<T>
where
T: TryWriteable<Error = Infallible>,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.write_to(f)
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
#[allow(clippy::exhaustive_structs)] pub struct WriteableAsTryWriteableInfallible<T>(pub T);
impl<T> TryWriteable for WriteableAsTryWriteableInfallible<T>
where
T: Writeable,
{
type Error = Infallible;
#[inline]
fn try_write_to<W: fmt::Write + ?Sized>(
&self,
sink: &mut W,
) -> Result<Result<(), Infallible>, fmt::Error> {
self.0.write_to(sink).map(Ok)
}
#[inline]
fn try_write_to_parts<S: PartsWrite + ?Sized>(
&self,
sink: &mut S,
) -> Result<Result<(), Infallible>, fmt::Error> {
self.0.write_to_parts(sink).map(Ok)
}
#[inline]
fn writeable_length_hint(&self) -> LengthHint {
self.0.writeable_length_hint()
}
#[inline]
#[cfg(feature = "alloc")]
fn try_write_to_string(&self) -> Result<Cow<'_, str>, (Infallible, Cow<'_, str>)> {
Ok(self.0.write_to_string())
}
}
#[macro_export]
macro_rules! assert_try_writeable_eq {
($actual_writeable:expr, $expected_str:expr $(,)?) => {
$crate::assert_try_writeable_eq!($actual_writeable, $expected_str, Ok(()))
};
($actual_writeable:expr, $expected_str:expr, $expected_result:expr $(,)?) => {
$crate::assert_try_writeable_eq!($actual_writeable, $expected_str, $expected_result, "")
};
($actual_writeable:expr, $expected_str:expr, $expected_result:expr, $($arg:tt)+) => {{
$crate::assert_try_writeable_eq!(@internal, $actual_writeable, $expected_str, $expected_result, $($arg)*);
}};
(@internal, $actual_writeable:expr, $expected_str:expr, $expected_result:expr, $($arg:tt)+) => {{
use $crate::TryWriteable;
let actual_writeable = &$actual_writeable;
let (actual_str, actual_parts, actual_error) = $crate::_internal::try_writeable_to_parts_for_test(actual_writeable);
assert_eq!(actual_str, $expected_str, $($arg)*);
assert_eq!(actual_error, Result::<(), _>::from($expected_result).err(), $($arg)*);
let actual_result = match actual_writeable.try_write_to_string() {
Ok(actual_cow_str) => {
assert_eq!(actual_cow_str, $expected_str, $($arg)+);
Ok(())
}
Err((e, actual_cow_str)) => {
assert_eq!(actual_cow_str, $expected_str, $($arg)+);
Err(e)
}
};
assert_eq!(actual_result, Result::<(), _>::from($expected_result), $($arg)*);
let length_hint = actual_writeable.writeable_length_hint();
assert!(
length_hint.0 <= actual_str.len(),
"hint lower bound {} larger than actual length {}: {}",
length_hint.0, actual_str.len(), format!($($arg)*),
);
if let Some(upper) = length_hint.1 {
assert!(
actual_str.len() <= upper,
"hint upper bound {} smaller than actual length {}: {}",
length_hint.0, actual_str.len(), format!($($arg)*),
);
}
actual_parts }};
}
#[macro_export]
macro_rules! assert_try_writeable_parts_eq {
($actual_writeable:expr, $expected_str:expr, $expected_parts:expr $(,)?) => {
$crate::assert_try_writeable_parts_eq!($actual_writeable, $expected_str, Ok(()), $expected_parts)
};
($actual_writeable:expr, $expected_str:expr, $expected_result:expr, $expected_parts:expr $(,)?) => {
$crate::assert_try_writeable_parts_eq!($actual_writeable, $expected_str, $expected_result, $expected_parts, "")
};
($actual_writeable:expr, $expected_str:expr, $expected_result:expr, $expected_parts:expr, $($arg:tt)+) => {{
let actual_parts = $crate::assert_try_writeable_eq!(@internal, $actual_writeable, $expected_str, $expected_result, $($arg)*);
assert_eq!(actual_parts, $expected_parts, $($arg)+);
}};
}
#[test]
fn test_result_try_writeable() {
let mut result: Result<&str, usize> = Ok("success");
assert_try_writeable_eq!(result, "success");
result = Err(44);
assert_try_writeable_eq!(result, "44", Err(44));
assert_try_writeable_parts_eq!(result, "44", Err(44), [(0, 2, Part::ERROR)])
}