1
#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))]
2
#![doc = include_str!("../README.md")]
3
// @@ begin lint list maintained by maint/add_warning @@
4
#![allow(renamed_and_removed_lints)] // @@REMOVE_WHEN(ci_arti_stable)
5
#![allow(unknown_lints)] // @@REMOVE_WHEN(ci_arti_nightly)
6
#![warn(missing_docs)]
7
#![warn(noop_method_call)]
8
#![warn(unreachable_pub)]
9
#![warn(clippy::all)]
10
#![deny(clippy::await_holding_lock)]
11
#![deny(clippy::cargo_common_metadata)]
12
#![deny(clippy::cast_lossless)]
13
#![deny(clippy::checked_conversions)]
14
#![warn(clippy::cognitive_complexity)]
15
#![deny(clippy::debug_assert_with_mut_call)]
16
#![deny(clippy::exhaustive_enums)]
17
#![deny(clippy::exhaustive_structs)]
18
#![deny(clippy::expl_impl_clone_on_copy)]
19
#![deny(clippy::fallible_impl_from)]
20
#![deny(clippy::implicit_clone)]
21
#![deny(clippy::large_stack_arrays)]
22
#![warn(clippy::manual_ok_or)]
23
#![deny(clippy::missing_docs_in_private_items)]
24
#![warn(clippy::needless_borrow)]
25
#![warn(clippy::needless_pass_by_value)]
26
#![warn(clippy::option_option)]
27
#![deny(clippy::print_stderr)]
28
#![deny(clippy::print_stdout)]
29
#![warn(clippy::rc_buffer)]
30
#![deny(clippy::ref_option_ref)]
31
#![warn(clippy::semicolon_if_nothing_returned)]
32
#![warn(clippy::trait_duplication_in_bounds)]
33
#![deny(clippy::unchecked_duration_subtraction)]
34
#![deny(clippy::unnecessary_wraps)]
35
#![warn(clippy::unseparated_literal_suffix)]
36
#![deny(clippy::unwrap_used)]
37
#![deny(clippy::mod_module_files)]
38
#![allow(clippy::let_unit_value)] // This can reasonably be done for explicitness
39
#![allow(clippy::uninlined_format_args)]
40
#![allow(clippy::significant_drop_in_scrutinee)] // arti/-/merge_requests/588/#note_2812945
41
#![allow(clippy::result_large_err)] // temporary workaround for arti#587
42
#![allow(clippy::needless_raw_string_hashes)] // complained-about code is fine, often best
43
#![allow(clippy::needless_lifetimes)] // See arti#1765
44
#![allow(mismatched_lifetime_syntaxes)] // temporary workaround for arti#2060
45
//! <!-- @@ end lint list maintained by maint/add_warning @@ -->
46

            
47
mod key_data;
48

            
49
pub use slotmap::{
50
    new_key_type, secondary, DefaultKey, Key, KeyData, SecondaryMap, SparseSecondaryMap,
51
};
52

            
53
use key_data::key_version_serde as key_version;
54

            
55
//use key_version::key_version_serde;
56

            
57
/// A single entry in one of our careful slotmaps.
58
///
59
/// An entry can either be `Present` (in which case we treat it normally),
60
/// or `Unusable`, in which case we
61
#[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))]
62
#[derive(Debug, Clone)]
63
enum Entry<V> {
64
    /// The entry is available.
65
    Present(V),
66
    /// The entry can no longer be used, removed, or set to anything else.
67
    ///
68
    /// It must not be removed from the slot map, since doing so would
69
    /// increase its slot's version number too high.
70
    Unusable,
71
}
72

            
73
impl<V> Entry<V> {
74
    /// Remove the value of `self` (if any), and make it unusable.
75
90
    fn take_and_mark_unusable(&mut self) -> Option<V> {
76
90
        match std::mem::replace(self, Entry::Unusable) {
77
36
            Entry::Present(v) => Some(v),
78
54
            Entry::Unusable => None,
79
        }
80
90
    }
81
    /// Return a reference to the value of `self`, if there is one.
82
21758
    fn value(&self) -> Option<&V> {
83
21758
        match self {
84
21710
            Entry::Present(val) => Some(val),
85
48
            Entry::Unusable => None,
86
        }
87
21758
    }
88
    /// Return a mutable reference to the value of `self``, if there is one.
89
25656081
    fn value_mut(&mut self) -> Option<&mut V> {
90
25656081
        match self {
91
25656075
            Entry::Present(val) => Some(val),
92
6
            Entry::Unusable => None,
93
        }
94
25656081
    }
95
    /// Consume this entry (which must be `Present`), and return its value.
96
    ///
97
    /// # Panics
98
    ///
99
    /// Panics if this entry is `Unusable`.
100
75328
    fn unwrap(self) -> V {
101
75328
        match self {
102
75328
            Entry::Present(val) => val,
103
            Entry::Unusable => panic!("Tried to unwrap an unusable slot."),
104
        }
105
75328
    }
106
}
107

            
108
/// Helper: Define a wrapper for a single SlotMap type.
109
///
110
/// This works for SlotMap, DenseSlotMap, and HopSlotMap.
111
///
112
/// (The alternative to using a macro here would be to define a new trait
113
/// implemented by all of the SlotMaps, and then to define our own SlotMap as a wrapper around an
114
/// instance of that trait.)
115
macro_rules! define_implementation {
116
        { $mapname:ident } => {paste::paste!{
117

            
118
        /// A variation of
119
        #[doc = concat!("[`slotmap::", stringify!($mapname), "`]")]
120
        /// that can never give the same key for multiple objects.
121
        ///
122
        /// Unlike a regular version of
123
        #[doc = concat!("`", stringify!($mapname), "`,")]
124
        /// this version will not allow a slot's version counter to roll over to
125
        /// 0 if it reaches 2^31.  Instead, it will mark the slot as unusable for future values.
126
        ///
127
        /// # Limitations
128
        ///
129
        /// The possibility of marking a slot as unusable
130
        /// makes it possible, given enough removals and re-insertions,
131
        /// for a slotmap to use an unbounded amount of memory, even if it is not storing much actual data.
132
        /// (From a DOS point of view: Given the ability to re-insert an entry ~2^31 times, an attacker can
133
        /// cause a slot-map to render approximately `4+sizeof(V)` bytes unusable.)
134
        ///
135
        /// This type does not include implementations for:
136
        ///   * `get_unchecked_mut()`
137
        ///   * `get_disjoint_unchecked_mut()`
138
        ///   * `IntoIterator`.
139
        ///   * `serde::{Serialize, Deserialize}`.
140
        ///
141
        /// # Risky business!
142
        ///
143
        /// This code relies upon stability of some undocumented properties of `slotmap` keys.
144
        /// In particular, it assumes:
145
        ///  * that the slotmap KeyData `serde` format is stable,
146
        ///  * that slot versions are represented as `u32`.
147
        ///  * that the least significant bit of a slot version is 1 if the slot is full,
148
        ///    and 0 if the slot is empty.
149
        ///  * that slot versions start at 0, and increase monotonically as the slot is
150
        ///    emptied and reused.
151
        ///
152
        /// Note that these assumptions are _probably_ okay: if `slotmap` were to change them,
153
        /// it would thereby create a breaking change in its serde version.
154
        //
155
        // Invariants:
156
        //
157
        // For every `(key,value)` that is present in `base`:
158
        //   - `key_okay(key)` is true.
159
        //   - if `value` is `Entry::Unusable`, then `key_version(key) == SATURATE_AT_VERSION`.
160
        //
161
        // `n_unusable` is the number of entries in `base` whose value is `Entry::Unusable`.
162
        //
163
        // To maintain these invariants:
164
        //   - Never remove a key with `key_version(key) == SATURATE_AT_VERSION`
165
        //   - Whenever setting a value to `Unusable`, increment `n_unusable`.
166
        #[derive(Clone, Debug)]
167
        pub struct $mapname<K: Key, V> {
168
            /// An underlying SlotMap, obeying the invariants above.
169
            base: slotmap::$mapname<K, Entry<V>>,
170
            /// The number of entries in this SlotMap that are filled with [`Entry::Unusable`] values.
171
            n_unusable: usize,
172
            /// A ZST, used to guarantee that we have spot-checked the behavior of the underlying
173
            /// SlotMap implementation.
174
            _valid: [<$mapname ValidationToken>],
175
        }
176

            
177
        impl<V> $mapname<DefaultKey, V> {
178
            /// Construct a new empty map, using a default key type.
179
            ///
180
            /// See
181
            #[doc = concat!("[`slotmap::", stringify!($mapname), "::new()`].")]
182
6
            pub fn new() -> Self {
183
6
                Self::with_key()
184
6
            }
185

            
186
            /// Construct a new empty map with a specified capacity, using a default key type.
187
            ///
188
            /// See
189
            #[doc = concat!("[`slotmap::", stringify!($mapname), "::with_capacity()`].")]
190
            /// ::with_capacity()`].
191
6
            pub fn with_capacity(capacity: usize) -> Self {
192
6
                Self::with_capacity_and_key(capacity)
193
6
            }
194
        }
195

            
196
        impl<K: Key, V> Default for $mapname<K, V> {
197
125802
            fn default() -> Self {
198
125802
                Self::with_key()
199
125802
            }
200
        }
201

            
202
        impl<K: Key, V> $mapname<K, V> {
203
            /// Construct a new empty map, using a specialized key type.
204
            ///
205
            /// See
206
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::with_key()`].")]
207
126473
            pub fn with_key() -> Self {
208
126473
                Self::with_capacity_and_key(0)
209
126473
            }
210

            
211
            /// Construct a new empty map with a specified capacity, using a specialized key type.
212
            ///
213
            /// See
214
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::with_capacity_and_key()`].")]
215
126479
            pub fn with_capacity_and_key(capacity: usize) -> Self {
216
126479
                Self {
217
126479
                    base: slotmap::$mapname::with_capacity_and_key(capacity),
218
126479
                    n_unusable: 0,
219
126479
                    _valid: [<validate_ $mapname:snake _behavior>](),
220
126479
                }
221
126479
            }
222

            
223
            /// Return the number of items in this map.
224
            ///
225
            /// See
226
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::len()`].")]
227
2686
            pub fn len(&self) -> usize {
228
2686
                self.base
229
2686
                    .len()
230
2686
                    .checked_sub(self.n_unusable)
231
2686
                    .expect("logic error")
232
2686
            }
233

            
234
            /// Return true if this map has no items.
235
            ///
236
            /// See
237
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::is_empty()`].")]
238
54
            pub fn is_empty(&self) -> bool {
239
54
                self.len() == 0
240
54
            }
241

            
242
            /// Return the total number of slots available for entries in this map.
243
            ///
244
            /// This number includes used slots, as well as empty slots that may become used.
245
            ///
246
            /// See
247
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::capacity()`],")]
248
            /// but note that a `slotmap-careful` implementation may _lose_ capacity over time,
249
            /// as slots are marked unusable.
250
2296
            pub fn capacity(&self) -> usize {
251
2296
                self.base
252
2296
                    .capacity()
253
2296
                    .checked_sub(self.n_unusable)
254
2296
                    .expect("logic error")
255
2296
            }
256

            
257
            /// Reserve space as needed.
258
            ///
259
            /// Allocates if needed, so that this map can hold `additional` new entries
260
            /// without having to resize.
261
            ///
262
            /// See
263
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::reserve()`].")]
264
18
            pub fn reserve(&mut self, additional: usize) {
265
18
                // Note that we don't need to check n_unusable here: the underlying
266
18
                // map type thinks that unusable entries are full, and so will allocate
267
18
                // correctly.
268
18
                self.base.reserve(additional);
269
18
            }
270

            
271
            /// Return true if the map contains an entry with a given key.
272
            ///
273
            /// See
274
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::contains_key()`].")]
275
60
            pub fn contains_key(&self, key: K) -> bool {
276
60
                // Calling self.get, not self.base.get, so it will be None if the
277
60
                // slot is unusable.
278
60
                self.get(key).is_some()
279
60
            }
280

            
281
            /// Insert a new value into the map, and return the key used for it.
282
            ///
283
            /// See
284
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::insert()`].")]
285
117778
            pub fn insert(&mut self, value: V) -> K {
286
117778
                let key = self.base.insert(Entry::Present(value));
287
117778
                debug_assert!(key_okay(key));
288
117778
                key
289
117778
            }
290

            
291
            /// Insert a new value into the map, constructing it using its own new key.
292
            ///
293
            /// This method is useful for the case where a value needs to refer to the
294
            /// key that will be assigned to it.
295
            ///
296
            /// See
297
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::insert_with_key()`].")]
298
6
            pub fn insert_with_key<F>(&mut self, f: F) -> K
299
6
            where
300
6
                F: FnOnce(K) -> V,
301
6
            {
302
6
                let key = self.base.insert_with_key(|k| Entry::Present(f(k)));
303
6
                debug_assert!(key_okay(key));
304
6
                key
305
6
            }
306

            
307
            /// As [`Self::insert_with_key`], but may return an `Err`.
308
            ///
309
            /// See
310
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::try_insert_with_key()`].")]
311
12
            pub fn try_insert_with_key<F, E>(&mut self, f: F) -> Result<K, E>
312
12
            where
313
12
                F: FnOnce(K) -> Result<V, E>,
314
12
            {
315
12
                let key = self
316
12
                    .base
317
12
                    .try_insert_with_key(|k| Ok(Entry::Present(f(k)?)))?;
318
6
                debug_assert!(key_okay(key));
319
6
                Ok(key)
320
12
            }
321

            
322
            /// Remove and return the element of this map with a given key.
323
            ///
324
            /// Return None if the key is not present in the map.
325
            ///
326
            /// See
327
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::remove()`].")]
328
75436
            pub fn remove(&mut self, key: K) -> Option<V> {
329
75436
                if key_version_is_maximal(key) {
330
                    // The key is as large as it is allowed to get,
331
                    // so we should not actually remove this Entry.
332
96
                    match self.base.get_mut(key) {
333
90
                        Some(slot) => {
334
90
                            // The entry is Present: extract its value and mark it unusable.
335
90
                            let rv = slot.take_and_mark_unusable();
336
90
                            if rv.is_some() {
337
36
                                self.n_unusable += 1;
338
54
                            }
339
90
                            rv
340
                        }
341
                        // The entry is Unusable; treat it as if it weren't there.
342
6
                        None => None,
343
                    }
344
                } else {
345
                    // The Entry::unwrap function will panic if its argument is
346
                    // Entry::Unusable.  But that is impossible in this case,
347
                    // since we already checked key_version_is_maximal() for this key,
348
                    // and our invariant guarantees that, if the value is Entry::Unusable,
349
                    // then key_version(key) == SATURATE_AT_VERSION,
350
                    // so key_version_is_maximal is true.
351
75340
                    self.base.remove(key).map(Entry::unwrap)
352
                }
353
75436
            }
354

            
355
            /// Remove every element of this map that does not satisfy a given predicate.
356
            ///
357
            /// See
358
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::retain()`].")]
359
280
            pub fn retain<F>(&mut self, mut f: F)
360
280
            where
361
280
                F: FnMut(K, &mut V) -> bool,
362
280
            {
363
3728
                self.base.retain(|k, v| {
364
3728
                    let Entry::Present(v_inner) = v else {
365
12
                        return true;
366
                    };
367

            
368
3716
                    if f(k, v_inner) {
369
1676
                        true
370
2040
                    } else if key_version_is_maximal(k) {
371
18
                        self.n_unusable += 1;
372
18
                        *v = Entry::Unusable;
373
18
                        true
374
                    } else {
375
2022
                        false
376
                    }
377
3728
                });
378
280
            }
379

            
380
            /// Remove every element of this map.
381
            ///
382
            /// See
383
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::clear()`].")]
384
18
            pub fn clear(&mut self) {
385
18
                self.retain(|_, _| false);
386
18
            }
387

            
388
            /// Return a reference to the element of this map with a given key.
389
            ///
390
            /// Return None if there is no such element.
391
            ///
392
            /// See
393
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::get()`].")]
394
23590
            pub fn get(&self, key: K) -> Option<&V> {
395
23590
                self.base.get(key).and_then(Entry::value)
396
23590
            }
397
            /// Return a mutable reference to the element of this map with a given key.
398
            ///
399
            /// Return None if there is no such element.
400
            ///
401
            /// See
402
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::get_mut()`].")]
403
25666347
            pub fn get_mut(&mut self, key: K) -> Option<&mut V> {
404
25666347
                self.base.get_mut(key).and_then(|ent| ent.value_mut())
405
25666347
            }
406

            
407
            /// Return an array of mutable references to the elements of this map with a given list
408
            /// of keys.
409
            ///
410
            /// Return None if any key is not present, or if the same key is given twice.
411
            ///
412
            /// See
413
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::get_disjoint_mut()`].")]
414
18
            pub fn get_disjoint_mut<const N: usize>(&mut self, keys: [K; N]) -> Option<[&mut V; N]> {
415
18
                let vals = self.base.get_disjoint_mut(keys)?;
416
                // TODO array::try_map would be preferable, but it isn't stable.
417
18
                if vals.iter().all(|e| matches!(e, Entry::Present(_))) {
418
                    // Cannot panic, since we checked that every entry is present.
419
12
                    Some(vals.map(|v| match v {
420
12
                        Entry::Present(v) => v,
421
                        Entry::Unusable => panic!("Logic error"),
422
12
                    }))
423
                } else {
424
6
                    None
425
                }
426
18
            }
427

            
428
            /// Return an iterator over the elements of this map.
429
            ///
430
            /// See
431
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::iter()`].")]
432
            ///
433
            /// # Current limitations
434
            ///
435
            /// Does not return a named type.
436
82226
            pub fn iter(&self) -> impl Iterator<Item = (K, &V)> + '_ {
437
104648
                self.base.iter().filter_map(|(k, v)| match v {
438
104630
                    Entry::Present(v) => Some((k, v)),
439
18
                    Entry::Unusable => None,
440
104648
                })
441
82226
            }
442

            
443
            /// Remove every element of this map.
444
            ///
445
            /// See
446
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::drain()`].")]
447
558
            pub fn drain(&mut self) -> impl Iterator<Item = (K, V)> + '_ {
448
588
                self.base.drain().filter_map(|(k, v)| match v {
449
384
                    Entry::Present(v) => Some((k, v)),
450
                    Entry::Unusable => None,
451
588
                })
452
558
            }
453

            
454
            /// Return a mutable iterator over the elements of this map.
455
            ///
456
            /// See
457
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::iter_mut()`].")]
458
            ///
459
            /// # Current limitations
460
            ///
461
            /// Does not return a named type.
462
38
            pub fn iter_mut(&mut self) -> impl Iterator<Item = (K, &mut V)> + '_ {
463
144
                self.base.iter_mut().filter_map(|(k, v)| match v {
464
138
                    Entry::Present(v) => Some((k, v)),
465
6
                    Entry::Unusable => None,
466
144
                })
467
38
            }
468

            
469
            /// Return an iterator over all the keys in this map.
470
            ///
471
            /// See
472
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::keys()`].")]
473
            ///
474
            /// # Current limitations
475
            ///
476
            /// Does not return a named type.
477
20
            pub fn keys(&self) -> impl Iterator<Item = K> + '_ {
478
38
                self.iter().map(|(k, _)| k)
479
20
            }
480

            
481
            /// Return an iterator over the values in this map.
482
            ///
483
            /// See
484
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::values()`].")]
485
            ///
486
            /// # Current limitations
487
            ///
488
            /// Does not return a named type.
489
24
            pub fn values(&self) -> impl Iterator<Item = &V> + '_ {
490
24
                self.base.values().filter_map(Entry::value)
491
24
            }
492

            
493
            /// Return a mutable iterator over the values in this map.
494
            ///
495
            /// See
496
            #[doc= concat!("[`slotmap::", stringify!($mapname), "::values_mut()`].")]
497
            ///
498
            /// # Current limitations
499
            ///
500
            /// Does not return a named type.
501
14
            pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> + '_ {
502
14
                self.base.values_mut().filter_map(Entry::value_mut)
503
14
            }
504

            
505
            /// Testing helper: Assert that every invariant holds for this map.
506
            ///
507
            /// # Panics
508
            ///
509
            /// Panics if any invariant does not hold.
510
            #[cfg(test)]
511
162
            fn assert_rep_ok(&self) {
512
162
                let mut n_unusable_found = 0;
513
282
                for (k, v) in self.base.iter() {
514
282
                    assert!(key_okay(k), "Key {:?} was invalid", k.data());
515
282
                    if matches!(v, Entry::Unusable) {
516
144
                        n_unusable_found += 1;
517
144
                        assert_eq!(key_version(k), SATURATE_AT_VERSION);
518
138
                    }
519
                }
520
162
                assert_eq!(n_unusable_found, self.n_unusable);
521
162
            }
522
        }
523

            
524
        /// Helper: a token constructed if the slotmap behavior matches our expectations.
525
        ///
526
        /// See `validate_*_behavior()`
527
        #[derive(Clone, Debug)]
528
        struct [<$mapname ValidationToken>];
529

            
530
        /// Spot-check whether `SlotMap` has changed its key encoding behavior; panic if so.
531
        ///
532
        /// (Our implementation relies on our ability to check whether a version number is about to
533
        /// overflow. But the only efficient way to access a version number is via `KeyData::as_ffi`,
534
        /// which does not guarantee anything about the actual encoding of the versions.)
535
        ///
536
        /// This function returns a ZST ValidationToken; nothing else must return one.
537
        /// Being able to construct a ValidationToken implies
538
        /// that `slotmap` has probably not changed its behavior in a way that will break us.
539
        ///
540
        /// # Panics
541
        ///
542
        /// May panic if slotmap does not encode its keys in the expected manner.
543
207994
        fn [<validate_ $mapname:snake _behavior>]() -> [<$mapname ValidationToken>] {
544
            use std::sync::atomic::{AtomicBool, Ordering::Relaxed};
545
            /// Helper:
546
            static VALIDATED: AtomicBool = AtomicBool::new(false);
547
207994
            if VALIDATED.load(Relaxed) {
548
                // We have already validated it at least once.
549
206528
                return [<$mapname ValidationToken>];
550
1466
            }
551
            /// Helper: assert that key has bit 32 set.
552
4398
            fn ver_lsb_check<K: Key>(key: K) {
553
4398
                let (ver, _) = key_data::key_data_parts(key.data()).expect("slotmap has changed its serde representation");
554
4398
                assert_eq!(ver & 1, 1,
555
                    "Key version LSB not set as expected"
556
                );
557
4398
            }
558

            
559
1466
            let mut map = slotmap::$mapname::new();
560
1466
            let k1 = map.insert("a");
561
1466
            assert_eq!(key_version(k1), 0, "Keys do not begin with version 0.");
562
1466
            assert_eq!(key_slot(k1), 1, "Keys do not begin with index 1.");
563
1466
            ver_lsb_check(k1);
564
1466

            
565
1466
            // This is a basic correctness check.
566
1466
            map.remove(k1).expect("insert+remove failed");
567
1466
            let k2 = map.insert("b");
568
1466
            assert_eq!(key_slot(k1), key_slot(k2), "Slot not re-used as expected.");
569
1466
            assert_eq!(
570
1466
                key_version(k1) + 1,
571
1466
                key_version(k2),
572
                "Key version did not increment by 1 after slot reuse"
573
            );
574
1466
            ver_lsb_check(k2);
575
1466

            
576
1466
            let k3 = map.insert("c");
577
1466
            assert_eq!(
578
1466
                key_version(k3),
579
                0,
580
                "A different slot did not begin with version 0.",
581
            );
582
1466
            assert_eq!(
583
1466
                key_slot(k3),
584
1466
                key_slot(k1) + 1,
585
                "Slots not allocated in expected order."
586
            );
587
1466
            ver_lsb_check(k3);
588
1466

            
589
1466
            // Remember that we've validated SlotMap.
590
1466
            VALIDATED.store(true, Relaxed);
591
1466
            [<$mapname ValidationToken>]
592
207994
        }
593
    }
594

            
595
    impl<K:Key, V> std::ops::Index<K> for $mapname<K,V> {
596
        type Output = V;
597
118
        fn index(&self, key: K) -> &V {
598
118
            self.get(key).expect("key invalid")
599
118
        }
600
    }
601
    impl<K:Key, V> std::ops::IndexMut<K> for $mapname<K,V> {
602
6
        fn index_mut(&mut self, key: K) -> &mut V {
603
6
            self.get_mut(key).expect("key invalid")
604
6
        }
605
    }
606
}} // END OF MACRO.
607

            
608
define_implementation! { SlotMap }
609

            
610
define_implementation! { DenseSlotMap }
611

            
612
define_implementation! { HopSlotMap }
613

            
614
/// Return true if this key is apparently valid.
615
///
616
/// We should use debug_assert! to test this on every new key, every time an entry is inserted.
617
///
618
/// If inserting an entry results in a _not_ valid key,
619
/// we have messed up, and allowed a version counter to grow too high.
620
118072
fn key_okay<K: Key>(key: K) -> bool {
621
118072
    key_version(key) <= SATURATE_AT_VERSION
622
118072
}
623

            
624
/// Return true if the version number for this key should not be allowed to grow any larger.
625
///
626
/// We should call this whenever we are about to remove an entry with a given key.
627
/// If it returns true, we should instead replace the entry with [`Entry::Unusable`]
628
77470
fn key_version_is_maximal<K: Key>(key: K) -> bool {
629
77470
    key_version(key) == SATURATE_AT_VERSION
630
77470
}
631
/// The maximal version that we allow a key to reach.
632
///
633
/// When it reaches this version, we do not remove the entry with the key any longer;
634
/// instead, when we would remove the entry, we instead set its value to [`Entry::Unusable`]
635
///
636
/// This value is deliberately chosen to be less than the largest possible value (`0x7fff_ffff`),
637
/// so that we can detect any bugs that would risk overflowing the version.
638
const SATURATE_AT_VERSION: u32 = 0x7fff_fffe;
639

            
640
/// Helper: return the slot of a key, assuming that the representation is as we expect.
641
///
642
/// Used for testing and verify functions.
643
7390
fn key_slot<K: Key>(key: K) -> u32 {
644
7390
    let (_, idx) =
645
7390
        key_data::key_data_parts(key.data()).expect("slotmap has changed its serde representation");
646
7390
    idx
647
7390
}
648

            
649
#[cfg(test)]
650
mod test {
651
    // @@ begin test lint list maintained by maint/add_warning @@
652
    #![allow(clippy::bool_assert_comparison)]
653
    #![allow(clippy::clone_on_copy)]
654
    #![allow(clippy::dbg_macro)]
655
    #![allow(clippy::mixed_attributes_style)]
656
    #![allow(clippy::print_stderr)]
657
    #![allow(clippy::print_stdout)]
658
    #![allow(clippy::single_char_pattern)]
659
    #![allow(clippy::unwrap_used)]
660
    #![allow(clippy::unchecked_duration_subtraction)]
661
    #![allow(clippy::useless_vec)]
662
    #![allow(clippy::needless_pass_by_value)]
663
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
664

            
665
    /// Create a new key, using `ver` as its version field (includes trailing 1)
666
    /// and `idx` as its index field.
667
    fn construct_key(ver: u32, idx: u32) -> slotmap::DefaultKey {
668
        let j = serde_json::json! {
669
            {
670
                "version": ver,
671
                "idx": idx,
672
            }
673
        };
674
        serde_json::from_value(j).expect("invalid representation")
675
    }
676

            
677
    /// Define a set of tests for one of the map variants, in a module named after that variant.
678
    macro_rules! tests_for {
679
            { $mapname:ident } => {paste::paste!{
680

            
681
            mod [<$mapname:snake>] {
682

            
683
                use slotmap::DefaultKey;
684
                use crate::*;
685

            
686
            #[test]
687
            fn validate() {
688
                let _tok = [<validate_ $mapname:snake _behavior>]();
689
            }
690

            
691
            #[test]
692
            fn empty() {
693
                let mut m: $mapname<DefaultKey, ()> = $mapname::default();
694

            
695
                for _ in 1..=3 {
696
                    assert_eq!(m.len(), 0);
697
                    assert!(m.is_empty());
698
                    m.assert_rep_ok();
699

            
700
                    let k1 = m.insert(());
701
                    let k2 = m.insert(());
702
                    let k3 = m.insert(());
703
                    m.remove(k1);
704
                    m.remove(k2);
705
                    m.remove(k3);
706
                }
707
            }
708

            
709
            fn construct_near_saturated_slotmap() -> ($mapname<DefaultKey, String>, DefaultKey, DefaultKey) {
710
                fn encode_ver(v: u32) -> u32 {
711
                    (v << 1) | 1
712
                }
713

            
714
                let json = serde_json::json! {
715
                    [
716
                        // sentinel entry.
717
                        { "value": null, "version": 0},
718
                        { "value": {"Present": "hello"}, "version": encode_ver(SATURATE_AT_VERSION) },
719
                        { "value": {"Present": "world"}, "version": encode_ver(SATURATE_AT_VERSION - 2) }
720
                    ]
721
                };
722

            
723
                let m = $mapname {
724
                    base: serde_json::from_value(json).expect("invalid json"),
725
                    n_unusable: 0,
726
                    _valid: [<validate_ $mapname:snake _behavior>](),
727
                };
728
                let mut k1 = None;
729
                let mut k2 = None;
730

            
731
                for (k, v) in m.iter() {
732
                    if v == "hello" {
733
                        k1 = Some(k);
734
                    }
735
                    if v == "world" {
736
                        k2 = Some(k);
737
                    }
738
                }
739
                let (k1, k2) = (k1.unwrap(), k2.unwrap());
740
                (m, k1, k2)
741
            }
742

            
743
            #[test]
744
            #[allow(clippy::cognitive_complexity)]
745
            fn saturating() {
746
                let (mut m, k1, k2) = construct_near_saturated_slotmap();
747

            
748
                assert_eq!(key_version(k1), SATURATE_AT_VERSION);
749
                assert_eq!(key_version(k2), SATURATE_AT_VERSION - 2);
750

            
751
                // Replace k1, and make sure that the index is _not_ reused.
752
                let v = m.remove(k1);
753
                assert_eq!(v.unwrap(), "hello");
754
                assert!(matches!(m.base.get(k1), Some(Entry::Unusable)));
755
                let k1_new = m.insert("HELLO".into());
756
                assert_ne!(key_slot(k1), key_slot(k1_new));
757
                assert_eq!(key_version(k1_new), 0);
758
                assert!(matches!(m.base.get(k1), Some(Entry::Unusable)));
759
                assert_eq!(m.get(k1_new).unwrap(), "HELLO");
760
                assert!(m.get(k1).is_none());
761
                m.assert_rep_ok();
762

            
763
                // Replace k2 and make sure that that the index gets reused twice.
764
                let v = m.remove(k2);
765
                assert_eq!(v.unwrap(), "world");
766
                let k2_2 = m.insert("WoRlD".into());
767
                assert_eq!(key_version(k2_2), SATURATE_AT_VERSION - 1);
768
                m.remove(k2_2);
769
                m.assert_rep_ok();
770
                assert!(m.base.get(k2_2).is_none());
771
                let k2_3 = m.insert("WORLD".into());
772
                assert_eq!(key_slot(k2), key_slot(k2_2));
773
                assert_eq!(key_slot(k2), key_slot(k2_3));
774
                assert_eq!(key_version(k2_3), SATURATE_AT_VERSION);
775
                m.remove(k2_3);
776
                assert!(m.base.get(k2_2).is_none());
777
                m.assert_rep_ok();
778

            
779
                let k2_4 = m.insert("World!".into());
780
                assert!(matches!(m.base.get(k2_3), Some(Entry::Unusable)));
781
                assert_eq!(m.get(k2_4).unwrap(), "World!");
782
                assert_ne!(key_slot(k2_4), key_slot(k2));
783
                assert!(m.contains_key(k2_4));
784
                assert!(!m.contains_key(k2_3));
785
                m.assert_rep_ok();
786
            }
787

            
788
            #[test]
789
            fn insert_variations() {
790
                let mut m = $mapname::new();
791
                let k1 = m.insert("hello".to_string());
792
                let k2 = m.insert_with_key(|k| format!("{:?}", k));
793
                let k3 = m
794
                    .try_insert_with_key(|k| Result::<_, ()>::Ok(format!("{:?}", k)))
795
                    .unwrap();
796
                let () = m.try_insert_with_key(|_k| Err(())).unwrap_err();
797

            
798
                assert!(m.contains_key(k1));
799
                assert!(m.contains_key(k2));
800
                assert!(m.contains_key(k3));
801
                assert_eq!(m.len(), 3);
802
            }
803

            
804
            #[test]
805
            fn remove_large_but_bogus() {
806
                let mut m: $mapname<DefaultKey, String> = $mapname::with_capacity(0);
807
                let _k1 = m.insert("hello".to_string());
808
                // Construct a key with maximal version (so we would expect to freeze it),
809
                // but which won't actually be present.
810
                let k_fake = super::construct_key((SATURATE_AT_VERSION << 1) | 1, 1);
811

            
812
                let v = m.remove(k_fake);
813
                assert!(v.is_none());
814
                m.assert_rep_ok();
815
            }
816

            
817
            #[test]
818
            fn remove_many_times() {
819
                let (mut m, k1, _k2) = construct_near_saturated_slotmap();
820

            
821
                let mut n_removed = 0;
822
                for _ in 0..10 {
823
                    if m.remove(k1).is_some() {
824
                        n_removed += 1;
825
                    }
826
                    m.assert_rep_ok();
827
                    assert_eq!(m.n_unusable, 1);
828
                    assert_eq!(m.len(), 1);
829
                }
830
                assert_eq!(n_removed, 1);
831
            }
832

            
833
            #[test]
834
            fn clear() {
835
                let (mut m, k1, k2) = construct_near_saturated_slotmap();
836
                assert_eq!(m.len(), 2);
837
                assert_eq!(m.is_empty(), false);
838
                assert_eq!(m.n_unusable, 0);
839

            
840
                for _ in 0..=2 {
841
                    m.clear();
842
                    m.assert_rep_ok();
843

            
844
                    assert_eq!(m.len(), 0);
845
                    assert_eq!(m.is_empty(), true);
846
                    assert!(m.get(k1).is_none());
847
                    assert!(m.get(k2).is_none());
848
                    assert!(matches!(m.base.get(k1), Some(Entry::Unusable)));
849
                    assert_eq!(m.n_unusable, 1);
850
                }
851

            
852
                let k_next = m.insert("probe".into());
853
                assert_eq!(key_slot(k_next), key_slot(k2));
854
                assert_eq!(key_version(k_next), SATURATE_AT_VERSION - 1);
855
            }
856

            
857
            #[test]
858
            fn retain() {
859
                let (mut m, k1, k2) = construct_near_saturated_slotmap();
860

            
861
                // drop all but the nearly-saturated (but not saturated) "world" item.
862
                m.retain(|_k, v| v == "world");
863
                m.assert_rep_ok();
864
                assert_eq!(m.len(), 1);
865
                assert!(!m.is_empty());
866
                assert_eq!(m.n_unusable, 1);
867
                assert_eq!(m.contains_key(k1), false);
868
                assert_eq!(m.contains_key(k2), true);
869
                assert_eq!(m.base.contains_key(k1), true); // key still internally present as Unusable.
870

            
871
                let (mut m, k1, k2) = construct_near_saturated_slotmap();
872

            
873
                // drop all but the saturated (but not saturated) "hello" item.
874
                m.retain(|_k, v| v == "hello");
875
                m.assert_rep_ok();
876
                assert_eq!(m.len(), 1);
877
                assert!(!m.is_empty());
878
                assert_eq!(m.n_unusable, 0);
879
                assert_eq!(m.contains_key(k1), true);
880
                assert_eq!(m.contains_key(k2), false);
881
                assert_eq!(m.base.contains_key(k2), false); // key not present.
882
            }
883

            
884
            #[test]
885
            fn retain_and_panic() {
886
                use std::panic::AssertUnwindSafe;
887
                let (mut m, k1, _k2) = construct_near_saturated_slotmap();
888

            
889
                let _ = std::panic::catch_unwind(AssertUnwindSafe(|| {
890
                    m.retain(|k,_| if k == k1 { false } else { panic!() })
891
                })).unwrap_err();
892
                m.assert_rep_ok();
893
            }
894

            
895
            #[test]
896
            fn modify() {
897
                let (mut m, k1, k2) = construct_near_saturated_slotmap();
898

            
899
                *m.get_mut(k1).unwrap() = "HELLO".to_string();
900
                *m.get_mut(k2).unwrap() = "WORLD".to_string();
901

            
902
                let v: Vec<_> = m.values().collect();
903
                assert_eq!(v, vec![&"HELLO".to_string(), &"WORLD".to_string()]);
904
            }
905

            
906
            #[test]
907
            fn iterators() {
908
                let (mut m, k1, k2) = construct_near_saturated_slotmap();
909

            
910
                m.remove(k1);
911
                assert_eq!(m.n_unusable, 1);
912

            
913
                for v in m.values_mut() {
914
                    *v = "WORLD".to_string();
915
                }
916

            
917
                let v: Vec<_> = m.values().collect();
918
                assert_eq!(v, vec![&"WORLD".to_string()]);
919

            
920
                let v: Vec<_> = m.iter().collect();
921
                assert_eq!(v, vec![(k2, &"WORLD".to_string())]);
922

            
923
                for (k, v) in m.iter_mut() {
924
                    assert_eq!(k, k2);
925
                    *v = "World".to_string();
926
                }
927

            
928
                let v: Vec<_> = m.iter().collect();
929
                assert_eq!(v, vec![(k2, &"World".to_string())]);
930

            
931
                let v: Vec<_> = m.keys().collect();
932
                assert_eq!(v, vec![k2]);
933

            
934
                m.assert_rep_ok();
935
            }
936

            
937
            #[test]
938
            fn get_mut_multiple() {
939
                let (mut m, k1, k2) = construct_near_saturated_slotmap();
940

            
941
                assert!(m.get_disjoint_mut([k1,k1]).is_none());
942

            
943
                if let Some([v1, v2]) = m.get_disjoint_mut([k1, k2]) {
944
                    assert_eq!(v1, "hello");
945
                    assert_eq!(v2, "world");
946
                    *v1 = "HELLO".into();
947
                    *v2 = "WORLD".into();
948
                } else {
949
                    panic!("get_disjoint_mut failed.");
950
                };
951

            
952
                m.remove(k1);
953
                assert_eq!(m.contains_key(k1), false);
954
                assert_eq!(m.base.contains_key(k1), true);
955
                m.assert_rep_ok();
956

            
957
                if let Some([_v1, _v2]) = m.get_disjoint_mut([k1, k2]) {
958
                    panic!("get_disjoint_mut succeeded unexpectedly.")
959
                }
960
            }
961

            
962
            #[test]
963
            fn get_capacity() {
964
                let (mut m, k1, _) = construct_near_saturated_slotmap();
965

            
966
                let cap_orig = dbg!(m.capacity());
967
                m.remove(k1);
968
                m.assert_rep_ok();
969

            
970
                assert_eq!(m.n_unusable, 1);
971
                assert_eq!(m.capacity(), cap_orig - 1); // capacity decreased, since there is an unusable slot.
972

            
973
                m.reserve(5);
974
                assert!(m.capacity() >= 5);
975
            }
976

            
977
            #[test]
978
            fn index() {
979
                let (mut m, k1, k2) = construct_near_saturated_slotmap();
980

            
981
                assert_eq!(m[k1], "hello");
982
                assert_eq!(*(&mut m[k2]), "world");
983
            }
984
        } // end module.
985
        }}} // End macro rules
986

            
987
    tests_for! {SlotMap}
988
    tests_for! {DenseSlotMap}
989
    tests_for! {HopSlotMap}
990
}