use std::fmt;
use std::hash::{Hash, Hasher};
use std::rc::Rc;
#[derive(Clone, Default)]
pub struct Cactus<T> {
node: Option<Rc<Node<T>>>
}
#[derive(Clone)]
struct Node<T> {
val: T,
parent: Option<Rc<Node<T>>>
}
impl<T> Cactus<T> {
pub fn new() -> Cactus<T> {
Cactus{node: None}
}
pub fn is_empty(&self) -> bool {
self.node.is_none()
}
pub fn len(&self) -> usize {
self.vals().count()
}
pub fn child(&self, val: T) -> Cactus<T> {
Cactus {
node: Some(Rc::new(Node{val,
parent: self.node.clone()
}))
}
}
pub fn parent(&self) -> Option<Cactus<T>> {
self.node.as_ref()
.map(|n| Cactus{node: n.parent.clone()} )
}
pub fn val(&self) -> Option<&T> {
self.node.as_ref().map(|n| &n.val)
}
pub fn nodes(&self) -> CactusNodesIter<T> {
CactusNodesIter{next: self.node.as_ref()}
}
pub fn vals(&self) -> CactusValsIter<T> {
CactusValsIter{next: self.node.as_ref()}
}
pub fn try_unwrap(self) -> Result<T, Cactus<T>> {
match self.node {
None => Err(Cactus{node: None}),
Some(x) => {
match Rc::try_unwrap(x) {
Ok(n) => Ok(n.val),
Err(rc) => Err(Cactus{node: Some(rc)})
}
}
}
}
}
pub struct CactusNodesIter<'a, T> where T: 'a {
next: Option<&'a Rc<Node<T>>>
}
impl<'a, T> Iterator for CactusNodesIter<'a, T> {
type Item = Cactus<T>;
fn next(&mut self) -> Option<Self::Item> {
self.next.take().map(|n| {
self.next = n.parent.as_ref();
Cactus{node: Some(n.clone())}
})
}
}
pub struct CactusValsIter<'a, T> where T: 'a {
next: Option<&'a Rc<Node<T>>>
}
impl<'a, T> Iterator for CactusValsIter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.next.take().map(|n| {
self.next = n.parent.as_ref();
&n.val
})
}
}
impl<T: PartialEq> PartialEq for Cactus<T> {
fn eq(&self, other: &Cactus<T>) -> bool {
let mut si = self.node.as_ref();
let mut oi = other.node.as_ref();
while si.is_some() && oi.is_some() {
let sn = si.unwrap();
let on = oi.unwrap();
if Rc::ptr_eq(sn, on) {
return true;
}
if sn.val != on.val {
return false;
}
if let Some(n) = si.take() {
si = n.parent.as_ref();
}
if let Some(n) = oi.take() {
oi = n.parent.as_ref();
}
}
!(si.is_some() || oi.is_some())
}
}
impl<T: Eq> Eq for Cactus<T> {}
impl<T: Hash> Hash for Cactus<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
for v in self.vals() {
v.hash(state);
}
}
}
impl<T: fmt::Debug> fmt::Debug for Cactus<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Cactus[")?;
for (i, x) in self.vals().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{:?}", x)?;
}
write!(f, "]")
}
}
#[cfg(test)]
mod tests {
use std::collections::HashSet;
use std::collections::hash_map::DefaultHasher;
use super::*;
#[test]
fn test_simple() {
let r = Cactus::new();
assert!(r.is_empty());
assert_eq!(r.len(), 0);
assert!(r.val().is_none());
assert!(r.parent().is_none());
let r2 = r.child(2);
assert!(!r2.is_empty());
assert_eq!(r2.len(), 1);
assert_eq!(*r2.val().unwrap(), 2);
let r3 = r2.parent().unwrap();
assert_eq!(r3.is_empty(), true);
assert_eq!(r3.len(), 0);
let r4 = r.child(3);
assert_eq!(r4.len(), 1);
assert_eq!(*r4.val().unwrap(), 3);
let r5 = r4.parent().unwrap();
assert!(r5.is_empty());
let r6 = r4.child(4);
assert_eq!(r6.len(), 2);
assert_eq!(*r6.val().unwrap(), 4);
assert_eq!(*r6.parent().unwrap().val().unwrap(), 3);
}
#[test]
fn test_vals() {
let c = Cactus::new().child(3).child(2).child(1);
assert_eq!(c.vals().cloned().collect::<Vec<_>>(), [1, 2, 3]);
}
#[test]
fn test_vals_nodes() {
let c = Cactus::new().child(3).child(2).child(1);
assert_eq!(c.nodes().skip(1).next().unwrap(), Cactus::new().child(3).child(2));
assert_eq!(c.nodes().skip(2).next().unwrap(), Cactus::new().child(3));
}
#[test]
fn test_eq() {
let c1 = Cactus::new().child(1).child(2);
assert_eq!(c1, c1);
let c1_1 = c1.child(4);
let c1_2 = c1.child(4);
assert_eq!(c1_1, c1_2);
let c2 = Cactus::new().child(1).child(2);
assert_eq!(c1, c2);
assert!(!(c1 != c2));
let c3 = Cactus::new().child(2).child(2);
assert_ne!(c1, c3);
assert!(!(c1 == c3));
}
#[test]
fn test_debug() {
let c = Cactus::new().child(3).child(2).child(1);
assert_eq!(format!("{:?}", c), "Cactus[1, 2, 3]");
}
#[test]
fn test_try_unwrap() {
let c = Cactus::new().child(4).child(3);
let c1 = c.child(2);
let c2 = c.child(1);
assert_eq!(c2.try_unwrap(), Ok(1));
assert_eq!(c.try_unwrap().unwrap_or_else(|c| c.val().unwrap().clone()), 3);
assert_eq!(c1.try_unwrap(), Ok(2));
}
#[test]
fn test_hash() {
fn calculate_hash<T: Hash>(t: &T) -> u64 {
let mut s = DefaultHasher::new();
t.hash(&mut s);
s.finish()
}
let c1 = Cactus::new().child(4).child(3);
let c2 = Cactus::new().child(4).child(3);
assert_eq!(calculate_hash(&c1), calculate_hash(&c2));
let c3 = Cactus::new().child(3).child(4);
assert_ne!(calculate_hash(&c1), calculate_hash(&c3));
let mut s = HashSet::new();
s.insert(c1.clone());
s.insert(c2.clone());
assert_eq!(s.len(), 1);
assert_eq!(*s.iter().nth(0).unwrap(), c1);
assert_eq!(*s.iter().nth(0).unwrap(), c2);
}
}