use std::fmt;
use crate::iterator;
use std::rc::Rc;
use std::collections::HashMap;
pub struct Node<T> {
children: Vec<Node<T>>,
obj: Option<Rc<T>>,
text: Option<String>,
}
struct AffectedNode {
node_index: usize,
start: usize,
end: usize,
completely_enclosed: bool,
}
impl<T> Node<T> {
pub fn new_leaf(text: String, obj: Option<Rc<T>>) -> Node<T> {
Node {
children: Vec::new(),
obj,
text: Some(text),
}
}
pub fn new() -> Node<T> {
Node {
children: Vec::new(),
obj: None,
text: None,
}
}
pub fn is_leaf(&self) -> bool {
self.children.is_empty()
}
pub fn add_child(&mut self, child: Node<T>) {
self.children.push(child);
}
pub fn text(&self) -> String {
if self.is_leaf() {
self.text.as_ref().unwrap().to_string()
} else {
let mut result = String::with_capacity(self.length());
for child in &self.children {
result.push_str(&child.text());
}
result
}
}
pub fn length(&self) -> usize {
if self.is_leaf() {
self.text.as_ref().unwrap().len()
} else {
let mut result = 0;
for child in &self.children {
result += child.length();
}
result
}
}
pub fn obj(&self) -> Option<&Rc<T>> {
assert!(!self.is_leaf());
self.obj.as_ref()
}
pub fn set(&mut self, start_idx: usize, end_idx: usize, obj: Rc<T>) -> Option<Vec<Node<T>>> {
assert!(start_idx < end_idx);
if self.is_leaf() {
self.set_on_leaf(start_idx, end_idx, obj)
} else {
self.set_on_node(start_idx, end_idx, obj);
None
}
}
fn set_on_node(&mut self, mut start_idx: usize, end_idx: usize, obj: Rc<T>) {
let mut offset = 0;
let mut affected_children = Vec::new();
for i in 0..self.children.len() {
let child = &self.children[i];
let length = child.length();
if start_idx >= offset && start_idx <= offset + length {
let end = if end_idx <= offset + length { end_idx - offset } else { length };
let completely_enclosed = start_idx == offset && end == length;
affected_children.push(AffectedNode {
node_index: i,
start: start_idx - offset,
end,
completely_enclosed,
});
if end_idx <= offset + length {
break;
}
start_idx = offset + length;
}
offset += length;
}
let mut replace_later = HashMap::new();
let completely_enclosed: Vec<&AffectedNode> = affected_children.iter().filter(|a| a.completely_enclosed).collect();
if completely_enclosed.len() >= 2 {
let mut parent = Node::new();
parent.obj = Some(Rc::clone(&obj));
let mut removed_count = 0;
for a in &completely_enclosed {
parent.add_child(self.children.remove(a.node_index - removed_count));
removed_count += 1;
}
self.children.insert(completely_enclosed.first().as_ref().unwrap().node_index, parent);
affected_children = affected_children.into_iter().filter(|a| !a.completely_enclosed).collect();
}
for i in 0..affected_children.len() {
let affected = &affected_children[i];
let child = &mut self.children[affected.node_index];
if let Some(replace_with) = child.set(affected.start, affected.end, Rc::clone(&obj)) {
replace_later.insert(i, replace_with);
}
}
for (idx, replace_with) in replace_later {
self.children.remove(idx);
let mut i = 0;
for node in replace_with {
self.children.insert(idx + i, node);
i += 1;
}
}
}
fn set_on_leaf(&mut self, start_idx: usize, end_idx: usize, obj: Rc<T>) -> Option<Vec<Node<T>>> {
let text = self.text.take().unwrap();
let length = text.len();
let has_obj = self.obj.is_some();
assert!(start_idx <= length);
assert!(end_idx <= length);
if start_idx == 0 && end_idx == length {
self.obj = Some(obj);
if has_obj {
self.add_child(Node::new_leaf(text, None));
} else {
self.text = Some(text);
}
None
} else if start_idx == 0 {
let left_node = Node::new_leaf(String::from(&text[0..end_idx]), Some(obj));
let right_node = Node::new_leaf(String::from(&text[end_idx..length]), None);
if has_obj {
self.add_child(left_node);
self.add_child(right_node);
None
} else {
Some(vec!(left_node, right_node))
}
} else if end_idx == length {
let left_node = Node::new_leaf(String::from(&text[0..start_idx]), None);
let right_node = Node::new_leaf(String::from(&text[start_idx..length]), Some(obj));
if has_obj {
self.add_child(left_node);
self.add_child(right_node);
None
} else {
Some(vec!(left_node, right_node))
}
} else {
let left_node = Node::new_leaf(String::from(&text[0..start_idx]), None);
let middle_node = Node::new_leaf(String::from(&text[start_idx..end_idx]), Some(obj));
let right_node = Node::new_leaf(String::from(&text[end_idx..length]), None);
if has_obj {
self.add_child(left_node);
self.add_child(middle_node);
self.add_child(right_node);
None
} else {
Some(vec!(left_node, middle_node, right_node))
}
}
}
pub fn insert(&mut self, idx: usize, ch: char) {
if self.is_leaf() {
let length = self.length();
if idx >= length {
panic!("Cannot insert at position {} when underlying text has length {}", idx, length);
}
self.text.as_mut().unwrap().insert(idx, ch);
} else {
let mut offset = 0;
for child in &mut self.children {
let length = child.length();
if idx <= offset + length {
child.insert(idx - offset, ch);
break;
}
offset += child.length();
}
}
}
pub fn insert_str(&mut self, idx: usize, string: &str) {
if self.is_leaf() {
let length = self.length();
if idx > length {
panic!("Cannot insert at position {} when underlying text has length {}", idx, length);
}
self.text.as_mut().unwrap().insert_str(idx, string);
} else {
let mut offset = 0;
for child in &mut self.children {
let length = child.length();
if idx <= offset + length {
child.insert_str(idx - offset, string);
break;
}
offset += child.length();
}
}
}
pub fn push(&mut self, ch: char) {
if self.is_leaf() {
self.text.as_mut().unwrap().push(ch);
} else {
self.children.last_mut().unwrap().push(ch);
}
}
pub fn push_str(&mut self, string: &str) {
if self.is_leaf() {
self.text.as_mut().unwrap().push_str(string);
} else {
self.children.last_mut().unwrap().push_str(string);
}
}
pub fn child_count(&self) -> usize {
self.children.len()
}
pub fn children(&self) -> &[Node<T>] {
&self.children[..]
}
pub fn pre_order_iter(&self) -> iterator::PreOrder<T> {
iterator::PreOrder::new(self)
}
pub fn leaf_iter(&self) -> impl Iterator<Item=iterator::Item<T>> {
self.pre_order_iter().filter(|item| item.node.is_leaf())
}
}
impl<T> fmt::Debug for Node<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for iterator::Item { node, level } in self.pre_order_iter() {
if node.is_leaf() {
writeln!(f, "{spacing}|-- '{text}'{format}", spacing = " ".repeat(level * 4), text = node.text(), format = if node.obj.is_some() { " #" } else { "" })?;
} else {
writeln!(f, "{spacing}|---o ('{text}'){format}", spacing = " ".repeat(level * 4), text = node.text(), format = if node.obj.is_some() { " #" } else { "" })?;
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::Node;
#[test]
fn insert_char_one_level() {
let mut node: Node<()> = Node::new_leaf(String::from("Hello"), None);
node.insert(2, 'b');
assert_eq!(node.text(), "Hebllo");
}
#[test]
#[should_panic]
fn insert_char_panic() {
let mut node: Node<()> = Node::new_leaf(String::from("Hello"), None);
node.insert(6, 's');
}
#[test]
fn insert_char_multiple_levels() {
let mut root: Node<()> = Node::new();
root.add_child(Node::new_leaf(String::from("Hello "), None));
root.add_child(Node::new_leaf(String::from("World"), None));
root.insert(3, 'X');
root.insert(9, 'Z');
assert_eq!(root.text(), "HelXlo WoZrld");
}
#[test]
fn insert_string_one_level() {
let mut node: Node<()> = Node::new_leaf(String::from("Hello"), None);
node.insert_str(3, "TEST");
assert_eq!(node.text(), "HelTESTlo");
}
#[test]
#[should_panic]
fn insert_string_panic() {
let mut node: Node<()> = Node::new_leaf(String::from("Hello"), None);
node.insert_str(233, "wefewf");
}
#[test]
fn insert_string_multiple_levels() {
let mut root: Node<()> = Node::new();
root.add_child(Node::new_leaf(String::from("Hello "), None));
root.add_child(Node::new_leaf(String::from("World"), None));
root.insert_str(3, "XXXX");
root.insert_str(12, "ZZZZ");
assert_eq!(root.text(), "HelXXXXlo WoZZZZrld");
}
#[test]
fn push_string() {
let mut root: Node<()> = Node::new();
let child1: Node<()> = Node::new_leaf(String::from("Hello "), None);
root.add_child(child1);
let mut child2: Node<()> = Node::new();
let subchild1: Node<()> = Node::new_leaf(String::from("Wor"), None);
let subchild2: Node<()> = Node::new_leaf(String::from("ld"), None);
child2.add_child(subchild1);
child2.add_child(subchild2);
root.add_child(child2);
root.push_str("! I am a pushed string!");
assert_eq!(root.text(), "Hello World! I am a pushed string!");
}
#[test]
fn push_char() {
let mut root: Node<()> = Node::new();
let mut child1: Node<()> = Node::new();
let subchild1: Node<()> = Node::new_leaf(String::from("Hel"), None);
let subchild2: Node<()> = Node::new_leaf(String::from("lo "), None);
child1.add_child(subchild1);
child1.add_child(subchild2);
root.add_child(child1);
let mut child2: Node<()> = Node::new();
let subchild1: Node<()> = Node::new_leaf(String::from("Wor"), None);
let subchild2: Node<()> = Node::new_leaf(String::from("ld"), None);
let subchild3: Node<()> = Node::new_leaf(String::from("!"), None);
child2.add_child(subchild1);
child2.add_child(subchild2);
child2.add_child(subchild3);
root.add_child(child2);
root.push('!');
assert_eq!(root.text(), "Hello World!!");
}
}