pub struct VoluntaryServitude<T>(_);
Expand description

Appendable list with lock-free iterator (also called VS)

Examples

Single thread

let (a, b, c) = (0usize, 1usize, 2usize);
// VS alias to VoluntaryServitude
// vs! alias to voluntary_servitude! (and operate like vec!)
let list = vs![a, b, c];
assert_eq!(list.iter().collect::<Vec<_>>(), vec![&a, &b, &c]);

// Current VS's length
// Be careful with race conditions since the value, when used, may not be true anymore
assert_eq!(list.len(), 3);

// The 'iter' method makes a one-time lock-free iterator (Iter)
for (index, element) in list.iter().enumerate() {
    assert_eq!(index, *element);
}

// You can get the current iteration index
// iter.next() == iter.len() means iteration ended (iter.next() == None)
let mut iter = list.iter();
assert_eq!(iter.index(), 0);
assert_eq!(iter.next(), Some(&0));
assert_eq!(iter.index(), 1);

// List can also be cleared (but current iterators are not affected)
list.clear();

assert_eq!(iter.len(), 3);
assert_eq!(list.len(), 0);
assert_eq!(list.iter().len(), 0);
assert_eq!(list.iter().next(), None);

println!("Single thread example ended without errors");

Multi-producer, multi-consumer

#[macro_use]
extern crate voluntary_servitude;
use std::{sync::Arc, thread::spawn};

const CONSUMERS: usize = 8;
const PRODUCERS: usize = 4;
const ELEMENTS: usize = 10000000;

fn main() {
    let list = Arc::new(vs![]);
    let mut handlers = vec![];

    // Creates producer threads to insert 10k elements
    for _ in 0..PRODUCERS {
        let l = Arc::clone(&list);
        handlers.push(spawn(move || {
            let _ = (0..ELEMENTS).map(|i| l.append(i)).count();
        }));
    }

    // Creates consumer threads to print number of elements
    // Until all of them are inserted
    for _ in 0..CONSUMERS {
        const TOTAL: usize = PRODUCERS * ELEMENTS;
        let consumer = Arc::clone(&list);
        handlers.push(spawn(move || loop {
            let count = consumer.iter().count();
            println!("{} elements", count);
            if count >= TOTAL { break };
        }));
    }

    // Join threads
    for handler in handlers.into_iter() {
        handler.join().expect("Failed to join thread");
    }

    println!("Multi-thread rust example ended without errors");
}

Implementations

Returns current size, be careful with race conditions when using it

let list = vs![3, 2];
assert_eq!(list.len(), 2);
list.append(5);
assert_eq!(list.len(), 3);
list.clear();
assert_eq!(list.len(), 0);

Checks if VS is currently empty, be careful with race conditions when using it

let list = vs![];
assert!(list.is_empty());
list.append(());
assert!(!list.is_empty());

Inserts element after last node

let list = vs![];
let mut iter = list.iter();
list.append(3);
assert!(iter.is_empty());
iter = list.iter();
list.append(8);
assert_eq!(iter.collect::<Vec<_>>(), vec![&3, &8]);

Makes lock-free iterator based on VS

let list = vs![3, 2];
assert_eq!(list.iter().collect::<Vec<_>>(), vec![&3, &2]);
for (index, element) in list.iter().enumerate() {
    assert_eq!(*element, [3, 2][index]);
}

Clears list (iterators referencing old chain will still work)

let list = vs![3, 2];
let iter = list.iter();
list.clear();
assert_eq!(iter.len(), 2);
assert_eq!(list.len(), 0);
assert_eq!(list.iter().len(), 0);

Extends VS like the Extend trait, but without needing a mutable reference

let list = vs![1, 2, 3];
list.extend(vec![4, 5, 6]);
assert_eq!(list.iter().collect::<Vec<_>>(), vec![&1, &2, &3, &4, &5, &6]);

let list = vs![1, 2, 3];
list.extend(vs![4, 5, 6].iter().cloned());
assert_eq!(list.iter().collect::<Vec<_>>(), vec![&1, &2, &3, &4, &5, &6]);

let list = vs![1, 2, 3];
list.extend(vec![&4, &5, &6].into_iter().cloned());
assert_eq!(list.iter().collect::<Vec<_>>(), vec![&1, &2, &3, &4, &5, &6]);
Available on crate feature rayon-traits only.

Parallely Extends VS like the ParallelExtend trait, but without a mutable reference

let list = vs![1u8, 2, 3];
list.par_extend(vec![4, 5, 6]);
assert_eq!(list.iter().sum::<u8>(), 21u8);

Trait Implementations

Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Deserialize this value from the given Serde deserializer. Read more
Extends a collection with the contents of an iterator. Read more
🔬This is a nightly-only experimental API. (extend_one)
Extends a collection with exactly one element.
🔬This is a nightly-only experimental API. (extend_one)
Reserves capacity in a collection for the given number of additional elements. Read more
Extends a collection with the contents of an iterator. Read more
🔬This is a nightly-only experimental API. (extend_one)
Extends a collection with exactly one element.
🔬This is a nightly-only experimental API. (extend_one)
Reserves capacity in a collection for the given number of additional elements. Read more
Creates a value from an iterator. Read more
Creates a value from an iterator. Read more
Creates an instance of the collection from the parallel iterator par_iter. Read more
Extends an instance of the collection with the elements drawn from the parallel iterator par_iter. Read more
Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.