dejavu-runtime 0.1.1

DejaVu shared types and runtime
Documentation
use core::fmt::{Display, Formatter, Write};

pub trait Escaper {
    fn write_escaped<W>(&self, fmt: W, string: &str) -> core::fmt::Result
    where
        W: Write;
}

#[derive(Debug)]
pub struct EscapeDisplay<E, T>
where
    E: Escaper,
    T: Display,
{
    value: DisplayValue<T>,
    escaper: E,
}

#[derive(Debug)]
pub struct EscapeWriter<'a, E, W> {
    fmt: W,
    escaper: &'a E,
}

#[derive(Debug)]
pub struct Escaped<'a, E>
where
    E: Escaper,
{
    string: &'a str,
    escaper: E,
}

impl<E, T> EscapeDisplay<E, T>
where
    E: Escaper,
    T: Display,
{
    pub fn dangerous(value: T, escaper: E) -> Self {
        Self { value: DisplayValue::Unsafe(value), escaper }
    }

    pub fn safe(value: T, escaper: E) -> Self {
        Self { value: DisplayValue::Safe(value), escaper }
    }

    #[must_use]
    pub fn mark_safe(mut self) -> EscapeDisplay<E, T> {
        self.value = match self.value {
            DisplayValue::Unsafe(t) => DisplayValue::Safe(t),
            _ => self.value,
        };
        self
    }
}

impl<E, T> Display for EscapeDisplay<E, T>
where
    E: Escaper,
    T: Display,
{
    fn fmt(&self, fmt: &mut Formatter<'_>) -> core::fmt::Result {
        match self.value {
            DisplayValue::Unsafe(ref t) => write!(EscapeWriter { fmt, escaper: &self.escaper }, "{t}"),
            DisplayValue::Safe(ref t) => t.fmt(fmt),
        }
    }
}

impl<E, W> Write for EscapeWriter<'_, E, W>
where
    W: Write,
    E: Escaper,
{
    fn write_str(&mut self, s: &str) -> core::fmt::Result {
        self.escaper.write_escaped(&mut self.fmt, s)
    }
}

pub fn escape<E>(string: &str, escaper: E) -> Escaped<'_, E>
where
    E: Escaper,
{
    Escaped { string, escaper }
}

impl<E> Display for Escaped<'_, E>
where
    E: Escaper,
{
    fn fmt(&self, fmt: &mut Formatter<'_>) -> core::fmt::Result {
        self.escaper.write_escaped(fmt, self.string)
    }
}

#[derive(Debug, PartialEq)]
enum DisplayValue<T>
where
    T: Display,
{
    Safe(T),
    Unsafe(T),
}