use std::cell::RefCell;
#[derive(Debug, Default)]
pub struct Teleports {
targets: RefCell<Vec<(String, Vec<String>)>>,
}
impl Teleports {
#[must_use]
pub fn new() -> Teleports {
Teleports::default()
}
#[must_use]
pub fn get(&self, target: &str) -> Option<String> {
self.targets
.borrow()
.iter()
.find(|(t, _)| t == target)
.map(|(_, parts)| parts.concat())
}
#[must_use]
pub fn into_targets(self) -> Vec<(String, String)> {
self.targets
.into_inner()
.into_iter()
.map(|(t, parts)| (t, parts.concat()))
.collect()
}
fn reserve(&self, target: &str) -> usize {
let mut targets = self.targets.borrow_mut();
let parts = match targets.iter().position(|(t, _)| t == target) {
Some(i) => &mut targets[i].1,
None => {
targets.push((target.to_owned(), Vec::new()));
&mut targets.last_mut().expect("just pushed").1
}
};
parts.push(String::new());
parts.len() - 1
}
fn fill(&self, target: &str, index: usize, content: String) {
let mut targets = self.targets.borrow_mut();
if let Some((_, parts)) = targets.iter_mut().find(|(t, _)| t == target) {
parts[index] = content;
}
}
}
pub fn teleport_into(
out: &mut String,
teleports: &Teleports,
target: &str,
disabled: bool,
content: &dyn Fn(&mut String),
) {
out.push_str("<!--teleport start-->");
let index = teleports.reserve(target);
if disabled {
content(out);
teleports.fill(
target,
index,
"<!--teleport start anchor--><!--teleport anchor-->".to_owned(),
);
} else {
let mut moved = String::from("<!--teleport start anchor-->");
content(&mut moved);
moved.push_str("<!--teleport anchor-->");
teleports.fill(target, index, moved);
}
out.push_str("<!--teleport end-->");
}
#[cfg(test)]
mod tests;