實現Linux內核中的list_head。
Linux內核中List Head是一種雙向鏈表,可將任意類型鏈接起來,有點類似泛型又勝過泛型。常見用法是這樣的:
自定義一種類型:
struct Demo {
...
struct list_head head;
...
}
通過head將Demo類型鏈接起來,在需要的時候通過head指針結合container_of()找回Demo。
Rust實現有幾個點:
一、previous和next分別用什麼類型表示。
二、初始化如何保證head.prev和head.next都指向自己。
第一個問題:用裸指針。
第二個問題:先move,再borrow,得到reference地址。注意每次move都會導致對象地址不同。
第二個問題導致了list head初始化需要兩步:先new,再init,不得不說再這個問題上沒有C來得優雅。
#![allow(dead_code)]
use std::ptr;
fn _list_add<T>(new: *mut ListHead<T>, prev: *mut ListHead<T>, next: *mut ListHead<T>) {
unsafe {
(*next).prev = new;
(*new).next = next;
(*new).prev = prev;
(*prev).next = new;
}
}
fn _list_del<T>(prev: *mut ListHead<T>, next: *mut ListHead<T>) {
unsafe {
(*next).prev = prev;
(*prev).next = next;
}
}
fn _list_del_entry_valid<T>(_entry: &mut ListHead<T>) -> bool {
// TODO:
return true;
}
fn _list_del_entry<T>(entry: &mut ListHead<T>) {
if _list_del_entry_valid(entry) {
return;
}
_list_del(entry.prev, entry.next);
}
fn list_replace<T>(old: &mut ListHead<T>, new: &mut ListHead<T>) {
unsafe {
new.next = old.next;
(*new.next).prev = new;
new.prev = old.prev;
(*new.prev).next = new;
}
}
fn list_is_last<T>(list: &mut ListHead<T>, head: &mut ListHead<T>) -> bool {
return list.next == head;
}
// TODO: needs const
fn list_empty<T>(head: &mut ListHead<T>) -> bool {
return head.next == head.prev;
}
/// head -> item -> item -> item -> tail
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ListHead<T> {
v: T,
prev: *mut ListHead<T>,
next: *mut ListHead<T>,
}
/// usage
/// ```
/// use linked_list::ListHead;
/// let mut head = ListHead::new(1);
/// head.init();
/// head.add(&mut ListHead::new(2));
/// head.add_tail(&mut ListHead::new(3));
/// assert_eq!(head.at(1).value(), 2);
/// ```
impl<T> ListHead<T> {
pub fn new(v: T) -> Self {
let head = ListHead {
v,
prev: ptr::null_mut(),
next: ptr::null_mut(),
};
head
}
pub fn value(&self) -> &T {
&self.v
}
pub fn init(&mut self) {
self.prev = self;
self.next = self;
}
pub fn add(&mut self, new: &mut ListHead<T>) {
_list_add(new, self, self.next);
}
pub fn add_tail(&mut self, new: &mut ListHead<T>) {
_list_add(new, self.prev, self);
}
pub fn list_del(entry: &mut ListHead<T>) {
_list_del_entry(entry);
entry.prev = ptr::null_mut();
entry.next = ptr::null_mut();
}
pub fn next(&self) -> &ListHead<T> {
return unsafe {&*self.next};
}
pub fn prev(&mut self) -> &ListHead<T> {
return unsafe {&*self.prev};
}
pub fn at(&mut self, pos: u32) -> &ListHead<T> {
let mut current = self;
let mut count = pos;
while count > 0 {
current = unsafe {&mut *current.next};
count -= 1;
}
return &*current;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn init_list() {
let list = &mut ListHead::new(1);
list.init();
assert!(!list.prev.is_null() && !list.next.is_null());
assert!(list.prev == list.next);
{
list.add(&mut ListHead::new(2));
list.add_tail(&mut ListHead::new(3));
list.add(&mut ListHead::new(4));
}
let mut current = list;
let mut count = 10;
while count > 0 {
println!("{:?} - {:?}", current, current.next);
current = unsafe {&mut *current.next};
count -= 1;
}
assert_eq!(1, 2);
}
}