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(new: *mut ListHead, prev: *mut ListHead, next: *mut ListHead) {
    unsafe {
        (*next).prev = new;
        (*new).next = next;
        (*new).prev = prev;
        (*prev).next = new;
    }
}

fn _list_del(prev: *mut ListHead, next: *mut ListHead) {
    unsafe {
        (*next).prev = prev;
        (*prev).next = next;
    }
}

fn _list_del_entry_valid(_entry: &mut ListHead) -> bool {
    // TODO:
    return true;
}

fn _list_del_entry(entry: &mut ListHead) {
    if _list_del_entry_valid(entry) {
        return;
    }
    _list_del(entry.prev, entry.next);
}

fn list_replace(old: &mut ListHead, new: &mut ListHead) {
    unsafe {
        new.next = old.next;
        (*new.next).prev = new;
        new.prev = old.prev;
        (*new.prev).next = new;
    }
}

fn list_is_last(list: &mut ListHead, head: &mut ListHead) -> bool {
    return list.next == head;
}

// TODO: needs const
fn list_empty(head: &mut ListHead) -> bool {
    return head.next == head.prev;
}

/// head -> item -> item -> item -> tail
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ListHead {
    v: T,
    prev: *mut ListHead,
    next: *mut ListHead,
}

/// 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 ListHead {
    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) {
        _list_add(new, self, self.next);
    }

    pub fn add_tail(&mut self, new: &mut ListHead) {
        _list_add(new, self.prev, self);
    }

    pub fn list_del(entry: &mut ListHead) {
        _list_del_entry(entry);
        entry.prev = ptr::null_mut();
        entry.next = ptr::null_mut();
    }

    pub fn next(&self) -> &ListHead {
        return unsafe {&*self.next};
    }

    pub fn prev(&mut self) -> &ListHead {
        return unsafe {&*self.prev};
    }

    pub fn at(&mut self, pos: u32) -> &ListHead {
        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);
    }
}

你可能感兴趣的:(Rust双向链表)