pub mod prelude {
pub use super::ShowOption as _;
pub use super::format_option;
}
use std::fmt::Display;
pub trait ShowOption<T> {
fn show_or<'t, O>(&'t self, otherwise: O) -> ShowOr<'t, T, O>;
fn show_prefixed_or<'t, P, O>(&'t self, prefix: P, otherwise: O) -> ShowPrefixedOr<'t, T, P, O>;
fn show_suffixed_or<'t, S, O>(&'t self, suffix: S, otherwise: O) -> ShowSuffixedOr<'t, T, S, O>;
fn show_surrounded_or<'t, P, S, O>(&'t self, prefix: P, suffix: S, otherwise: O) -> ShowSurroundedOr<'t, T, P, S, O>;
fn show_formatted_or<'t, F, O>(&'t self, format: F, otherwise: O) -> ShowFormattedOr<'t, T, F, O>;
}
impl<T> ShowOption<T> for Option<T> {
fn show_or<'t, O>(&'t self, otherwise: O) -> ShowOr<'t, T, O> {
ShowOr { option: self, otherwise }
}
fn show_prefixed_or<'t, P, O>(&'t self, prefix: P, otherwise: O) -> ShowPrefixedOr<'t, T, P, O> {
ShowPrefixedOr { option: self, prefix, otherwise }
}
fn show_suffixed_or<'t, S, O>(&'t self, suffix: S, otherwise: O) -> ShowSuffixedOr<'t, T, S, O> {
ShowSuffixedOr { option: self, suffix, otherwise }
}
fn show_surrounded_or<'t, P, S, O>(&'t self, prefix: P, suffix: S, otherwise: O) -> ShowSurroundedOr<'t, T, P, S, O> {
ShowSurroundedOr { option: self, prefix, suffix, otherwise }
}
fn show_formatted_or<'t, F, O>(&'t self, format: F, otherwise: O) -> ShowFormattedOr<'t, T, F, O> {
ShowFormattedOr { option: self, format, otherwise }
}
}
#[doc(hidden)]
pub struct ShowOr<'t, T, O> {
option: &'t Option<T>,
otherwise: O
}
impl<'t, T: Display, O: Display> Display for ShowOr<'t, T, O> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.option {
Some(value) => value.fmt(f),
None => self.otherwise.fmt(f),
}
}
}
#[doc(hidden)]
pub struct ShowPrefixedOr<'t, T, P, O> {
option: &'t Option<T>,
prefix: P,
otherwise: O,
}
impl<'t, T: Display, P: Display, O: Display> Display for ShowPrefixedOr<'t, T, P, O> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Some(value) = self.option else {
return self.otherwise.fmt(f);
};
self.prefix.fmt(f)?;
value.fmt(f)?;
Ok(())
}
}
#[doc(hidden)]
pub struct ShowSuffixedOr<'t, T, S, O> {
option: &'t Option<T>,
suffix: S,
otherwise: O,
}
impl<'t, T: Display, S: Display, O: Display> Display for ShowSuffixedOr<'t, T, S, O> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Some(value) = self.option else {
return self.otherwise.fmt(f);
};
value.fmt(f)?;
self.suffix.fmt(f)?;
Ok(())
}
}
#[doc(hidden)]
pub struct ShowSurroundedOr<'t, T, P, S, O> {
option: &'t Option<T>,
prefix: P,
suffix: S,
otherwise: O,
}
impl<'t, T: Display, P: Display, S: Display, O: Display> Display for ShowSurroundedOr<'t, T, P, S, O> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Some(value) = self.option else {
return self.otherwise.fmt(f);
};
self.prefix.fmt(f)?;
value.fmt(f)?;
self.suffix.fmt(f)?;
Ok(())
}
}
#[doc(hidden)]
pub struct ShowFormattedOr<'t, T, F, O> {
option: &'t Option<T>,
format: F,
otherwise: O,
}
impl<'t, T, D: 't + Display, F: Fn(&'t T) -> D, O: Display> Display for ShowFormattedOr<'t, T, F, O> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Some(value) = self.option else {
return self.otherwise.fmt(f);
};
(self.format)(value).fmt(f)?;
Ok(())
}
}
#[cfg(any(test, feature="macro"))]
#[macro_export]
macro_rules! format_option {
($option:expr, $format:literal, $default:expr) => {{
use $crate::ShowOption as _;
$option.show_formatted_or(|v| ::lazy_format::lazy_format!($format, v), $default)
}};
}
#[cfg(test)]
mod tests {
use super::ShowOption as _;
use std::fmt::Display;
use lazy_format::lazy_format;
#[test]
fn show_or() {
assert_eq!(Some(20).show_or("none").to_string(), "20");
assert_eq!(None::<usize>.show_or("none").to_string(), "none");
}
#[test]
fn show_prefixed_or() {
assert_eq!(Some(20).show_prefixed_or("set to ", "none").to_string(), "set to 20");
assert_eq!(None::<usize>.show_prefixed_or("set to ", "none").to_string(), "none");
}
#[test]
fn show_suffixed_or() {
assert_eq!(Some(20).show_suffixed_or(" bytes", "none").to_string(), "20 bytes");
assert_eq!(None::<usize>.show_suffixed_or(" bytes", "none").to_string(), "none");
}
#[test]
fn show_formatted_or() {
assert_eq!(Some(20).show_formatted_or(|v| lazy_format!("{v} bytes"), "none").to_string(), "20 bytes");
assert_eq!(None::<usize>.show_formatted_or(|v| lazy_format!("{v} bytes"), "none").to_string(), "none");
}
#[test]
fn format_option() {
assert_eq!(format!("{}", format_option!(Some(20), "{} bytes", "none")), "20 bytes");
assert_eq!(format!("{}", format_option!(None::<usize>, "{} bytes", "none")), "none");
}
#[test]
fn reuse() {
fn opt_bytes(v: &Option<usize>) -> impl Display + '_ {
v.show_suffixed_or(" bytes", "none")
}
assert_eq!(format!("received: {}", opt_bytes(&Some(20))), "received: 20 bytes");
}
}