summaryrefslogblamecommitdiff
path: root/rust-book/smart-pointers/src/main.rs
blob: 5a59f52edec88c84d0f969053ea173c1944957d9 (plain) (tree)









































































































































































































































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

//enum List {
//    Cons(i32, Rc<List>),
//    Nil,
//}

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

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

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

//enum List {
//    Cons(i32, Box<List>),
//    Nil,
//}

struct MyBox<T>(T);

impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> {
        MyBox(x)
    }
}

impl<T> Deref for MyBox<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.0
    }
}

struct CustomSmartPointer {
    data: String,
}

impl Drop for CustomSmartPointer {
    fn drop(&mut self) {
        println!("Dropped `{}`", self.data);
    }
}

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

fn main() {
//    let x = 5;
//    let y = MyBox::new(x);
//
//    assert_eq!(5, x);
//    assert_eq!(5, *y);

//    let m = MyBox::new(String::from("world"));
//    hello(&m);

//    let c = CustomSmartPointer { data: String::from("my stuff") };
//    drop(c);
//    let d = CustomSmartPointer { data: String::from("other stuff") };
//    println!("created.");

//    let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
//    dbg!(Rc::strong_count(&a));
//    let b = Cons(3, Rc::clone(&a));
//    dbg!(Rc::strong_count(&a));
//    {
//        let c = Cons(4, Rc::clone(&a));
//        dbg!(Rc::strong_count(&a));
//    }
//    dbg!(Rc::strong_count(&a));

//    let value = Rc::new(RefCell::new(5));
//
//    let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil)));
//
//    let b = Cons(Rc::new(RefCell::new(6)), Rc::clone(&a));
//    let c = Cons(Rc::new(RefCell::new(10)), Rc::clone(&a));
//
//    *value.borrow_mut() += 10;
//
//    dbg!(a);
//    dbg!(b);
//    dbg!(c);

//    let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));
//    dbg!(Rc::strong_count(&a));
//    dbg!(a.tail());
//    let b = Rc::new(Cons(10, RefCell::new(Rc::clone(&a))));
//    dbg!(Rc::strong_count(&a));
//    dbg!(Rc::strong_count(&b));
//    dbg!(b.tail());
//    
//    if let Some(link) = a.tail() {
//        *link.borrow_mut() = Rc::clone(&b);
//    }
//
//    dbg!(Rc::strong_count(&b));
//    dbg!(Rc::strong_count(&a));

    //dbg!(a.tail()); // stack overflow

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

    println!("leaf strong = {}, weak = {}", 
             Rc::strong_count(&leaf), 
             Rc::weak_count(&leaf),);

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

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

        println!(
            "branch strong = {}, weak = {}",
            Rc::strong_count(&branch),
            Rc::weak_count(&branch),
        );

        println!(
            "leaf strong = {}, weak = {}",
            Rc::strong_count(&leaf),
            Rc::weak_count(&leaf),
        );
    }

    println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
    println!(
        "leaf strong = {}, weak = {}",
        Rc::strong_count(&leaf),
        Rc::weak_count(&leaf),
    );
}

fn hello(name: &str) {
    println!("hiya {}", name);
}

pub trait Messenger {
    fn send(&self, msg: &str);
}

pub struct LimitTracker<'a, T: 'a + Messenger> {
    messenger: &'a T,
    value: usize,
    max: usize,
}

impl<'a, T> LimitTracker<'a, T> where T: Messenger {
    pub fn new(messenger: &T, max: usize) -> LimitTracker<T> {
        LimitTracker {
            messenger,
            value: 0,
            max,
        }
    }

    pub fn set_value(&mut self, value: usize) {
        self.value = value;

        let percentage_of_max = self.value as f64 / self.max as f64;

        if percentage_of_max >= 1.0 {
            self.messenger.send("over quota");
        }
        else if percentage_of_max >= 0.9 {
            self.messenger.send("90% of quota");
        }
        else if percentage_of_max >= 0.75 {
            self.messenger.send("75% of quota");
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::cell::RefCell;

    struct MockMessenger {
        sent_messages: RefCell<Vec<String>>,
    }

    impl MockMessenger {
        fn new() -> MockMessenger {
            MockMessenger { sent_messages: RefCell::new(vec![]) }
        }
    }

    impl Messenger for MockMessenger {
        fn send(&self, message: &str) {
            self.sent_messages.borrow_mut().push(String::from(message));
        }
    }

    #[test]
    fn sends_75() {
        let mock_messenger = MockMessenger::new();
        let mut limit_tracker = LimitTracker::new(&mock_messenger, 100);

        limit_tracker.set_value(80);

        assert_eq!(mock_messenger.sent_messages.borrow().len(), 1);
    }
}