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 operates 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 lock-free iterator (Iter)
for (index, element) in list.iter().enumerate() {
    assert_eq!(index, *element);
}

// You can get the current iteration index
// iter.index() == iter.len() means iteration ended (iter.next() == None)
let mut iter = &mut 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!((&mut list.iter()).next(), None);

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

Multi-producer, multi-consumer

use std::{sync::Arc, thread::spawn};

const CONSUMERS: usize = 8;
const PRODUCERS: usize = 4;
const ELEMENTS: usize = 10_000_000;

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 example ended without errors");
}

Implementations

Available on crate feature rayon-traits only.

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

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

Creates new empty VS (like Default trait)

let list: VS<()> = VS::new();
assert!(list.is_empty());

Inserts element after last node

let list = vs![];
let mut iter = list.iter();

list.append(3);
// Iter doesn't grow if it's empty (originally empty or was consumed)
assert!(iter.is_empty());

iter = list.iter();
list.append(8);
// Iter grows if it has not been consumed
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 (element, expected) in list.iter().zip(&[3, 2][..]) {
    assert_eq!(element, expected);
}

Returns current size, be careful with race conditions when using it since other threads can change it right after the read

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 since other threads can change it right after the read

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

Clears list (iterators referencing the 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);

Clears list returning iterator to it (other iterators referencing the old chain will still work)

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

Swaps two VS

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

Extends VS like the Extend trait, but without 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]);

// You can extend from another `VS` if you clone (or copy) each element
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]);

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
The VALUES clause to insert these records Read more
Construct Self::Values Read more
Insert self into a given table. 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.

Convert self to an expression for Diesel’s query builder. Read more
Convert &self to an expression for Diesel’s query builder. Read more
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.