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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/// Result of [`crate::ConcurrentOrderedBag::into_inner`] call.
pub enum IntoInnerResult<P> {
    /// Length of the bag is equal to the number of elements pushed.
    ///
    /// *Length is assumed to be `m + 1`, where `m` is the index of the maximum position an element is written to.*
    LenMatchesNumPushes {
        /// Length of the bag.
        ///
        /// *Length is assumed to be `m + 1`, where `m` is the index of the maximum position an element is written to.*
        len: usize,
        /// Underlying pinned vector which can safely be `unwrapped` if the caller can guarantee that each element is written exactly once.
        /// Otherwise, the vector might still contain gaps.
        vec: MayFail<P>,
    },
    /// Number of pushes to the bag is greater than the length of the vector.
    /// This indicates that at least one position is never written; and hence, there exists at least `len - num_pushed` gaps.
    /// The caller is required to take the responsibility to unwrap.
    ///
    /// *Length is assumed to be `m + 1`, where `m` is the index of the maximum position an element is written to.*
    GreaterLenThanNumPushes {
        /// Length of the bag.
        ///
        /// *Length is assumed to be `m + 1`, where `m` is the index of the maximum position an element is written to.*
        len: usize,
        /// Number of times an element is written to the bag.
        num_pushed: usize,
        /// Underlying pinned vector has gaps.
        /// The caller is required to take the responsibility to unwrap.
        vec: MayFail<P>,
    },
    /// Number of pushes to the bag is greater than the length of the vector.
    /// This indicates that at least one position is written at least twice, which is a violation of the safety requirement.
    /// The caller is required to take the responsibility to unwrap.
    ///
    /// *Length is assumed to be `m + 1`, where `m` is the index of the maximum position an element is written to.*
    LessLenThanNumPushes {
        /// Length of the bag.
        ///
        /// *Length is assumed to be `m + 1`, where `m` is the index of the maximum position an element is written to.*
        len: usize,
        /// Number of times an element is written to the bag.
        num_pushed: usize,
        /// There has been multiple writes to the same position and there might still be gaps in the collection.
        /// The caller is required to take the responsibility to unwrap.
        vec: MayFail<P>,
    },
}

impl<P> IntoInnerResult<P> {
    /// Without checking the `IntoInnerResult` variant, directly unwraps and returns the underlying pinned vector.
    ///
    /// # Safety
    ///
    /// The underlying vector might be in an invalid condition if the safety requirements are not followed during concurrent growth:
    /// * Each position is written exactly once, so that there exists no race condition.
    /// * At the point where `into_inner` is called (not necessarily always), the bag must not contain any gaps.
    ///   * Let `m` be the maximum index of the position that we write an element to.
    ///   * The bag assumes that the length of the vector is equal to `m + 1`.
    ///   * Then, it expects that exactly `m + 1` elements are written to the bag.
    ///   * 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.
    pub unsafe fn unwrap(self) -> P {
        match self {
            IntoInnerResult::LenMatchesNumPushes { len: _, vec } => vec.unwrap(),
            IntoInnerResult::GreaterLenThanNumPushes {
                len: _,
                num_pushed: _,
                vec,
            } => vec.unwrap(),
            IntoInnerResult::LessLenThanNumPushes {
                len: _,
                num_pushed: _,
                vec,
            } => vec.unwrap(),
        }
    }

    /// Unwraps and returns the pinned vector if the result is of [`IntoInnerResult::LenMatchesNumPushes`] variant, panics otherwise.
    ///
    /// # Panics
    ///
    /// Panics if the result is not of the [`IntoInnerResult::LenMatchesNumPushes`] variant.
    ///
    /// # Safety
    ///
    /// The underlying vector might be in an invalid condition if the safety requirements are not followed during concurrent growth:
    /// * Each position is written exactly once, so that there exists no race condition.
    /// * At the point where `into_inner` is called (not necessarily always), the bag must not contain any gaps.
    ///   * Let `m` be the maximum index of the position that we write an element to.
    ///   * The bag assumes that the length of the vector is equal to `m + 1`.
    ///   * Then, it expects that exactly `m + 1` elements are written to the bag.
    ///   * 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.
    #[allow(clippy::panic)]
    pub unsafe fn unwrap_only_if_counts_match(self) -> P {
        match self {
            IntoInnerResult::LenMatchesNumPushes { len: _, vec } => vec.unwrap(),
            IntoInnerResult::GreaterLenThanNumPushes {
                len,
                num_pushed,
                vec: _,
            } => panic!("OrderedConcurrentBag surely contains gaps: {} elements are pushed; however, maximum index is {}.", num_pushed, len),
            IntoInnerResult::LessLenThanNumPushes {
                len,
                num_pushed,
                vec: _,
            } => panic!("OrderedConcurrentBag surely contains gaps: {} elements are pushed; however, maximum index is {}.", num_pushed, len),
        }
    }
}

/// A wrapped value which can only be unwrapped through an unsafe call, leaving the decision or responsibility to the caller.
pub struct MayFail<T>(T);

impl<T> MayFail<T> {
    /// Wraps the `value` as a `MayFail` value.
    pub fn new(value: T) -> Self {
        Self(value)
    }

    /// Unwraps and returns the underlying value.
    ///
    /// # Safety
    ///
    /// 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.
    pub unsafe fn unwrap(self) -> T {
        self.0
    }
}

impl<P> From<P> for MayFail<P> {
    fn from(value: P) -> Self {
        Self::new(value)
    }
}