Coverage Report

Created: 2026-01-25 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/elsa-1.11.2/src/vec.rs
Line
Count
Source
1
use std::cell::UnsafeCell;
2
use std::cmp::Ordering;
3
use std::iter::FromIterator;
4
use std::ops::Index;
5
6
use stable_deref_trait::StableDeref;
7
8
/// Append-only version of `std::vec::Vec` where
9
/// insertion does not require mutable access
10
pub struct FrozenVec<T> {
11
    vec: UnsafeCell<Vec<T>>,
12
    // XXXManishearth do we need a reentrancy guard here as well?
13
    // StableDeref may not guarantee that there are no side effects
14
}
15
16
// safety: UnsafeCell implies !Sync
17
18
impl<T> FrozenVec<T> {
19
    /// Constructs a new, empty vector.
20
0
    pub const fn new() -> Self {
21
0
        Self {
22
0
            vec: UnsafeCell::new(Vec::new()),
23
0
        }
24
0
    }
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::Typed>>>::new
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::ctxt::StoredImport>>>::new
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::ctxt::StoredImportAlternative>>>::new
25
}
26
27
impl<T> FrozenVec<T> {
28
    // these should never return &T
29
    // these should never delete any entries
30
31
    /// Appends an element to the back of the vector.
32
0
    pub fn push(&self, val: T) {
33
        unsafe {
34
0
            let vec = self.vec.get();
35
0
            (*vec).push(val)
36
        }
37
0
    }
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::Typed>>>::push
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::ctxt::StoredImport>>>::push
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::ctxt::StoredImportAlternative>>>::push
38
}
39
40
impl<T: StableDeref> FrozenVec<T> {
41
    /// Push, immediately getting a reference to the element
42
    pub fn push_get(&self, val: T) -> &T::Target {
43
        unsafe {
44
            let vec = self.vec.get();
45
            (*vec).push(val);
46
            &*(&**(*vec).get_unchecked((*vec).len() - 1) as *const T::Target)
47
        }
48
    }
49
50
    /// Returns a reference to an element.
51
0
    pub fn get(&self, index: usize) -> Option<&T::Target> {
52
        unsafe {
53
0
            let vec = self.vec.get();
54
0
            (*vec).get(index).map(|x| &**x)
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::Typed>>>::get::{closure#0}
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::ctxt::StoredImport>>>::get::{closure#0}
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::ctxt::StoredImportAlternative>>>::get::{closure#0}
55
        }
56
0
    }
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::Typed>>>::get
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::ctxt::StoredImport>>>::get
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::ctxt::StoredImportAlternative>>>::get
57
58
    /// Returns a reference to an element, without doing bounds checking.
59
    ///
60
    /// ## Safety
61
    ///
62
    /// `index` must be in bounds, i.e. it must be less than `self.len()`
63
    pub unsafe fn get_unchecked(&self, index: usize) -> &T::Target {
64
        let vec = self.vec.get();
65
        (*vec).get_unchecked(index)
66
    }
67
}
68
69
impl<T: Copy> FrozenVec<T> {
70
    /// Returns a copy of an element.
71
    pub fn get_copy(&self, index: usize) -> Option<T> {
72
        unsafe {
73
            let vec = self.vec.get();
74
            (*vec).get(index).copied()
75
        }
76
    }
77
}
78
79
impl<T> FrozenVec<T> {
80
    /// Returns the number of elements in the vector.
81
0
    pub fn len(&self) -> usize {
82
        unsafe {
83
0
            let vec = self.vec.get();
84
0
            (*vec).len()
85
        }
86
0
    }
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::Typed>>>::len
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::ctxt::StoredImport>>>::len
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::ctxt::StoredImportAlternative>>>::len
87
88
    /// Returns `true` if the vector contains no elements.
89
    pub fn is_empty(&self) -> bool {
90
        self.len() == 0
91
    }
92
}
93
94
impl<T: StableDeref> FrozenVec<T> {
95
    /// Returns the first element of the vector, or `None` if empty.
96
    pub fn first(&self) -> Option<&T::Target> {
97
        unsafe {
98
            let vec = self.vec.get();
99
            (*vec).first().map(|x| &**x)
100
        }
101
    }
102
103
    /// Returns the last element of the vector, or `None` if empty.
104
    pub fn last(&self) -> Option<&T::Target> {
105
        unsafe {
106
            let vec = self.vec.get();
107
            (*vec).last().map(|x| &**x)
108
        }
109
    }
110
    /// Returns an iterator over the vector.
111
    pub fn iter(&self) -> Iter<T> {
112
        self.into_iter()
113
    }
114
}
115
116
impl<T: StableDeref> FrozenVec<T> {
117
    /// Converts the frozen vector into a plain vector.
118
    pub fn into_vec(self) -> Vec<T> {
119
        self.vec.into_inner()
120
    }
121
}
122
123
impl<T: StableDeref> FrozenVec<T> {
124
    // binary search functions: they need to be reimplemented here to be safe (instead of calling
125
    // their equivalents directly on the underlying Vec), as they run user callbacks that could
126
    // reentrantly call other functions on this vector
127
128
    /// Binary searches this sorted vector for a given element, analogous to [slice::binary_search].
129
    pub fn binary_search(&self, x: &T::Target) -> Result<usize, usize>
130
    where
131
        T::Target: Ord,
132
    {
133
        self.binary_search_by(|p| p.cmp(x))
134
    }
135
136
    /// Binary searches this sorted vector with a comparator function, analogous to
137
    /// [slice::binary_search_by].
138
    pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
139
    where
140
        F: FnMut(&'a T::Target) -> Ordering,
141
    {
142
        let mut size = self.len();
143
        let mut left = 0;
144
        let mut right = size;
145
        while left < right {
146
            let mid = left + size / 2;
147
148
            // safety: like the core algorithm, mid is always within original vector len; in
149
            // pathlogical cases, user could push to the vector in the meantime, but this can only
150
            // increase the length, keeping this safe
151
            let cmp = f(unsafe { self.get_unchecked(mid) });
152
153
            if cmp == Ordering::Less {
154
                left = mid + 1;
155
            } else if cmp == Ordering::Greater {
156
                right = mid;
157
            } else {
158
                return Ok(mid);
159
            }
160
161
            size = right - left;
162
        }
163
        Err(left)
164
    }
165
166
    /// Binary searches this sorted vector with a key extraction function, analogous to
167
    /// [slice::binary_search_by_key].
168
    pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize, usize>
169
    where
170
        F: FnMut(&'a T::Target) -> B,
171
        B: Ord,
172
    {
173
        self.binary_search_by(|k| f(k).cmp(b))
174
    }
175
176
    /// Returns the index of the partition point according to the given predicate
177
    /// (the index of the first element of the second partition), analogous to
178
    /// [slice::partition_point].
179
    pub fn partition_point<P>(&self, mut pred: P) -> usize
180
    where
181
        P: FnMut(&T::Target) -> bool,
182
    {
183
        let mut left = 0;
184
        let mut right = self.len();
185
186
        while left != right {
187
            let mid = left + (right - left) / 2;
188
            // safety: like in binary_search_by
189
            let value = unsafe { self.get_unchecked(mid) };
190
            if pred(value) {
191
                left = mid + 1;
192
            } else {
193
                right = mid;
194
            }
195
        }
196
197
        left
198
    }
199
200
    // TODO add more
201
}
202
203
impl<T> std::convert::AsMut<Vec<T>> for FrozenVec<T> {
204
    /// Get mutable access to the underlying vector.
205
    ///
206
    /// This is safe, as it requires a `&mut self`, ensuring nothing is using
207
    /// the 'frozen' contents.
208
    fn as_mut(&mut self) -> &mut Vec<T> {
209
        unsafe { &mut *self.vec.get() }
210
    }
211
}
212
213
impl<T> Default for FrozenVec<T> {
214
0
    fn default() -> Self {
215
0
        FrozenVec::new()
216
0
    }
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::Typed>> as core::default::Default>::default
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::ctxt::StoredImport>> as core::default::Default>::default
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::ctxt::StoredImportAlternative>> as core::default::Default>::default
217
}
218
219
impl<T: Clone> Clone for FrozenVec<T> {
220
    fn clone(&self) -> Self {
221
        Self {
222
            vec: unsafe { self.vec.get().as_ref().unwrap() }.clone().into(),
223
        }
224
    }
225
}
226
227
impl<T> From<Vec<T>> for FrozenVec<T> {
228
    fn from(vec: Vec<T>) -> Self {
229
        Self {
230
            vec: UnsafeCell::new(vec),
231
        }
232
    }
233
}
234
235
impl<T: StableDeref> Index<usize> for FrozenVec<T> {
236
    type Output = T::Target;
237
0
    fn index(&self, idx: usize) -> &T::Target {
238
0
        self.get(idx).unwrap_or_else(|| {
239
0
            panic!(
240
0
                "index out of bounds: the len is {} but the index is {}",
241
0
                self.len(),
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::Typed>> as core::ops::index::Index<usize>>::index::{closure#0}
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::ctxt::StoredImport>> as core::ops::index::Index<usize>>::index::{closure#0}
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::ctxt::StoredImportAlternative>> as core::ops::index::Index<usize>>::index::{closure#0}
242
                idx
243
            )
244
        })
245
0
    }
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::Typed>> as core::ops::index::Index<usize>>::index
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::ctxt::StoredImport>> as core::ops::index::Index<usize>>::index
Unexecuted instantiation: <elsa::vec::FrozenVec<alloc::boxed::Box<dhall::ctxt::StoredImportAlternative>> as core::ops::index::Index<usize>>::index
246
}
247
248
impl<A> FromIterator<A> for FrozenVec<A> {
249
    fn from_iter<T>(iter: T) -> Self
250
    where
251
        T: IntoIterator<Item = A>,
252
    {
253
        let vec: Vec<_> = iter.into_iter().collect();
254
        vec.into()
255
    }
256
}
257
258
/// Iterator over FrozenVec, obtained via `.iter()`
259
///
260
/// It is safe to push to the vector during iteration
261
pub struct Iter<'a, T> {
262
    vec: &'a FrozenVec<T>,
263
    idx: usize,
264
}
265
266
impl<'a, T: StableDeref> Iterator for Iter<'a, T> {
267
    type Item = &'a T::Target;
268
    fn next(&mut self) -> Option<&'a T::Target> {
269
        if let Some(ret) = self.vec.get(self.idx) {
270
            self.idx += 1;
271
            Some(ret)
272
        } else {
273
            None
274
        }
275
    }
276
}
277
278
impl<'a, T: StableDeref> IntoIterator for &'a FrozenVec<T> {
279
    type Item = &'a T::Target;
280
    type IntoIter = Iter<'a, T>;
281
    fn into_iter(self) -> Iter<'a, T> {
282
        Iter { vec: self, idx: 0 }
283
    }
284
}
285
286
impl<T: StableDeref + PartialEq> PartialEq for FrozenVec<T>
287
where
288
    T::Target: PartialEq,
289
{
290
    fn eq(&self, other: &Self) -> bool {
291
        unsafe { self.vec.get().as_ref() == other.vec.get().as_ref() }
292
    }
293
}
294
295
#[test]
296
fn test_iteration() {
297
    let vec = vec!["a", "b", "c", "d"];
298
    let frozen: FrozenVec<_> = vec.clone().into();
299
300
    assert_eq!(vec, frozen.iter().collect::<Vec<_>>());
301
    for (e1, e2) in vec.iter().zip(frozen.iter()) {
302
        assert_eq!(*e1, e2);
303
    }
304
305
    assert_eq!(vec.len(), frozen.iter().count())
306
}
307
308
#[test]
309
fn test_accessors() {
310
    let vec: FrozenVec<String> = FrozenVec::new();
311
312
    assert!(vec.is_empty());
313
    assert_eq!(vec.len(), 0);
314
    assert_eq!(vec.first(), None);
315
    assert_eq!(vec.last(), None);
316
    assert_eq!(vec.get(1), None);
317
318
    vec.push("a".to_string());
319
    vec.push("b".to_string());
320
    vec.push("c".to_string());
321
322
    assert!(!vec.is_empty());
323
    assert_eq!(vec.len(), 3);
324
    assert_eq!(vec.first(), Some("a"));
325
    assert_eq!(vec.last(), Some("c"));
326
    assert_eq!(vec.get(1), Some("b"));
327
}
328
329
#[test]
330
fn test_non_stable_deref() {
331
    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
332
    struct Moo(i32);
333
    let vec: FrozenVec<Moo> = FrozenVec::new();
334
335
    assert!(vec.is_empty());
336
    assert_eq!(vec.len(), 0);
337
    assert_eq!(vec.get_copy(1), None);
338
339
    vec.push(Moo(1));
340
    vec.push(Moo(2));
341
    vec.push(Moo(3));
342
343
    assert!(!vec.is_empty());
344
    assert_eq!(vec.len(), 3);
345
    assert_eq!(vec.get_copy(1), Some(Moo(2)));
346
}
347
348
#[test]
349
fn test_binary_search() {
350
    let vec: FrozenVec<_> = vec!["ab", "cde", "fghij"].into();
351
352
    assert_eq!(vec.binary_search("cde"), Ok(1));
353
    assert_eq!(vec.binary_search("cdf"), Err(2));
354
    assert_eq!(vec.binary_search("a"), Err(0));
355
    assert_eq!(vec.binary_search("g"), Err(3));
356
357
    assert_eq!(vec.binary_search_by_key(&1, |x| x.len()), Err(0));
358
    assert_eq!(vec.binary_search_by_key(&3, |x| x.len()), Ok(1));
359
    assert_eq!(vec.binary_search_by_key(&4, |x| x.len()), Err(2));
360
361
    assert_eq!(vec.partition_point(|x| x.len() < 4), 2);
362
    assert_eq!(vec.partition_point(|_| false), 0);
363
    assert_eq!(vec.partition_point(|_| true), 3);
364
}