rust-unofficial / too-many-lists

Learn Rust by writing Entirely Too Many linked lists
https://rust-unofficial.github.io/too-many-lists/
MIT License
3.16k stars 276 forks source link

first-drop.html needs small clarification. #292

Open rbarghou opened 9 months ago

rbarghou commented 9 months ago

I'm not skilled enough with Rust yet to understand the nature of the errors, but the code provided in the first-drop.html is no longer accurate.

I've followed the tutorial as closely as possible and checked as much as possible

I'm using rustc version 1.74.0

Here is my main.rs

use std::mem;

pub struct List {
    head: Link,
}

enum Link {
    Empty,
    More(Box<Node>),
}

struct Node {
    elem: i32,
    next: Link,
}

impl List {
    pub fn new() -> Self {
        List { head: Link::Empty }
    }

    pub fn push(&mut self, elem: i32) {
        let new_node = Box::new(Node {
            elem: elem,
            next: mem::replace(&mut self.head, Link::Empty)
        });
        self.head = Link::More(new_node);
    }

    pub fn pop(&mut self) -> Option<i32> {
        match mem::replace(&mut self.head, Link::Empty) {
            Link::Empty => None,
            Link::More(node) => {
                self.head = node.next;
                Some(node.elem)
            }
        }
    }
}

// impl Drop for List {
//     fn drop(&mut self) {
//         println!("Dropping List");
//     }
// }

impl Drop for List {
    fn drop(&mut self) {
        let mut cur_link = mem::replace(&mut self.head, Link::Empty);
        // `while let` == "do this thing until this pattern doesn't match"
        while let Link::More(mut boxed_node) = cur_link {
            cur_link = mem::replace(&mut boxed_node.next, Link::Empty);
            // boxed_node goes out of scope and gets dropped here;
            // but its Node's `next` field has been set to Link::Empty
            // so no unbounded recursion occurs.
        }
    }
}

impl Drop for Link {
    fn drop(&mut self) {
        match *self {
            Link::Empty => {}
            Link::More(ref mut boxed_node) => {
                boxed_node.drop();
            }
        }
    }
}

impl Drop for Box<Node> {
    fn drop(&mut self) {
        self.ptr.drop();
        deallocate(self.ptr);
    }
}

impl Drop for Node {
    fn drop(&mut self) {
        println!("Dropping Node");
        self.next.drop();
    }
}

fn main() {
    println!("Hello, world!");
}

#[cfg(test)]
mod test {
    use super::List;

    #[test]
    fn basics() {
        let mut list = List::new();
        assert_eq!(list.pop(), None);

        list.push(1);
        list.push(2);
        list.push(3);

        assert_eq!(list.pop(), Some(3));
        assert_eq!(list.pop(), Some(2));

        list.push(4);
        list.push(5);

        assert_eq!(list.pop(), Some(5));
        assert_eq!(list.pop(), Some(4));

        assert_eq!(list.pop(), Some(1));
        assert_eq!(list.pop(), None);
    }
}

Here is the output of the cargo build

➜  toomanylists git:(master) ✗ cargo build
   Compiling toomanylists v0.1.0 (/Users/ramseybarghouti/rust-too-many-lists/toomanylists)
error[E0119]: conflicting implementations of trait `Drop` for type `Box<Node>`
  --> src/main.rs:59:1
   |
59 | impl Drop for Box<Node> {
   | ^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: conflicting implementation in crate `alloc`:
           - impl<T, A> Drop for Box<T, A>
             where A: Allocator, T: ?Sized;

error[E0120]: the `Drop` trait may only be implemented for local structs, enums, and unions
  --> src/main.rs:59:15
   |
59 | impl Drop for Box<Node> {
   |               ^^^^^^^^^ must be a struct, enum, or union in the current crate

error[E0425]: cannot find function `deallocate` in this scope
  --> src/main.rs:62:9
   |
62 |         deallocate(self.ptr);
   |         ^^^^^^^^^^ not found in this scope

Some errors have detailed explanations: E0119, E0120, E0425.
For more information about an error, try `rustc --explain E0119`.

I think that what's intended in this tutorial is to only implement the Drop trait on the List Struct and not implement the Drop trait on List, Box<Node> and Node types, but I'm not sure. If that's the case I think this page simply needs some clarification.