#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RenderOptions {
pub pretty: bool,
pub indent: String,
pub xhtml_self_closing: bool,
}
impl Default for RenderOptions {
fn default() -> Self {
Self {
pretty: false,
indent: " ".to_string(),
xhtml_self_closing: false,
}
}
}
impl RenderOptions {
#[must_use]
pub fn compact() -> Self {
Self::default()
}
#[must_use]
pub fn pretty() -> Self {
Self {
pretty: true,
..Self::default()
}
}
#[must_use]
pub fn with_indent(mut self, indent: impl Into<String>) -> Self {
self.indent = indent.into();
self
}
#[must_use]
pub fn with_xhtml_self_closing(mut self, yes: bool) -> Self {
self.xhtml_self_closing = yes;
self
}
pub(crate) fn write_indent(&self, out: &mut String, depth: usize) {
for _ in 0..depth {
out.push_str(&self.indent);
}
}
}
pub trait Render {
fn write_into(&self, out: &mut String, options: &RenderOptions, depth: usize);
fn render(&self) -> String {
self.render_with(&RenderOptions::compact())
}
fn render_pretty(&self) -> String {
self.render_with(&RenderOptions::pretty())
}
fn render_with(&self, options: &RenderOptions) -> String {
let mut out = String::with_capacity(1024);
self.write_into(&mut out, options, 0);
out
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compact_is_the_default() {
let options = RenderOptions::default();
assert!(!options.pretty);
assert_eq!(options.indent, " ");
assert!(!options.xhtml_self_closing);
}
#[test]
fn the_indent_string_is_configurable() {
let options = RenderOptions::pretty().with_indent(" ");
let mut out = String::new();
options.write_indent(&mut out, 2);
assert_eq!(out, " ");
}
#[test]
fn options_have_value_semantics() {
let base = RenderOptions::compact();
let derived = base.clone().with_xhtml_self_closing(true);
assert!(!base.xhtml_self_closing);
assert!(derived.xhtml_self_closing);
}
}