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}