Skip to content

Instantly share code, notes, and snippets.

@DarinM223
Last active September 15, 2018 02:05
Show Gist options
  • Save DarinM223/7cebf527fe575b45deb7d27dbc1e9286 to your computer and use it in GitHub Desktop.
Save DarinM223/7cebf527fe575b45deb7d27dbc1e9286 to your computer and use it in GitHub Desktop.
Example of NonNull in Rust with a doubly linked list
use std::fmt::Debug;
use std::ptr::NonNull;
#[derive(Debug)]
pub struct DListNode<T: Debug> {
data: T,
next: Option<Box<DListNode<T>>>,
prev: Option<NonNull<DListNode<T>>>,
}
impl<T: Debug> DListNode<T> {
pub fn new(value: T) -> DListNode<T> {
DListNode {
data: value,
next: None,
prev: None,
}
}
}
impl<T: Debug> Drop for DListNode<T> {
fn drop(&mut self) {
println!("Dropping node: {:?}", *self);
}
}
pub struct DList<T: Debug> {
head: Box<DListNode<T>>,
tail: NonNull<DListNode<T>>,
}
impl<T: Debug> DList<T> {
pub fn from_value(value: T) -> DList<T> {
let mut head = Box::new(DListNode::new(value));
let tail = NonNull::new(&mut *head).unwrap();
DList { head, tail }
}
pub fn from_iterator<I>(iter: &mut I) -> Option<DList<T>>
where
I: Iterator<Item = T>,
{
let mut list = DList::from_value(iter.next()?);
for value in iter {
list.add(value);
}
Some(list)
}
pub fn add(&mut self, value: T) {
let mut next = Box::new(DListNode {
data: value,
next: None,
prev: Some(self.tail),
});
let next_ptr = NonNull::new(&mut *next).unwrap();
unsafe { self.tail.as_mut().next = Some(next) };
self.tail = next_ptr;
}
pub fn print(&self) {
print(&self.head);
}
}
pub fn remove<T: Debug>(mut node: DListNode<T>) {
let mut next = node.next.take();
let mut prev = node.prev.take();
if let Some(ref mut next) = next {
next.prev = prev;
}
if let Some(ref mut prev) = prev {
unsafe { prev.as_mut().next = next };
}
}
pub fn print<T: Debug>(node: &DListNode<T>) {
print!("{:?}", node.data);
if let Some(ref next) = node.next {
print!(" -> ");
print(next);
} else {
println!();
}
}
fn main() {
let list = DList::from_iterator(&mut vec![1, 2, 3].into_iter());
if let Some(mut list) = list {
list.print();
if let Some(next) = list.head.next.take() {
remove(*next);
list.print();
list.print();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment