#[derive(Debug, Clone)]
pub enum Doc {
Atom(String),
Group {
open: String,
items: Vec<Doc>,
close: String,
},
}
impl Doc {
pub fn atom(text: impl Into<String>) -> Doc {
Doc::Atom(text.into())
}
pub fn group(open: impl Into<String>, items: Vec<Doc>, close: impl Into<String>) -> Doc {
Doc::Group {
open: open.into(),
items,
close: close.into(),
}
}
pub fn flat(&self) -> String {
match self {
Doc::Atom(text) => text.clone(),
Doc::Group { open, items, close } => {
let inner = items.iter().map(Doc::flat).collect::<Vec<_>>().join(", ");
format!("{open}{inner}{close}")
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn flat_renders_nested_groups_on_one_line() {
let doc = Doc::group(
"typing.Union[",
vec![
Doc::group(
"typing.Literal[",
vec![Doc::atom("\"a\""), Doc::atom("\"b\"")],
"]",
),
Doc::atom("typing.Any"),
],
"]",
);
assert_eq!(
doc.flat(),
"typing.Union[typing.Literal[\"a\", \"b\"], typing.Any]"
);
}
#[test]
fn flat_atom_is_verbatim() {
assert_eq!(Doc::atom("dt.datetime").flat(), "dt.datetime");
}
}