I've tried to modify the code from rust-unofficial. Its an implementation of a queue. So far, I replaced direct pointer(*mut T) to directly using a mutable reference NotNull<T>
. But, NotNull::mut()
is an unsafe function and I have to still use the unsafe block. Is there any smart pointer other than NotNull that can make it safe?
use std::ptr::NonNull;
type Link<T> = Option<Box<Node<T>>>;
struct List<T> {
head: Link<T>, tail: Option<NonNull<Node<T>>>,
}
struct Node<T> {
elem: T, next: Link<T>,
}
impl<T> List<T> {
pub fn new() -> Self {
Self {
head: None, tail: None,
}
}
pub fn push(&mut self, elem: T) {
let mut new_node = Box::new(Node {elem, next: None });
let new_tail = Some(NonNull::from(new_node.as_mut()));
//if tail is empty, head is also empty and whole list is empty
if let Some(mut node) = self.tail.take() {
unsafe { node.as_mut().next = Some(new_node); }
} else {
self.head = Some(new_node);
}
self.tail = new_tail;
}
pub fn pop(&mut self) -> Option<T> {
self.head.take().map(|node| {
//i.e. if this node is removed the list will be empty
if node.next.is_none() {
self.tail = None;
} else {
self.head = node.next;
}
node.elem
})
}
}
fn main() {
let mut list = List::new();
assert_eq!(list.pop(), None);
list.push(1);
list.push(2);
list.push(3);
assert_eq!(list.pop().unwrap(), 1);
assert_eq!(list.pop().unwrap(), 2);
assert_eq!(list.pop().unwrap(), 3);
assert_eq!(list.pop(), None);
println!("ended");
}