#![no_std]
extern crate alloc;
use alloc::rc::Rc;
use core::cell::RefCell;
#[derive(Clone, Debug)]
pub struct DsuRoot<T> {
node: Rc<DsuNode<T>>,
}
impl<T> DsuRoot<T> {
pub fn new(value: T) -> Self {
Self {
node: Rc::new(DsuNode::new(value)),
}
}
pub fn same(lhs: &mut Self, rhs: &mut Self) -> bool {
lhs.move_to_root();
rhs.move_to_root();
Rc::ptr_eq(&lhs.node, &rhs.node)
}
pub fn value(&mut self) -> &T {
self.move_to_root();
&self.node.value
}
pub fn merge_into(&mut self, another: &mut Self) {
if Self::same(self, another) {
return;
}
debug_assert!(self.node.is_root());
debug_assert!(another.node.is_root());
self.node.set_parent(another.node.clone())
}
fn move_to_root(&mut self) {
self.node.compress_path();
if !self.node.is_root() {
self.node = self.node.parent().unwrap();
}
debug_assert!(self.node.is_root());
}
}
#[derive(Debug)]
struct DsuNode<T> {
parent: RefCell<Option<Rc<DsuNode<T>>>>,
value: T,
}
impl<T> DsuNode<T> {
fn new(value: T) -> Self {
Self {
parent: RefCell::new(None),
value,
}
}
fn is_root(&self) -> bool {
self.parent.borrow().is_none()
}
fn parent(&self) -> Option<Rc<DsuNode<T>>> {
(*self.parent.borrow()).clone()
}
fn set_parent(&self, parent: Rc<DsuNode<T>>) {
*self.parent.borrow_mut() = Some(parent);
}
fn compress_path(&self) {
let trivial = {
let parent_borrow = self.parent.borrow();
match &*parent_borrow {
Some(parent) => parent.is_root(),
None => true,
}
};
if trivial {
return;
}
let mut parent_borrow = self.parent.borrow_mut();
let parent_node = parent_borrow.as_ref().unwrap();
parent_node.compress_path();
*parent_borrow = Some(parent_node.parent().unwrap());
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec::Vec;
fn create_link_tree() -> Vec<Rc<DsuNode<i32>>> {
let mut nodes = Vec::with_capacity(10);
let root = Rc::new(DsuNode::new(0));
nodes.push(root.clone());
for i in 1..10usize {
let mut node = DsuNode::new(i as i32);
node.parent = RefCell::new(Some(nodes[i - 1].clone()));
nodes.push(Rc::new(node));
}
nodes
}
fn assert_path_compressed(nodes: &[Rc<DsuNode<i32>>]) {
let root = nodes[0].clone();
for i in 1..nodes.len() {
let parent = nodes[i].parent();
assert!(parent.is_some());
assert!(Rc::ptr_eq(parent.as_ref().unwrap(), &root));
}
}
mod dsu_node_tests {
use super::*;
#[test]
fn test_new() {
let node = DsuNode::new(10);
assert!(node.parent.borrow().is_none());
assert_eq!(node.value, 10);
}
#[test]
fn test_is_root_true() {
let node = DsuNode::new(10);
assert!(node.is_root());
}
#[test]
fn test_is_root_false() {
let mut node = DsuNode::new(10);
node.parent = RefCell::new(Some(Rc::new(DsuNode::new(20))));
assert!(!node.is_root());
}
#[test]
fn test_parent_root() {
let node = DsuNode::new(10);
assert!(node.parent().is_none());
}
#[test]
fn test_parent_non_root() {
let mut node = DsuNode::new(10);
let root = Rc::new(DsuNode::new(20));
node.parent = RefCell::new(Some(root.clone()));
let node_parent = node.parent();
assert!(node_parent.is_some());
assert!(Rc::ptr_eq(node_parent.as_ref().unwrap(), &root));
}
#[test]
fn test_set_parent() {
let node = DsuNode::new(10);
let parent = Rc::new(DsuNode::new(20));
node.set_parent(parent.clone());
assert!(node.parent.borrow().is_some());
assert!(Rc::ptr_eq(node.parent.borrow().as_ref().unwrap(), &parent));
}
#[test]
fn test_compress_path_root() {
let node = DsuNode::new(10);
node.compress_path();
assert!(node.parent.borrow().is_none());
}
#[test]
fn test_compress_path_root_child() {
let mut node = DsuNode::new(10);
let root = Rc::new(DsuNode::new(20));
node.parent = RefCell::new(Some(root.clone()));
node.compress_path();
assert!(node.parent.borrow().is_some());
assert!(Rc::ptr_eq(node.parent.borrow().as_ref().unwrap(), &root));
}
#[test]
fn test_compress_path_deep() {
let nodes = create_link_tree();
nodes.last().unwrap().compress_path();
assert_path_compressed(&nodes);
}
}
mod dsu_root_tests {
use super::*;
#[test]
fn test_new() {
let ptr = DsuRoot::new(10);
assert!(ptr.node.is_root());
assert_eq!(ptr.node.value, 10);
}
#[test]
fn test_same() {
let mut ptr_1 = DsuRoot::new(10);
let mut ptr_2 = DsuRoot::new(20);
assert!(!DsuRoot::same(&mut ptr_1, &mut ptr_2));
ptr_1.node.set_parent(ptr_2.node.clone());
assert!(DsuRoot::same(&mut ptr_1, &mut ptr_2));
}
#[test]
fn test_value_basic() {
let mut ptr = DsuRoot::new(10);
assert_eq!(*ptr.value(), 10);
}
#[test]
fn test_value_merged() {
let mut ptr = DsuRoot::new(10);
ptr.node.set_parent(Rc::new(DsuNode::new(20)));
assert_eq!(*ptr.value(), 20);
}
#[test]
fn test_merge_into_basic() {
let mut ptr = DsuRoot::new(10);
let mut root = DsuRoot::new(20);
ptr.merge_into(&mut root);
assert!(DsuRoot::same(&mut ptr, &mut root));
assert_eq!(*ptr.value(), 20);
}
#[test]
fn test_merge_into_root() {
let mut ptr = DsuRoot::new(10);
let mut root = DsuRoot::new(20);
ptr.node.set_parent(root.node.clone());
ptr.merge_into(&mut root);
assert_eq!(*ptr.value(), 20);
}
#[test]
fn test_merge_into_child() {
let mut ptr = DsuRoot::new(10);
let mut root = DsuRoot::new(20);
ptr.node.set_parent(root.node.clone());
root.merge_into(&mut ptr);
assert_eq!(*root.value(), 20);
}
#[test]
fn test_move_to_root() {
let nodes = create_link_tree();
let root = nodes[0].clone();
let mut ptr = DsuRoot {
node: nodes.last().unwrap().clone(),
};
ptr.move_to_root();
assert!(Rc::ptr_eq(&ptr.node, &root));
assert_path_compressed(&nodes);
}
}
}