djc / askama

Type-safe, compiled Jinja-like templates for Rust
Apache License 2.0
3.35k stars 215 forks source link

Implemented display_some and display_some_or #1014

Open vallentin opened 4 months ago

vallentin commented 4 months ago

Resolves #1007

Questions:

Alternatively, we could also turn DisplaySome private, and then use:

fn display_some(...) -> askama::Result<impl fmt::Display + 'a>
Kijewski commented 4 months ago

I think we can omit the explicit lifetimes:

pub struct DisplaySome<T>(Option<T>);

impl<T: fmt::Display> fmt::Display for DisplaySome<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Some(val) = &self.0 {
            write!(f, "{val}")?;
        }
        Ok(())
    }
}

/// See [`display_some` in the Askama book] for more information.
///
/// See also [`display_some_or`].
///
/// [`display_some` in the Askama book]: https://djc.github.io/askama/filters.html#display_some
pub fn display_some<T: fmt::Display>(value: &Option<T>) -> Result<DisplaySome<&T>> {
    Ok(DisplaySome(value.as_ref()))
}

pub enum DisplaySomeOr<T, U> {
    Value(T),
    Otherwise(U),
}

impl<T: fmt::Display, U: fmt::Display> fmt::Display for DisplaySomeOr<T, U> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Value(val) => write!(f, "{val}"),
            Self::Otherwise(val) => write!(f, "{val}"),
        }
    }
}

/// See [`display_some_or` in the Askama book] for more information.
///
/// See also [`display_some`].
///
/// [`display_some_or` in the Askama book]: https://djc.github.io/askama/filters.html#display_some_or
pub fn display_some_or<T: fmt::Display, U: fmt::Display>(
    value: &Option<T>,
    otherwise: U,
) -> Result<DisplaySomeOr<&T, U>> {
    Ok(value
        .as_ref()
        .map_or(DisplaySomeOr::Otherwise(otherwise), DisplaySomeOr::Value))
}