实现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);
}
}