Rust雙向鏈表

實現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);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章