use self::List::{Cons, Nil};
use std::cell::RefCell;
use std::rc::Rc;
use std::rc::Weak;

#[derive(Debug)]
enum List {
	Cons(i32, RefCell<Rc<List>>),
	Nil,
}

impl List {
	fn tail(&self) -> Option<&RefCell<Rc<List>>> {
		match *self {
			Cons(_, ref item) => Some(item),
			Nil => None,
		}
	}
}

pub fn ref_loop_demo() {
	let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));

	println!("a initial rc count = {}", Rc::strong_count(&a));
	println!("a next item = {:?}", a.tail());

	let b = Rc::new(Cons(10, RefCell::new(Rc::clone(&a))));

	println!("a rc count after b creation = {}", Rc::strong_count(&a));
	println!("b initial rc count = {}", Rc::strong_count(&b));
	println!("b next item = {:?}", b.tail());

	if let Some(link) = a.tail() {
		*link.borrow_mut() = Rc::clone(&b);
	}

	println!("b rc count after changing a = {}", Rc::strong_count(&b));
	println!("a rc count after changing a = {}", Rc::strong_count(&a));

	// Uncomment the next line to see that we have a cycle; it will soverflow the stack
	//println!("a next item = {:?}", a.tail());
}

#[derive(Debug)]
struct Node {
	value: i32,
	parent: RefCell<Weak<Node>>,
	children: RefCell<Vec<Rc<Node>>>,
}

pub fn weak_ref_demo() {
	let leaf = Rc::new(Node {
		value: 100,
		parent: RefCell::new(Weak::new()),
		children: RefCell::new(vec![]),
	});
	// None,1,0
	println!("leaf: value={} parent={:?} 强引用数={} 弱引用数={}",
	         leaf.value, leaf.parent.borrow().upgrade(),
	         Rc::strong_count(&leaf), Rc::weak_count(&leaf));

	{
		let branch = Rc::new(Node {
			value: 50,
			parent: RefCell::new(Weak::new()),
			children: RefCell::new(vec![]),
		});

		(*branch.children.borrow_mut()).push(Rc::clone(&leaf));
		*leaf.parent.borrow_mut() = Rc::downgrade(&branch);

		// branch,2,0
		println!("leaf: value={} parent={:#?} 强引用数={} 弱引用数={}",
		         leaf.value, leaf.parent.borrow().upgrade(),
		         Rc::strong_count(&leaf), Rc::weak_count(&leaf));
		// 1,1
		println!("branch: value={} 强引用数={} 弱引用数={}", branch.value, Rc::strong_count(&branch), Rc::weak_count(&branch));
	}

	// None,1,0
	println!("leaf: value={} parent={:?} 强引用数={} 弱引用数={}",
	         leaf.value, leaf.parent.borrow().upgrade(),
	         Rc::strong_count(&leaf), Rc::weak_count(&leaf));
}




