#[derive(derive_more::Deref, derive_more::DerefMut)]
pub struct CodeFormatContext<'a> {
pub depth: usize,
#[deref]
#[deref_mut]
pub f: &'a mut dyn std::fmt::Write,
}
impl<'a> CodeFormatContext<'a> {
pub fn new(f: &'a mut dyn std::fmt::Write) -> Self {
Self { depth: 0, f }
}
pub fn indent(&mut self) -> std::fmt::Result {
let indent = self.depth * 4;
write!(self, "{:indent$}", "")
}
pub fn nest<F>(&mut self, f: F) -> std::fmt::Result
where
F: FnOnce(&mut Self) -> std::fmt::Result,
{
self.depth += 1;
let result = f(self);
self.depth -= 1;
result
}
}
pub trait CodeDisplay<'a, Context = CodeFormatContext<'a>> {
fn code_display(&self, f: &mut Context) -> std::fmt::Result;
}
impl<'a, T> CodeDisplay<'a> for T
where
T: std::fmt::Display,
{
fn code_display(&self, ctx: &mut CodeFormatContext) -> std::fmt::Result {
write!(ctx, "{self}")
}
}
pub struct CodeStack<'a, T>(pub &'a [T]);
pub struct CodeList<'a, T>(pub &'a [T]);
impl<'a, 'b, T> CodeDisplay<'a> for CodeList<'b, T>
where
T: CodeDisplay<'a>,
{
fn code_display(&self, f: &mut CodeFormatContext<'a>) -> std::fmt::Result {
self.0.iter().try_for_each(|item| {
item.code_display(f)?;
write!(f, ", ")
})
}
}
impl<'a, 'b, T> CodeDisplay<'a> for CodeStack<'b, T>
where
T: CodeDisplay<'a>,
{
fn code_display(&self, f: &mut CodeFormatContext<'a>) -> std::fmt::Result {
self.0.iter().try_for_each(|item| {
item.code_display(f)?;
writeln!(f)
})
}
}
#[macro_export]
macro_rules! code_display {
($f:expr => { $($body:expr)* }) => {
{
writeln!($f, "{{")?;
$f.nest(|f| {
$(
$body.code_display(f)?;
)*
Ok(())
})?;
$f.indent()?; write!($f, "}}")
}
};
($f:expr => $($arg:expr)*) => {
{
$(
$arg.code_display($f)?;
)*
Ok(())
}
};
}