Learn Rust With Entirely Too Many Linked Lists
15

Final Code

The complete module: generic over T, using Option<Box<Node<T>>>, with peek/peek_mut, IntoIter, Iter, and IterMut. Hand-written Drop carries over from Chapter 1. This is what a typical safe Rust collection looks like before you start optimizing.

  1. Read it top to bottom. Every method is now a one- to three-line operation on Option, Box, or a pointer cursor. There is no unsafe, no mem::replace, no custom enum.
    pub struct List<T> {
        head: Link<T>,
    }
    
    type Link<T> = Option<Box<Node<T>>>;
    
    struct Node<T> {
        elem: T,
        next: Link<T>,
    }
    
    impl<T> List<T> {
        pub fn new() -> Self {
            List { head: None }
        }
    
        pub fn push(&mut self, elem: T) {
            let new_node = Box::new(Node {
                elem,
                next: self.head.take(),
            });
            self.head = Some(new_node);
        }
    
        pub fn pop(&mut self) -> Option<T> {
            self.head.take().map(|node| {
                self.head = node.next;
                node.elem
            })
        }
    
        pub fn peek(&self) -> Option<&T> {
            self.head.as_ref().map(|node| &node.elem)
        }
    
        pub fn peek_mut(&mut self) -> Option<&mut T> {
            self.head.as_mut().map(|node| &mut node.elem)
        }
    
        pub fn into_iter(self) -> IntoIter<T> {
            IntoIter(self)
        }
    
        pub fn iter(&self) -> Iter<'_, T> {
            Iter { next: self.head.as_deref() }
        }
    
        pub fn iter_mut(&mut self) -> IterMut<'_, T> {
            IterMut { next: self.head.as_deref_mut() }
        }
    }
    
    impl<T> Drop for List<T> {
        fn drop(&mut self) {
            let mut cur = self.head.take();
            while let Some(mut node) = cur {
                cur = node.next.take();
            }
        }
    }
    
    pub struct IntoIter<T>(List<T>);
    
    impl<T> Iterator for IntoIter<T> {
        type Item = T;
        fn next(&mut self) -> Option<T> { self.0.pop() }
    }
    
    pub struct Iter<'a, T> {
        next: Option<&'a Node<T>>,
    }
    
    impl<'a, T> Iterator for Iter<'a, T> {
        type Item = &'a T;
        fn next(&mut self) -> Option<&'a T> {
            self.next.map(|node| {
                self.next = node.next.as_deref();
                &node.elem
            })
        }
    }
    
    pub struct IterMut<'a, T> {
        next: Option<&'a mut Node<T>>,
    }
    
    impl<'a, T> Iterator for IterMut<'a, T> {
        type Item = &'a mut T;
        fn next(&mut self) -> Option<&'a mut T> {
            self.next.take().map(|node| {
                self.next = node.next.as_deref_mut();
                &mut node.elem
            })
        }
    }