1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use atomic_ref2::{AtomicOptionRef, IntoOptionArc};
use std::sync::Arc;

/// An array of references in which elements may be updated and retrieved atomically.
///
/// This is a Rust interpretation of [AtomicReferenceArray](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicReferenceArray.html) from Java.
pub struct AtomicOptionRefArray<T> {
    buf: Box<[AtomicOptionRef<T>]>,
}

impl<T> AtomicOptionRefArray<T> {
    /// Constructs a new array with the specified length.
    /// All values will be `None`.
    pub fn new(len: usize) -> Self {
        let mut buf = Vec::with_capacity(len);

        for _ in 0..len {
            buf.push(AtomicOptionRef::new());
        }

        Self {
            buf: buf.into_boxed_slice(),
        }
    }

    /// Constructs a new array with the specified length.
    /// Uses the given function to construct each value.
    pub fn new_with<U: IntoOptionArc<T>>(len: usize, f: impl Fn(usize) -> U) -> Self {
        let mut buf = Vec::with_capacity(len);

        for i in 0..len {
            buf.push(AtomicOptionRef::from(f(i)));
        }

        Self {
            buf: buf.into_boxed_slice(),
        }
    }

    /// Returns the number of elements in the array.
    pub fn len(&self) -> usize {
        self.buf.len()
    }

    /// Returns `true` if the array has a length of 0.
    pub fn is_empty(&self) -> bool {
        self.buf.is_empty()
    }

    /// Loads and returns a reference to an value at the given position or `None`
    /// if the value at the index is not set.
    ///
    /// Panics if `index` is out of bounds.
    pub fn load(&self, index: usize) -> Option<Arc<T>> {
        self.buf[index].load()
    }

    /// Stores the value at the given position.
    ///
    /// Panics if `index` is out of bounds.
    pub fn store(&self, index: usize, value: impl IntoOptionArc<T>) {
        self.buf[index].store(value);
    }

    /// Swaps the value at the given position, returning the previous value.
    ///
    /// Panics if `index` is out of bounds.
    pub fn swap(&self, index: usize, value: impl IntoOptionArc<T>) -> Option<Arc<T>> {
        self.buf[index].swap(value)
    }
}