-
Notifications
You must be signed in to change notification settings - Fork 175
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add TryWriteable for writeables that can fail #4772
Conversation
fn unwrap_infallible(self) -> Self::T; | ||
} | ||
|
||
impl<T> UnwrapInfallible for Result<T, Infallible> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: let's just use a free function for this
fn fallible_write_to< | ||
W: fmt::Write + ?Sized, | ||
L: Writeable, | ||
E, | ||
F: FnMut(Self::Error) -> Result<L, E>, | ||
>( | ||
&self, | ||
sink: &mut W, | ||
handler: F, | ||
) -> Result<Result<(), E>, fmt::Error>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussion: This signature is nice in the sense that it enforces consistency while handling errors via the type system, but it also may cause more monomorphization. We'd probably need to add it to write_pattern
. However, the creep should be limited to which version of TryWriteable the user calls.
pub(crate) fn write_pattern<'data, T, W, DS, TS>(
pattern_items: impl Iterator<Item = PatternItem>,
pattern_metadata: PatternMetadata,
date_symbols: Option<&DS>,
time_symbols: Option<&TS>,
loc_datetime: &impl LocalizedDateTimeInput<T>,
fixed_decimal_format: &FixedDecimalFormatter,
w: &mut W,
) -> Result<(), Error>
where
T: DateTimeInput,
W: fmt::Write + ?Sized,
DS: DateSymbols<'data>,
TS: TimeSymbols,
{
Working Group Discussion:
|
enum NeverWriteable {} | ||
|
||
impl Writeable for NeverWriteable { | ||
#[inline(always)] // to help the compiler find unreachable code paths |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: does this actually work with the annotation, and not without?
} | ||
} | ||
|
||
impl<T> TryWriteable for T where T: FallibleWriteable {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why are these separate traits if TryWriteable
is blanket-implemented?
match self.fallible_write_to(&mut wc, handler) { | ||
Ok(Ok(())) => (), | ||
Ok(Err(e)) => return Err(e), | ||
Err(core::fmt::Error) => unreachable!("writing to string is infallible"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: wrong message, you're not writing to string
>( | ||
&self, | ||
sink: &mut W, | ||
handler: F, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing error handlers as closures is unusual. Can this not be done at the call site?
/// Lower-level trait for writeables that can fail while writing. | ||
/// | ||
/// The methods on this trait should be implemented on custom writeables, but they generally | ||
/// should not called directly. For methods more useful in client code, see [`TryWriteable`]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// should not called directly. For methods more useful in client code, see [`TryWriteable`]. | |
/// should not be called directly. For methods more useful in client code, see [`TryWriteable`]. |
/// writeable::assert_writeable_eq!(try_writeable.lossy(), "�"); | ||
/// ``` | ||
#[inline] | ||
fn lossy(&self) -> LossyWriteable<&Self> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LossyWriteable
needs Self::Error: Writeable
to work, but the bound is not here. This sounds like it will lead to very annoying errors.
I do find it a bit odd that lossy allows custom errors to be written, it's not really lossy then because no information is lost. If it unconditionally wrote U+FFFD, it'd be lossy.
/// ); | ||
/// assert_writeable_eq!( | ||
/// HelloWriteable { name: None::<&str> }.lossy(), | ||
/// "Hello, ___!" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lossy
is documented to return U+FFFD in the error case, but here it returns ___
because the writeable can somehow overwrite that? I think this is very confusing.
/// | ||
/// let try_writeable = None::<&str>; | ||
/// assert!(matches!( | ||
/// try_writeable.checked().try_write_to_string(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: why is try_write_to_string
not on TryWriteable
itself?
/// } | ||
/// ``` | ||
#[inline] | ||
fn gigo(&self) -> GigoWriteable<&Self> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, so we haven't been using the term "gigo" on our API before. I think it's not one of the universally known acronyms, so I'd like to find a better name for it.
|
||
impl_display_with_writeable!([T] GigoWriteable<T> where T: FallibleWriteable, T::Error: Writeable, T::Error: fmt::Debug); | ||
|
||
impl<T> FallibleWriteable for Option<T> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer implementing FallibleWriteable
on Result<T, E>
, so that the caller can control the error type. Using Option
means the caller has to keep track of errors outside of this fallibility, because the handler will always receive the ZST.
Putting in draft because we might merge #4787 instead |
Replaced by #4787 Code backed up at https://github.com/sffc/omnicu/tree/archive/fallible-writeable |
Fixes #4741
We need something of this shape for at least two things I'm currently collaborating on: datetime formatting and freeform multi-placeholder patterns.
In this PR, I add a new trait
TryWriteable
, which is implemented onOption<T>
, with the following behavior: