use std::cell::RefCell;
use std::rc::Rc;
use crate::IndentedOptions;
type IOResult = std::result::Result<(), std::io::Error>;
type FmtResult = std::result::Result<(), std::fmt::Error>;
type RrcRoot<'a, Opt> = Rc<RefCell<Root<'a, Opt>>>;
type RrcInner<'a, Opt> = Rc<RefCell<Inner<'a, Opt>>>;
struct Root<'a, Opt: IndentedOptions<'a>> {
fmt: &'a mut (dyn std::io::Write + 'a),
options: &'a Opt,
pending_newline: bool,
sol: bool,
ind: &'a str,
subind: Vec<(usize, &'a str)>,
depth: usize,
}
impl<'a, Opt: IndentedOptions<'a>> Root<'a, Opt> {
fn new(fmt: &'a mut (dyn std::io::Write + 'a), ind: &'a str, options: &'a Opt) -> Self {
let subind = Vec::new();
Self {
fmt,
options,
pending_newline: false,
sol: true,
ind,
subind,
depth: 0,
}
}
fn push_indent(&mut self, depth: usize, ind: Option<&'a str>) {
self.pending_newline = true;
if let Some(ind) = ind {
self.subind.push((self.depth, ind));
}
self.depth = depth;
}
fn pop_indent(&mut self, depth: usize) {
self.pending_newline = true;
if let Some((d, _)) = self.subind.last() {
if *d == depth {
self.subind.pop();
}
}
self.depth = depth;
}
fn output_newline(&mut self) -> IOResult {
self.pending_newline = false;
if self.sol {
Ok(())
} else {
self.sol = true;
self.fmt.write_all(b"\n")
}
}
fn output_indent(&mut self) -> IOResult {
let sublen = self.subind.len();
let mut s = 0;
for i in 0..self.depth {
if s < sublen {
if self.subind[s].0 == i {
self.fmt.write_all(self.subind[s].1.as_bytes())?;
s += 1;
} else {
self.fmt.write_all(self.ind.as_bytes())?;
}
} else {
self.fmt.write_all(self.ind.as_bytes())?;
}
}
Ok(())
}
fn output_str(&mut self, s: &str) -> IOResult {
if s.is_empty() {
return Ok(());
}
if self.pending_newline {
self.output_newline()?;
}
if self.sol {
self.output_indent()?;
}
self.sol = false;
self.fmt.write_all(s.as_bytes())
}
fn complete(&mut self) {
if self.pending_newline {
let _ = self.output_newline();
}
}
}
impl<'a, Opt: IndentedOptions<'a>> std::fmt::Debug for Root<'a, Opt> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"Root[sol:{} depth: {}, ind:{:?}]",
self.sol, self.depth, self.ind
)
}
}
impl<'a, Opt: IndentedOptions<'a>> std::fmt::Write for Root<'a, Opt> {
fn write_str(&mut self, s: &str) -> FmtResult {
let mut output_newline = false;
for line in s.split('\n') {
if output_newline {
if self.output_newline().is_err() {
return Err(std::fmt::Error);
}
}
if self.output_str(line).is_err() {
return Err(std::fmt::Error);
}
output_newline = true;
}
Ok(())
}
}
#[derive(Debug)]
pub struct Inner<'a, Opt: IndentedOptions<'a>> {
root: RrcRoot<'a, Opt>,
parent: Option<RrcInner<'a, Opt>>,
depth: usize,
}
impl<'a, Opt: IndentedOptions<'a>> Drop for Inner<'a, Opt> {
fn drop(&mut self) {
if let Some(parent) = &self.parent {
let depth = parent.borrow().depth;
self.root.borrow_mut().pop_indent(depth);
} else {
self.root.borrow_mut().complete();
}
}
}
impl<'a, Opt: IndentedOptions<'a>> Inner<'a, Opt> {
fn root(root: RrcRoot<'a, Opt>) -> RrcInner<'a, Opt> {
Rc::new(RefCell::new(Self {
root: root,
parent: None,
depth: 0,
}))
}
fn subnode(s: &Rc<RefCell<Self>>, ind: Option<&'a str>) -> RrcInner<'a, Opt> {
let root = s.borrow().root.clone();
let parent = Some(s.clone());
let depth = s.borrow().depth + 1;
root.borrow_mut().push_indent(depth, ind);
Rc::new(RefCell::new(Self {
root,
parent,
depth,
}))
}
fn pop(self) -> Option<RrcInner<'a, Opt>> {
if let Some(parent) = &self.parent {
Some(parent.clone())
} else {
None
}
}
fn take_parent(s: Rc<RefCell<Self>>) -> RrcInner<'a, Opt> {
assert!(s.borrow().parent.is_some());
match Rc::try_unwrap(s) {
Err(_) => {
panic!("Indent was multiply borrowed");
}
Ok(x) => x.into_inner().pop().unwrap(),
}
}
}
pub struct Indenter<'a, Opt: IndentedOptions<'a>> {
node: RrcInner<'a, Opt>,
}
impl<'a, Opt: IndentedOptions<'a>> Indenter<'a, Opt> {
pub fn new(fmt: &'a mut (dyn std::io::Write + 'a), s: &'a str, options: &'a Opt) -> Self {
let r = Rc::new(RefCell::new(Root::new(fmt, s, options)));
let node = Inner::root(r);
Self { node }
}
pub fn sub(&self) -> Self {
let node = Inner::subnode(&self.node, None);
Self { node }
}
pub fn push(&self, s: &'a str) -> Self {
let node = Inner::subnode(&self.node, Some(s));
Self { node }
}
pub fn pop(self) -> Self {
let node = Inner::take_parent(self.node);
Self { node }
}
pub fn options(&self) -> &Opt {
&self.node.borrow().root.borrow().options
}
}
impl<'a, Opt: IndentedOptions<'a>> std::fmt::Write for Indenter<'a, Opt> {
fn write_str(&mut self, s: &str) -> FmtResult {
self.node.borrow().root.borrow_mut().write_str(s)
}
}