[−][src]Struct voluntary_servitude::VoluntaryServitude
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"); }
Methods
impl<T: Send + Sync> VoluntaryServitude<T>
[src]
pub fn par_extend<I>(&self, par_iter: I) where
I: IntoParallelIterator<Item = T>,
[src]
I: IntoParallelIterator<Item = T>,
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);
impl<T> VoluntaryServitude<T>
[src]
pub fn new() -> Self
[src]
Creates new empty VS
(like Default
trait)
let list: VS<()> = VS::new(); assert!(list.is_empty());
pub fn append(&self, value: T)
[src]
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]);
ⓘImportant traits for &'a mut Iter<T>pub fn iter(&self) -> Iter<T>
[src]
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); }
pub fn len(&self) -> usize
[src]
Returns current size, be careful with race conditions when using it since other threads can change it right after the read
Relaxed
ordering is used to extract the length, so you shouldn't depend on this being sequentially consistent, only atomic
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);
pub fn is_empty(&self) -> bool
[src]
Checks if VS
is currently empty, be careful with race conditions when using it since other threads can change it right after the read
Relaxed
ordering is used to extract the length, so you shouldn't depend on this being sequentially consistent, only atomic
let list = vs![]; assert!(list.is_empty()); list.append(()); assert!(!list.is_empty());
pub fn clear(&self)
[src]
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);
ⓘImportant traits for &'a mut Iter<T>pub fn empty(&self) -> Iter<T>
[src]
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);
pub fn swap(&self, other: &Self)
[src]
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]);
pub fn extend<I: IntoIterator<Item = T>>(&self, iter: I)
[src]
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
impl<T> Default for VoluntaryServitude<T>
[src]
impl<T> Extend<T> for VoluntaryServitude<T>
[src]
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I)
[src]
impl<'a, T: 'a + Copy> Extend<&'a T> for VoluntaryServitude<T>
[src]
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I)
[src]
impl<T: Debug> Debug for VoluntaryServitude<T>
[src]
impl<T> FromIterator<T> for VoluntaryServitude<T>
[src]
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self
[src]
impl<'a, T: 'a + Copy> FromIterator<&'a T> for VoluntaryServitude<T>
[src]
fn from_iter<I: IntoIterator<Item = &'a T>>(iter: I) -> Self
[src]
impl<T: Send + Sync> ParallelExtend<T> for VoluntaryServitude<T>
[src]
fn par_extend<I: IntoParallelIterator<Item = T>>(&mut self, par_iter: I)
[src]
impl<T: Send + Sync> FromParallelIterator<T> for VoluntaryServitude<T>
[src]
fn from_par_iter<I: IntoParallelIterator<Item = T>>(par_iter: I) -> Self
[src]
impl<T: Serialize> Serialize for VoluntaryServitude<T>
[src]
impl<'a, T: Deserialize<'a>> Deserialize<'a> for VoluntaryServitude<T>
[src]
fn deserialize<D: Deserializer<'a>>(des: D) -> Result<Self, D::Error>
[src]
Auto Trait Implementations
impl<T> Send for VoluntaryServitude<T> where
T: Send + Sync,
T: Send + Sync,
impl<T> Sync for VoluntaryServitude<T> where
T: Send + Sync,
T: Send + Sync,
Blanket Implementations
impl<T, U> Into for T where
U: From<T>,
[src]
U: From<T>,
impl<T> From for T
[src]
impl<T, U> TryFrom for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T> Borrow for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,
impl<T> BorrowMut for T where
T: ?Sized,
[src]
T: ?Sized,
fn borrow_mut(&mut self) -> &mut T
[src]
impl<T, U> TryInto for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]
impl<T> DeserializeOwned for T where
T: Deserialize<'de>,
[src]
T: Deserialize<'de>,