orx_concurrent_ordered_bag/
failures.rs

1/// Result of [`crate::ConcurrentOrderedBag::into_inner`] call.
2pub enum IntoInnerResult<P> {
3    /// Length of the bag is equal to the number of elements pushed.
4    ///
5    /// *Length is assumed to be `m + 1`, where `m` is the index of the maximum position an element is written to.*
6    LenMatchesNumPushes {
7        /// Length of the bag.
8        ///
9        /// *Length is assumed to be `m + 1`, where `m` is the index of the maximum position an element is written to.*
10        len: usize,
11        /// Underlying pinned vector which can safely be `unwrapped` if the caller can guarantee that each element is written exactly once.
12        /// Otherwise, the vector might still contain gaps.
13        vec: MayFail<P>,
14    },
15    /// Number of pushes to the bag is greater than the length of the vector.
16    /// This indicates that at least one position is never written; and hence, there exists at least `len - num_pushed` gaps.
17    /// The caller is required to take the responsibility to unwrap.
18    ///
19    /// *Length is assumed to be `m + 1`, where `m` is the index of the maximum position an element is written to.*
20    GreaterLenThanNumPushes {
21        /// Length of the bag.
22        ///
23        /// *Length is assumed to be `m + 1`, where `m` is the index of the maximum position an element is written to.*
24        len: usize,
25        /// Number of times an element is written to the bag.
26        num_pushed: usize,
27        /// Underlying pinned vector has gaps.
28        /// The caller is required to take the responsibility to unwrap.
29        vec: MayFail<P>,
30    },
31    /// Number of pushes to the bag is greater than the length of the vector.
32    /// This indicates that at least one position is written at least twice, which is a violation of the safety requirement.
33    /// The caller is required to take the responsibility to unwrap.
34    ///
35    /// *Length is assumed to be `m + 1`, where `m` is the index of the maximum position an element is written to.*
36    LessLenThanNumPushes {
37        /// Length of the bag.
38        ///
39        /// *Length is assumed to be `m + 1`, where `m` is the index of the maximum position an element is written to.*
40        len: usize,
41        /// Number of times an element is written to the bag.
42        num_pushed: usize,
43        /// There has been multiple writes to the same position and there might still be gaps in the collection.
44        /// The caller is required to take the responsibility to unwrap.
45        vec: MayFail<P>,
46    },
47}
48
49impl<P> IntoInnerResult<P> {
50    /// Without checking the `IntoInnerResult` variant, directly unwraps and returns the underlying pinned vector.
51    ///
52    /// # Safety
53    ///
54    /// The underlying vector might be in an invalid condition if the safety requirements are not followed during concurrent growth:
55    /// * Each position is written exactly once, so that there exists no race condition.
56    /// * At the point where `into_inner` is called (not necessarily always), the bag must not contain any gaps.
57    ///   * Let `m` be the maximum index of the position that we write an element to.
58    ///   * The bag assumes that the length of the vector is equal to `m + 1`.
59    ///   * Then, it expects that exactly `m + 1` elements are written to the bag.
60    ///   * If the first condition was satisfied; then, this condition is sufficient to conclude that the bag can be converted to the underlying vector of `m + 1` elements.
61    pub unsafe fn unwrap(self) -> P {
62        match self {
63            IntoInnerResult::LenMatchesNumPushes { len: _, vec } => unsafe { vec.unwrap() },
64            IntoInnerResult::GreaterLenThanNumPushes {
65                len: _,
66                num_pushed: _,
67                vec,
68            } => unsafe { vec.unwrap() },
69            IntoInnerResult::LessLenThanNumPushes {
70                len: _,
71                num_pushed: _,
72                vec,
73            } => unsafe { vec.unwrap() },
74        }
75    }
76
77    /// Unwraps and returns the pinned vector if the result is of [`IntoInnerResult::LenMatchesNumPushes`] variant, panics otherwise.
78    ///
79    /// # Panics
80    ///
81    /// Panics if the result is not of the [`IntoInnerResult::LenMatchesNumPushes`] variant.
82    ///
83    /// # Safety
84    ///
85    /// The underlying vector might be in an invalid condition if the safety requirements are not followed during concurrent growth:
86    /// * Each position is written exactly once, so that there exists no race condition.
87    /// * At the point where `into_inner` is called (not necessarily always), the bag must not contain any gaps.
88    ///   * Let `m` be the maximum index of the position that we write an element to.
89    ///   * The bag assumes that the length of the vector is equal to `m + 1`.
90    ///   * Then, it expects that exactly `m + 1` elements are written to the bag.
91    ///   * If the first condition was satisfied; then, this condition is sufficient to conclude that the bag can be converted to the underlying vector of `m + 1` elements.
92    #[allow(clippy::panic)]
93    pub unsafe fn unwrap_only_if_counts_match(self) -> P {
94        match self {
95            IntoInnerResult::LenMatchesNumPushes { len: _, vec } => unsafe { vec.unwrap() },
96            IntoInnerResult::GreaterLenThanNumPushes {
97                len,
98                num_pushed,
99                vec: _,
100            } => panic!(
101                "OrderedConcurrentBag surely contains gaps: {} elements are pushed; however, maximum index is {}.",
102                num_pushed, len
103            ),
104            IntoInnerResult::LessLenThanNumPushes {
105                len,
106                num_pushed,
107                vec: _,
108            } => panic!(
109                "OrderedConcurrentBag surely contains gaps: {} elements are pushed; however, maximum index is {}.",
110                num_pushed, len
111            ),
112        }
113    }
114}
115
116/// A wrapped value which can only be unwrapped through an unsafe call, leaving the decision or responsibility to the caller.
117pub struct MayFail<T>(T);
118
119impl<T> MayFail<T> {
120    /// Wraps the `value` as a `MayFail` value.
121    pub fn new(value: T) -> Self {
122        Self(value)
123    }
124
125    /// Unwraps and returns the underlying value.
126    ///
127    /// # Safety
128    ///
129    /// MayFail is a marker where the producer cannot make sure of safety of the underlying value, and leaves the decision to the caller to unsafely unwrap.
130    pub unsafe fn unwrap(self) -> T {
131        self.0
132    }
133}
134
135impl<P> From<P> for MayFail<P> {
136    fn from(value: P) -> Self {
137        Self::new(value)
138    }
139}