Skip to content

Rust implementation of the chunked-array queue #47

Description

@scotts

Implementing a double-linked structure is not straight-forward in Rust for several reasons. @segeljakt has a WIP (#24) with an implementation. His thoughts on design follows:

I think there should be one or more chunked array queue implementations floating around on https://crates.io/. The solution I had in mind before was to use:

  • a std::collections::LinkedList for connecting the chunks
  • a std::vec::Vec (or array [T;N]) for storing each chunk.
  • a std::collections::linked_list::CursorMut for traversing between chunks.
  • a higher-level Cursor, building on top of CursorMut for traversing between elements of chunks.

A cursor is like an iterator but does not consume the thing it is iterating over. With DoubleEndedIterator, it might be a problem because you cannot iterate over the same element twice:

let numbers = vec![1, 2, 3, 4, 5, 6];

let mut iter = numbers.iter();

assert_eq!(Some(&1), iter.next());
assert_eq!(Some(&6), iter.next_back());
assert_eq!(Some(&5), iter.next_back());
assert_eq!(Some(&2), iter.next());
assert_eq!(Some(&3), iter.next());
assert_eq!(Some(&4), iter.next());
assert_eq!(None, iter.next());
assert_eq!(None, iter.next_back());

If you need multiple cursors, you might have to create them using an unsafe pointer. I think it is not possible to use a std::cell::RefCell + std::rc::Rc because the cursors must mutably borrow the linked list which they are traversing for their whole lifetime. With RefCell, Rust would panic if two cursors exist simultaneously. There should hopefully be no problem as long as you ensure that the cursors do not point to something which is deallocated.

fn main() {
    use std::collections::LinkedList;
    let mut l: LinkedList<[i32; 5]> = LinkedList::new();

    let (mut c0, mut c1, mut c2) = unsafe {
        let l = &mut l;
        let l = l as *mut LinkedList<[i32; 5]>;
        let c0 = l.as_mut().unwrap().cursor_back_mut();
        let c1 = l.as_mut().unwrap().cursor_back_mut();
        let c2 = l.as_mut().unwrap().cursor_back_mut();
        (c0, c1, c2)
    };

    l.push_back([0,1,2,3,4]);
    l.push_back([5,6,7,8,9]);

    c0.move_next();
    c1.move_next();
    c2.move_next();
    c2.move_next();

    l.push_front([4,3,2,1,0]);

    c0.move_prev();

    println!("{:?}", l);

    assert_eq!(c0.current(), Some(&mut [4,3,2,1,0]));
    assert_eq!(c1.current(), Some(&mut [0,1,2,3,4]));
    assert_eq!(c2.current(), Some(&mut [5,6,7,8,9]));
}

And,

I asked in the Rust community and was recommended this crate: https://crates.io/crates/bucket_queue

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestquestionFurther information is requested

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions