//! 智能指针
//! 指针(pointer)是一个通用的概念,它指代那些包含内存地址的变量。这个地址被用于索引,或者说用于“指向”内存中的其他数据。
//! 而智能指针(smart pointer)则是一些数据结构,它们的行为类似于指针但拥有额外的元数据和附加功能。String和Vec<T>就是智能指针。
//! 通常使用结构体来实现智能指针,但区别于一般结构体的地方在于它们会实现Deref和Drop这两个trait。
//! Deref trait使得智能指针结构体的实例拥有与引用一致的行为,它使你可以编写出能够同时用于引用和智能指针的代码。
//! Drop trait则使你可以自定义智能指针离开作用域时运行的代码。
use std::cell::RefCell;
use std::ops::Deref;
use std::rc::{Rc, Weak};

fn main() {
    weak_smart_pointer();
    circulate_quote();
    rc_and_ref_cell();
    refcell_smart_pointer();
    box_smart_pointer();
    pointer();
}

/// Weak<T>
///
/// 通过Rc::downgrade函数来创建出Rc<T>实例中值的弱引用。
/// 使用Rc<T>的引用来调用Rc::downgrade函数会返回一个类型为Weak<T>的智能指针,这一操作会让Rc<T>中的weak_count(弱引用计数)加1,而不会改变strong_count(强引用)的状态。
/// Rc<T>类型使用weak_count来记录当前存在多少个Weak<T>引用,这与strong_count有些类似。它们之间的差别在于,Rc<T>并不会执行清理操作前要求weak_count必须减为0。
///
/// 由于我们无法确定 Weak<T> 引用的值是否己经被释放了,所以我们需要在使用 Weak<T> 指向的值之前确保它依然存在。
/// 开发者可以调用 Weak<T> 实例的 upgrade() 来完成这一验证。
/// 此函数返回的 Option<RC<T>> 会在 RC<T> 值依然存在时表达为 Some,而在 RC<T> 值被释放时表达为 None。
/// 由于 upgrade() 返回的是Option<T>类型,所以 Rust 能够保证 Some 和 None两个分支都得到妥善的处理,而不会产生无效指针之类的问题。
///
/// 使用Weak<T>代替Rc<T>来避免循环引用
/// 强引用可以被用来共享一个Rc<T>实例的所有权,而弱引用则不会表达所有权关系。
/// 一旦强引用计数为0,任何弱引用组成的循环就会被打破。因此弱引用不会造成循环使用
fn weak_smart_pointer() {
    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));//打印强引用计数与弱引用计数
    println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());//调用Weak<T>实例的upgrade(),返回Option<T>来判断弱引用是否被释放。

    {
        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);//调用Rc::downgrade函数来获取Weak<T>弱引用。
        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());//调用Weak<T>实例的upgrade(),返回Option<T>来判断弱引用是否被释放。
    }
    println!("leaf strong = {},weak = {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf));//打印强引用计数与弱引用计数
    println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());//调用Weak<T>实例的upgrade(),返回Option<T>来判断弱引用是否被释放。

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

/// 循环引用
/// 循环引用会导致内存泄漏
fn circulate_quote() {
    let a = Rc::new(List::Cons(5, RefCell::new(Rc::new(List::Nil))));
    println!("a initial rc count = {}", Rc::strong_count(&a));
    println!("a next item = {:?}", a.tail());

    let b = Rc::new(List::Cons(10, RefCell::new(Rc::clone(&a))));
    println!("a initial 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 b = {}", Rc::strong_count(&a));

    // 取消下面的注释行可以观察到循环引用;它会造成栈的溢出。因为a、b的内部Rc<T>都是互相循环强引用,导致一直不能释放造成栈溢出。
    // println!("a next item = {:?}", a.tail());

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

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

/// 将RefCell<T>和RC<T>结合使用是一种很常见的用法。
/// RC<T>允许多个所有者持有同一数据,但只能提供针对数据的不可变访问。
/// 如果我们在RC<T>内存储了RefCell<T>,那么就可以定义出拥有多个所有者且能够进行修改的值了。
fn rc_and_ref_cell() {
    let value = Rc::new(RefCell::new(5));
    let a = Rc::new(List::Cons(Rc::clone(&value), Rc::new(List::Nil)));
    let b = List::Cons(Rc::new(RefCell::new(6)), Rc::clone(&a));
    let c = List::Cons(Rc::new(RefCell::new(10)), Rc::clone(&a));
    *value.borrow_mut() += 10;
    println!("a after = {:?}", a);
    println!("b after = {:?}", b);
    println!("c after = {:?}", c);
    #[derive(Debug)]
    enum List {
        Cons(Rc<RefCell<i32>>, Rc<List>),
        Nil,
    }
}

/// RefCell<T>和内部可变模式
///
/// 内部可变性(interior mutability)是 Rust 的设计模式之一,它允许你在只持有不可变引用的前提下对数据进行修改;
/// 通常而言,类似的行为会被借用规则所禁止。为了能够改变数据,内部可变性模式在它的数据结构中使用了unsafe (不安全)代码来绕过 Rust 正常的可变性和借用规则。
/// 假如我们能够保证自己的代码在运行时符合借用规则,那么就可以在即使编译器无法在编译阶段保证符合借用规则的前提下,也能使用那些采取了内部可变性模式的类型。
/// 实现过程中涉及的那些不安全代码会被妥善地封装在安全的 API 内,而类型本身从外部看来依然是不可变的。
///
/// RefCell<T>只能被用于单线程场景中。
/// 对于使用一般引用和 Box<T>的代码,Rust 会在编译阶段强制代码遵守借用规则。
/// 而对于使用 Refcell<T>的代码,Rust 则只会在运行时检查借用规则,并在出现违反借用规则的情況下触发 panic 来提前中止程序。
/// 下面是选择使用 Box<T>、 RC<T>还是Refcell<T>的依据:
/// 1) RC<T>允许一份数据有多个所有者,而Box<T>和Refcell<T>都只有一个所有者。
/// 2) Box<T>允许在编译时检查的可变或不可变借用,RC<T>仅允许编译时检查的不可变借用,Refcell<T>允许运行时检查的可变或不可变借用。
/// 3) 由于Refcell<T>允许我们在运行时检查可变借用,所以即便Refcell<T>本身是不可变的,我们仍然能够更改其中存储的值。
///
/// RefCell<T>运行机制,在运行时记录借用信息
/// 平时在创建不可变和可变引用时会分别使用语法&与&mut。
/// 对于RefCell<T>而言,我们需要使用borrow()与borrow_mut()来实现类似的功能,这两者都被作为RefCell<T>的安全接口来提供给用户。
/// borrow()与borrow_mut()会分别返回Ref<T>和RefMut<T>这两种智能指针。由于这两种智能指针都实现来Deref,所以开发者可以把它们当作一般的引用来对待。
/// RefCell<T>会记录当前存在多少个活跃的Ref<T>和RefMut<T>智能指针。每次调用borrow()时,RefCell<T>会将活跃的不可变借用计数加1,并且在任何一个Ref<T>的值离开作用域被释放时,不可变借用计数将减1。
/// RefCell<T>会基于这一技术来维护和编译器同样的借用检查规则:在任何一个给定的时间里,它只允许你拥有多个不可变引用或一个可变借用。
/// 当开发者违背借用规则时,相比于一般引用导致的编译错误,RefCell<T>的实现会在运行时触发panic。
fn refcell_smart_pointer() {
    let m = MockMessenger::new();
    let mut l = LimitTracker::new(&m, 100);
    l.set_value(80);

    impl Messenger for MockMessenger {
        fn send(&self, msg: &str) {
            // 如果Messenger结构体中的sent_messages值没有被RefCell<T>包裹的话,此处是不能直接修改sent_messages的值,因为&self是不可变引用。
            // 当Messenger结构体中的sent_messages值被RefCell<T>包裹后,就可以调用RefCell<T>的borrow_mut()获取内部值的可变引用进行修改。
            let mut ref_mut = self.sent_messages.borrow_mut();
            ref_mut.push(String::from(msg));// 调用RefCell<T>的borrow_mut()可以获取到内部值的可变引用
            println!("sent_messages_len: {}", ref_mut.len());

            // 当在同一作用域中调用两次borrow_mut()或borrow(),虽然代码编译期通过,但运行时会使RefCell<T>引发panic,因为这违背了借用规则。
            // let mut ref_ = self.sent_messages.borrow();// 调用RefCell<T>的borrow()可以获取到内部值的不可变引用
        }
    }

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

    impl MockMessenger {
        fn new() -> Self {
            Self {
                sent_messages: RefCell::new(vec![])
            }
        }
    }
    pub trait Messenger {
        fn send(&self, msg: &str);
    }

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

    impl<'a, T> LimitTracker<'a, T> where T: Messenger {
        pub fn new(messenger: &'a T, max: usize) -> Self {
            Self {
                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("Error: You are over your quota!");
            } else if percentage_of_max >= 0.9 {
                self.messenger.send("Urgent warning: You've used up over 90% of your quota!");
            } else if percentage_of_max >= 0.75 {
                self.messenger.send("Warning: You've used up over 75% of your quota!");
            }
        }
    }
}

/// 基于引用计数的智能指针Rc<T>
/// 所有权在大多数情况下都是清晰的:对于一个给定的值,可以准确地判断出哪个变量拥有它。但在某些场景中,单个值也可能同时被多个所有者持有。
/// Rust提供了一个名为RC<T>的类型来支持多重所有权,它名称中的RC是Reference counting(引用计数)的缩写。
/// RC<T>类型的实例会在内部维护一个用于记录值引用次数的计数器,从而确认这个值是否仍在使用。
/// 如果对一个值的引用次数为零,那么就意味着这个值可以被安全地清理掉,而不会触发引用失效的问题。
/// 引用计数机制保证了值会在其拥有的所有者存活时一直有效,并在所有者全部离开作用域时被自动清理。
/// Rc<T>通过不可变引用使开发者在程序的不同部分之间共享只读数据。
/// 需要注意的是,Rc<T>只能被用于单线程场景中。
fn rc_smart_pointer() {
    use crate::RcList::{Cons, Nil};
    let rc_list = Rc::new(Cons(2, Rc::new(Cons(3, Rc::new(Nil)))));
    // 调用Rc::clone()只会增加引用计数不会深度拷贝,如果调用实例的clone()会进行深度拷贝。
    // 每调用一次Rc::clone(),被克隆的实例引用计数就会增加一次。
    // 调用Rc::strong_count()可以查看实例被强引用的次数。
    let a = Cons(1, Rc::clone(&rc_list));// 调用Rc::clone(&rc_list),此处变量rc_list的引用计数为1
    println!("var a Rc::clone(&rc_list) Rc::strong_count(&rc_list):{}", Rc::strong_count(&rc_list));// 调用Rc::strong_count()读取实例的引用计数,此处rc_list的引用计数为1
    {
        let b = Cons(0, Rc::clone(&rc_list));// 调用Rc::clone(&rc_list),此处变量rc_list的引用计数为2
        println!("var b Rc::clone(&rc_list) Rc::strong_count(&rc_list):{}", Rc::strong_count(&rc_list));// 调用Rc::strong_count()读取实例的引用计数,此处rc_list的引用计数为2
    }//因为变量b离开了作用域被销毁,Rc<T>的Drop实现会在Rc<T>离开作用域时自动将引用计数减1,所以此处变量rc_list的引用计数为1
    println!("Rc::clone(&rc_list) Rc::strong_count(&rc_list):{}", Rc::strong_count(&rc_list));// 调用Rc::strong_count()读取实例的引用计数,此处rc_list的引用计数为1
}

/// 智能指针Box<T>
/// 装箱Box<T>是最简单直接的一种智能指针,数据存储在堆上,常常被用于下面的场景:
/// 1)当你拥有一个无法在编译时确定大小的类型,但又想要在一个要求固定尺寸但上下文环境中使用这个类型但值时。
/// 2)当你需要传递大量数据的所有权,但又不希望产生大量数据的复制行为时。
/// 3)当你希望拥有一个实现了指定trait的类型值,但又不关心具体的类型时。
fn box_smart_pointer() {
    use crate::List::{Cons, Nil};
    let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
    println!("box_smart_pointer: {:#?}", list);

    let x = 5;
    let y = MyBox::new(x);
    // 因为MyBox实现了Deref trait,所以使用解引用运算符(*)时,Rust会隐式调用deref(&self)。
    // 在没有Deref trait的情形下,编译器只能对&形式的常规引用执行解引用操作。deref方法使编译器可以从任何实现了Deref的类型中获取值,并能够调用deref方法来获得一个可以进行解引用操作的引用。
    println!("box_smart_pointer: {}", x == *y);// 这里的 *y 等价于 *(y.deref()),需要注意,这种将*运算符替换为*(x.deref())的过程,对代码中的每个*都只会进行一次,不会无穷尽的递归替换下去。

    let my_box_string = MyBox::new(String::from("解引用转换"));
    // 因为MyBox实现了Deref trait,所以当提供的参数与函数或方法参数类型不一致时,编译器会插入一系列的deref方法调用来将我们提供的类型转换为参数所需的类型。
    // &my_box_string是&MyBox<String>,Rust会先调用deref()转换成&String,又因为String类型也实现了Deref trait且当前转换还未满足函数参数类型所需,所以Rust继续将&String调用deref()转换为&str。
    deref_coercion(&my_box_string);// 这里的 &my_box_string 等价于 &(*my_box_string)[..],注意这里的等价只是说明如果MyBox没有实现Deref trait的写法。

    //该函数执行完毕后,所有实现了Drop trait的类型,会自动调用drop()
    //如果想要提前释放某个类型的实例,需要手动调用std::mem::drop
    println!("提前释放执行前");
    drop(y);
    println!("提前释放执行完毕");
}

/// 解引用转换
/// Rust为函数和方法的参数提供了一种便捷特性。
/// 当某个类型T实现了Deref trait时,它能够将T的引用转换为T经过Deref操作后生成的作用。
/// 当我们将某个特定类型的值引用作为参数传递给函数或方法,但传入的类型与参数类型不一致时,解引用转换就会自动发生。
/// 编译器会插入一系列的deref方法调用来将我们提供的类型转换为参数所需的类型。
///
/// 解引用转换与可变性
/// 使用Deref trait能够重载不可变引用的*运算符。与之类似,使用DerefMut trait能够重载可变引用的*运算符。
/// Rust会在类型与trait满足下面3种情形时执行解引用转换:
/// 1)当T: Deref<Target = U> 时,允许&T转换为&U。
/// 2)当T: DerefMut<Target = U> 时,允许&mut T转换为&mut U。
/// 3)当T: Deref<Target = U> 时,允许&mut T转换为&U。
fn deref_coercion(str: &str) {
    println!("deref_coercion: {}", str);
}

/// 普通指针
fn pointer() {
    let x = 5;
    //通过引用运算符(&)将x的地址赋值给y,换句话说,y借用了x,y存储的是x的地址
    let y = &x;
    // 通过解引用运算符(*)跟踪数据的引用
    println!("pointer: {}", x == *y);
}

/// 链接列表
#[derive(Debug)]
enum List<T> {
    // Cons(T, List<T>) 这样写无法通过编译,因为它产生来递归类型,拥有无限的大小,Rust无法确定具体的大小
    // 可以通过Box<T>来将递归类型的大小固定下来
    Cons(T, Box<List<T>>),
    Nil,
}

#[derive(Debug)]
enum RcList<T> {
    Cons(T, Rc<RcList<T>>),
    Nil,
}

/// 定义自己的智能指针
struct MyBox<T> (T);

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

/// 将自定义智能指针实现Deref trait
impl<T> Deref for MyBox<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

/// 将自定义智能指针实现Drop trait
impl<T> Drop for MyBox<T> {
    /// 当某个类型实现了Drop trait后,这个类型的实例离开作用域后,Rust会自动调用drop()
    /// Rust不允许开发者手动调用Drop trait的drop(),也不允许开发者禁用
    fn drop(&mut self) {
        println!("MyBox离开作用域自动调用drop()");
    }
}