1
//! Declaration for an n-keyed list type, allowing access to each of its members by each of N
2
//! different keys.
3

            
4
// Re-export dependencies that we use to make this macro work.
5
#[doc(hidden)]
6
pub mod deps {
7
    pub use paste::paste;
8
    pub use slab::Slab;
9
    pub use smallvec::SmallVec;
10
}
11

            
12
/// Declare a structure that can hold elements with multiple unique keys.
13
///
14
/// Each element can be looked up by any of its keys. The keys themselves can be any type that
15
/// supports `Hash`, `Eq`, and `Clone`. Elements can have multiple keys of the same type: for
16
/// example, a person can have a username `String` and an irc_handle `String`.
17
///
18
/// Multiple values can be stored for a given key: a lookup of one key returns all elements with
19
/// that key.
20
///
21
/// Keys may be accessed from elements either by field access or by an accessor function.
22
///
23
/// Keys may be optional. If all keys are optional, then we require additionally that every element
24
/// must have at least one key.
25
///
26
/// # Examples
27
///
28
/// ```
29
/// use tor_basic_utils::n_key_list;
30
///
31
/// // We declare a person struct with several different fields.
32
/// pub struct Person {
33
///     username: String,
34
///     irc_handle: String,
35
///     student_id: Option<u64>,
36
///     favorite_joke: Option<String>,
37
/// }
38
///
39
/// n_key_list! {
40
///     pub struct PersonList for Person {
41
///         // See note on "Key syntax" below.  The ".foo" syntax
42
///         // here means that the value for the key is returned
43
///         // by accessing a given field.
44
///         username: String { .username },
45
///         irc_handle: String { .irc_handle },
46
///         (Option) student_id: u64 { .student_id }
47
///     }
48
/// }
49
///
50
/// let mut people = PersonList::new();
51
/// people.insert(Person {
52
///     username: "mina".into(),
53
///     irc_handle: "pashMina".into(),
54
///     student_id: None,
55
///     favorite_joke: None,
56
/// });
57
/// assert_eq!(people.by_username("mina").len(), 1);
58
/// assert_eq!(people.by_irc_handle("pashMina").len(), 1);
59
/// ```
60
///
61
/// # Key syntax
62
///
63
/// You can tell the map to access the keys of an element in any of several ways.
64
///
65
/// * `name : type { func() }` - A key whose name is `name` and type is `type`, that can be accessed
66
///   from a given element by calling `element.func()`.
67
/// * `name : type { .field }` - A key whose name is `name` and type is `type`, that can be accessed
68
///   from a given element by calling `&element.field`.
69
/// * `name : type` - Short for as `name : type { name() }`.
70
///
71
/// If a key declaration is preceded with `(Option)`, then the key is treated as optional, and
72
/// accessor functions are expected to return `Option<&Type>`.
73
///
74
/// # Additional features
75
///
76
/// You can put generic parameters and `where` constraints on your structure. The `where` clause (if
77
/// present) must be wrapped in square brackets.
78
///
79
/// If you need to use const generics or lifetimes in your structure, you need to use square
80
/// brackets instead of angle brackets, and specify both the generic parameters *and* the type that
81
/// you are implementing. (This is due to limitations in the Rust macro system.)  For example:
82
///
83
/// ```
84
/// # use tor_basic_utils::n_key_list;
85
/// n_key_list!{
86
///     struct['a, T, const N: usize] ArrayMap2['a, T, N] for (String, [&'a T;N])
87
///         [ where T: Clone + 'a ]
88
///     {
89
///          name: String { .0 }
90
///     }
91
/// }
92
/// ```
93
#[macro_export]
94
macro_rules! n_key_list {
95
{
96
    $(#[$meta:meta])*
97
    $vis:vis struct $mapname:ident $(<$($P:ident),*>)? for $V:ty
98
    $( where [ $($constr:tt)+ ] )?
99
    {
100
        $($body:tt)+
101
    }
102
} => {
103
n_key_list!{
104
    $(#[$meta])*
105
    $vis struct [$($($P),*)?] $mapname [$($($P),*)?] for $V
106
    $( [ where $($constr)+ ] )?
107
    {
108
        $( $body )+
109
    }
110
}
111
};
112
{
113
    $(#[$meta:meta])*
114
    $vis:vis struct [$($($G:tt)+)?] $mapname:ident [$($($P:tt)+)?] for $V:ty
115
    $( [ where $($constr:tt)+ ])?
116
    {
117
        $( $(( $($flag:ident)+ ))? $key:ident : $KEY:ty $({ $($source:tt)+ })? ),+
118
        $(,)?
119
    }
120
} => {
121
$crate::n_key_list::deps::paste!{
122
    $( #[$meta] )*
123
    /// # General information
124
    ///
125
    #[doc = concat!(
126
        "A list of elements of type `", stringify!($V), "` whose members can be accessed by multiple keys."
127
    )]
128
    ///
129
    /// The keys are:
130
    ///
131
    #[doc = $( "- `" $key "` (`" $KEY "`)" $(" (" $($flag)+ ")\n" )? )+]
132
    ///
133
    /// Each element has a value for *each* required key, and up to one value for *each* optional
134
    /// key. There can be many elements for a given key value.
135
    ///
136
    /// ## Requirements
137
    ///
138
    /// Key types must have consistent `Hash` and `Eq` implementations, as they will be used as keys
139
    /// in a `HashMap`.
140
    ///
141
    /// If all keys are optional, then every element inserted must have at least one non-`None` key.
142
    ///
143
    /// An element must not change its keys over time through interior mutability.
144
    ///
145
    /// <div class='warning'>
146
    ///
147
    /// If *any* of these rules is violated, the consequences are unspecified, and could include
148
    /// panics or wrong answers (but not memory-unsafety).
149
    ///
150
    /// </div>
151
114
    $vis struct $mapname $(<$($G)*>)?
152
114
    where
153
114
        $( $KEY : std::hash::Hash + Eq + Clone , )+
154
114
        $($($constr)+, )?
155
114
    {
156
114
        /// The $key fields here are a set of maps from each of the key values to the lists of the
157
114
        /// positions of values with the same key within the Slab.
158
114
        ///
159
114
        /// Invariants:
160
114
        ///   - There is an entry K=>idx in the map `$key` if and only if values[idx].$accessor() ==
161
114
        ///     K.
162
114
        ///   - Every value in `values` has at least one key.
163
114
        ///   - A list should never be empty.
164
114
        ///
165
114
        /// The map values (the lists) are effectively a set, but using an inline vec should have
166
114
        /// better cache performance than something like HashSet.
167
114
        ///
168
114
        /// The SmallVec size of 4 was chosen arbitrarily under the assumption that a given key will
169
114
        /// have a small number of values on average. The exact constant probably won't matter, but
170
114
        /// inlining most of the lists should be good even if some spill into separate memory
171
114
        /// allocations. It's not worth exposing this level of internal detail to the macro caller
172
114
        /// unless there's a reason we need to.
173
114
        $([<$key _map>]: std::collections::HashMap<$KEY, $crate::n_key_list::deps::SmallVec<[usize; 4]>> , )+
174
114

            
175
114
        /// A map from the indices to the values.
176
114
        values: $crate::n_key_list::deps::Slab<$V>,
177
114
    }
178
114

            
179
114
    #[allow(dead_code)] // may be needed if this is not public
180
114
    impl $(<$($G)*>)? $mapname $(<$($P)*>)?
181
114
    where
182
114
        $( $KEY : std::hash::Hash + Eq + Clone , )+
183
114
        $($($constr)+)?
184
114
    {
185
114
        #[doc = "Construct a new [`" $mapname "`](Self)."]
186
118
        $vis fn new() -> Self {
187
118
            Self::with_capacity(0)
188
118
        }
189
114

            
190
114
        #[doc = "Construct a new [`" $mapname "`](Self) with a given capacity."]
191
124
        $vis fn with_capacity(n: usize) -> Self {
192
474
            Self {
193
124
                $([<$key _map>]: std::collections::HashMap::with_capacity(n),)*
194
124
                values: $crate::n_key_list::deps::Slab::with_capacity(n),
195
124
            }
196
474
        }
197
428

            
198
428
        // for each key type
199
428
        $(
200
428
        #[doc = "Return an iterator of the elements whose `" $key "` is `key`."]
201
428
        ///
202
428
        /// The iteration order is arbitrary.
203
452
        $vis fn [<by_ $key>] <BorrowAsKey_>(&self, key: &BorrowAsKey_) -> [<$mapname Iter>] <'_, $V>
204
452
        where
205
452
            $KEY : std::borrow::Borrow<BorrowAsKey_>,
206
452
            BorrowAsKey_: std::hash::Hash + Eq + ?Sized,
207
89
        {
208
89
            [<$mapname Iter>] {
209
452
                iter: self.[<$key _map>].get(key).map(|set| set.iter()).unwrap_or([].iter()),
210
452
                values: &self.values,
211
89
            }
212
452
        }
213
89

            
214
89
        #[doc = "Return `true` if this list contains an element whose `" $key "` is `key`."]
215
117
        $vis fn [<contains_ $key>] <BorrowAsKey_>(&mut self, key: &BorrowAsKey_) -> bool
216
117
        where
217
117
            $KEY : std::borrow::Borrow<BorrowAsKey_>,
218
117
            BorrowAsKey_: std::hash::Hash + Eq + ?Sized,
219
96
        {
220
124
            let Some(list) = self.[<$key _map>].get(key) else {
221
100
                return false;
222
96
            };
223
96

            
224
120
            if list.is_empty() {
225
96
                // we're not supposed to let this happen, so panic in debug builds
226
96
                #[cfg(debug_assertions)]
227
96
                panic!("Should not have an empty list");
228
96
                #[cfg(not(debug_assertions))]
229
96
                return false;
230
120
            }
231
96

            
232
120
            true
233
124
        }
234
96

            
235
96
        #[doc = "Remove and return the elements whose `" $key "` is `key`"]
236
96
        /// and where `filter` returns `true`.
237
100
        $vis fn [<remove_by_ $key>] <BorrowAsKey_>(
238
100
            &mut self,
239
100
            key: &BorrowAsKey_,
240
100
            mut filter: impl FnMut(&$V) -> bool,
241
100
        ) -> Vec<$V>
242
100
        where
243
100
            $KEY : std::borrow::Borrow<BorrowAsKey_>,
244
100
            BorrowAsKey_: std::hash::Hash + Eq + ?Sized,
245
62
        {
246
100
            let idx_list: Vec<usize> = {
247
100
                let Some(set) = self.[<$key _map>].get(key) else {
248
62
                    return Vec::new();
249
62
                };
250
62

            
251
100
                set
252
100
                    .iter()
253
120
                    .filter(|&&idx| filter(self.values.get(idx).expect("inconsistent state")))
254
100
                    .copied()
255
100
                    .collect()
256
62
            };
257
62

            
258
100
            let mut removed = Vec::with_capacity(idx_list.len());
259
106
            for idx in idx_list {
260
106
                removed.push(self.remove_at(idx).expect("inconsistent state"));
261
106
            }
262
62

            
263
100
            removed
264
100
        }
265
62
        )+
266
62

            
267
2100
        fn remove_at(&mut self, idx: usize) -> Option<$V> {
268
2100
            if let Some(removed) = self.values.try_remove(idx) {
269
62
                $(
270
2100
                let $key = $crate::n_key_list!( @access(removed, ($($($flag)+)?) $key : $KEY $({$($source)+})?) );
271
2092
                if let Some($key) = $key {
272
2092
                    let set = self.[<$key _map>].get_mut($key).expect("inconsistent state");
273
62

            
274
62
                    #[cfg(debug_assertions)]
275
2092
                    let size_before_remove = set.len();
276
62

            
277
62
                    // a `swap_retain` if it existed might be nice here, but the set should be small
278
62
                    // so shifting all later elements should be fine
279
4148
                    set.retain(|x| *x != idx);
280
62

            
281
62
                    #[cfg(debug_assertions)]
282
2092
                    assert_ne!(set.len(), size_before_remove, "should have removed at least one element");
283
62

            
284
62
                    // don't leave entries around with empty lists
285
2092
                    if set.is_empty() {
286
2076
                        self.[<$key _map>].remove($key);
287
2078
                    }
288
70
                }
289
62
                )*
290
2100
                Some(removed)
291
62
            } else {
292
62
                None
293
62
            }
294
2100
        }
295
62

            
296
62
        /// Return an iterator over the elements in this container.
297
64
        $vis fn values(&self) -> impl Iterator<Item=&$V> + '_ {
298
64
            self.values.iter().map(|(_, v)| v)
299
64
        }
300

            
301
        /// Consume this container and return an iterator of its values.
302
6
        $vis fn into_values(self) -> impl Iterator<Item=$V> {
303
202
            self.values.into_iter().map(|(_, v)| v)
304
202
        }
305
196

            
306
196
        /// Try to insert `value`.
307
196
        ///
308
196
        /// Return `Error::NoKeys` if all the keys are optional, and `value` has no keys at all.
309
2236
        $vis fn try_insert(&mut self, value: $V) -> Result<(), $crate::n_key_list::Error> {
310
2236
            if self.capacity() > 32 && self.len() < self.capacity() / 4 {
311
114
                // we have the opportunity to free up a fair amount of space; let's take it
312
118
                self.compact()
313
2232
            }
314
114

            
315
2236
            let mut some_key_found = false;
316
114

            
317
114
            $(
318
2236
            let $key = $crate::n_key_list!( @access(value, ($($($flag)+)?) $key : $KEY $({$($source)+})?) );
319
2236
            some_key_found |= $key.is_some();
320
114
            )*
321
114

            
322
2236
            if !some_key_found {
323
114
                // exit early before we add it to `values`
324
116
                return Err($crate::n_key_list::Error::NoKeys);
325
2234
            }
326
114

            
327
2234
            let idx = self.values.insert(value);
328
2234
            let value = self.values.get(idx).expect("inconsistent state");
329
114

            
330
114
            $(
331
2234
            let $key = $crate::n_key_list!( @access(value, ($($($flag)+)?) $key : $KEY $({$($source)+})?) );
332
2232
            if let Some($key) = $key {
333
2232
                let set = self.[<$key _map>].entry($key.to_owned()).or_default();
334
2232
                set.push(idx);
335
114

            
336
114
                // we don't want the list's capacity to grow unbounded, so in the (hopefully) rare
337
114
                // case that the list grows large and then small again, try to free some of the
338
114
                // memory
339
2232
                if set.capacity() > 64 && set.len() < set.capacity() / 4 {
340
                    set.shrink_to_fit();
341
2226
                }
342
114

            
343
114
                // TODO: would it be beneficial to aggressively shrink the list if `len()` is
344
114
                // smaller than `inline_size()`?
345
116
            }
346
114
            )*
347
114

            
348
2234
            Ok(())
349
2236
        }
350
114

            
351
114
        /// See [`try_insert`](Self::try_insert). Panicks on errors.
352
2152
        $vis fn insert(&mut self, value: $V) {
353
2152
            self.try_insert(value)
354
2152
                .expect("tried to add a value with no key")
355
2152
        }
356
10

            
357
10
        /// Return the number of elements in this container.
358
1974
        $vis fn len(&self) -> usize {
359
2146
            self.values.len()
360
2146
        }
361
174

            
362
174
        /// Return `true` if there are no elements in this container.
363
176
        $vis fn is_empty(&self) -> bool {
364
198
            let is_empty = self.len() == 0;
365
196

            
366
196
            #[cfg(debug_assertions)]
367
198
            if is_empty {
368
198
                $(assert!(self.[<$key _map>].is_empty());)*
369
196
            }
370
196

            
371
198
            is_empty
372
198
        }
373
196

            
374
196
        /// Return the number of elements for which this container has allocated storage.
375
4182
        $vis fn capacity(&self) -> usize {
376
4182
            self.values.capacity()
377
4182
        }
378
8

            
379
8
        /// Remove every element that does not satisfy the predicate `pred`.
380
10
        $vis fn retain<F>(&mut self, mut pred: F)
381
10
        where
382
10
            F: FnMut(&$V) -> bool,
383
        {
384
2088
            for idx in 0..self.values.capacity() {
385
2088
                if self.values.get(idx).map(&mut pred) == Some(false) {
386
1994
                    self.remove_at(idx);
387
2010
                }
388
            }
389
10
        }
390

            
391
        /// Re-index all the values in this map, so that the map can use a more compact
392
        /// representation.
393
        ///
394
        /// This should be done infrequently; it's expensive.
395
4
        fn compact(&mut self) {
396
4
            let old_value = std::mem::replace(self, Self::with_capacity(self.len()));
397
18
            for item in old_value.into_values() {
398
18
                self.insert(item);
399
18
            }
400
4
        }
401

            
402
        /// Assert that this list appears to be in an internally consistent state.
403
        ///
404
        /// This method can be very expensive, and it should never fail unless your code has a bug.
405
        ///
406
        /// # Panics
407
        ///
408
        /// Panics if it finds bugs in this object, or constraint violations in its elements. See
409
        /// the (type documentation)[Self#Requirements] for a list of constraints.
410
        // it would be nice to run this after every operation that mutates internal state in debug
411
        // builds, but this function is way too slow for that
412
18
        fn check_consistency(&self) {
413
            // ensure each value is in exactly the correct maps
414
2064
            for (idx, value) in &self.values {
415
                $(
416
2064
                    let $key = $crate::n_key_list!( @access(value, ($($($flag)+)?) $key : $KEY $({$($source)+})?) );
417
2062
                    if let Some($key) = $key {
418
                        // check that it exists in the set that it should be in
419
2062
                        let set = self.[<$key _map>].get($key).expect("inconsistent state");
420
2062
                        assert!(set.contains(&idx));
421
                        // check that it does not exist in any set that it should not be in
422
4000792
                        for (_key, set) in self.[<$key _map>].iter().filter(|(key, _)| *key != $key) {
423
1998336
                            assert!(!set.contains(&idx));
424
                        }
425
                    } else {
426
                        // check that it does not exist in any set
427
2
                        for set in self.[<$key _map>].values() {
428
2
                            assert!(!set.contains(&idx));
429
                        }
430
                    }
431
                )*
432
            }
433

            
434
            $(
435
2054
                for set in self.[<$key _map>].values() {
436
                    // ensure no sets have dangling idxs
437
2062
                    for idx in set {
438
2062
                        assert!(self.values.contains(*idx));
439
                    }
440

            
441
                    // ensure no sets have duplicate idxs
442
2054
                    let mut set_iter = set.iter();
443
4116
                    while let Some(idx) = set_iter.next() {
444
2062
                        assert!(!set_iter.clone().any(|x| x == idx));
445
                    }
446

            
447
                    // ensure no sets are empty
448
2054
                    assert!(!set.is_empty());
449
                }
450
            )*
451

            
452
            // ensure that if a value is in a key's map, then the value really has that key
453
            $(
454
2054
                for (key, set) in &self.[<$key _map>] {
455
2062
                    for idx in set {
456
2062
                        let value = self.values.get(*idx).expect("inconsistent state");
457
2062
                        let $key = $crate::n_key_list!( @access(value, ($($($flag)+)?) $key : $KEY $({$($source)+})?) );
458
2062
                        let $key = $key.expect("inconsistent state");
459
2062
                        assert!(key == $key);
460
                    }
461
                }
462
            )*
463
18
        }
464
    }
465

            
466
    impl $(<$($G)*>)? Default for $mapname $(<$($P)*>)?
467
    where
468
        $( $KEY : std::hash::Hash + Eq + Clone , )+
469
        $($($constr)+)?
470
    {
471
        fn default() -> Self {
472
            $mapname::new()
473
        }
474
    }
475

            
476
    impl $(<$($G)*>)? std::iter::FromIterator<$V> for $mapname $(<$($P)*>)?
477
    where
478
        $( $KEY : std::hash::Hash + Eq + Clone , )*
479
        $($($constr)+)?
480
    {
481
2
        fn from_iter<IntoIter_>(iter: IntoIter_) -> Self
482
2
        where
483
2
            IntoIter_: std::iter::IntoIterator<Item = $V>,
484
        {
485
2
            let iter = iter.into_iter();
486
2
            let mut list = Self::with_capacity(iter.size_hint().0);
487
2000
            for value in iter {
488
2000
                list.insert(value);
489
2000
            }
490
2
            list
491
2
        }
492
    }
493

            
494
    #[doc = "An iterator for [`" $mapname "`](" $mapname ")."]
495
    $vis struct [<$mapname Iter>] <'a, T> {
496
        iter: std::slice::Iter<'a, usize>,
497
        values: &'a $crate::n_key_list::deps::Slab<T>,
498
    }
499

            
500
    impl<'a, T> std::iter::Iterator for [<$mapname Iter>] <'a, T> {
501
        type Item = &'a T;
502

            
503
670
        fn next(&mut self) -> std::option::Option<Self::Item> {
504
670
            self.iter.next().map(|idx| self.values.get(*idx).expect("inconsistent state"))
505
670
        }
506

            
507
        #[inline]
508
72
        fn size_hint(&self) -> (usize, std::option::Option<usize>) {
509
72
            self.iter.size_hint()
510
72
        }
511
    }
512

            
513
    impl<'a, T> std::iter::ExactSizeIterator for [<$mapname Iter>] <'a, T>
514
    where
515
        // no harm in specifying it here, even though it should always be true
516
        std::slice::Iter<'a, usize>: std::iter::ExactSizeIterator,
517
    {
518
        #[inline]
519
28
        fn len(&self) -> usize {
520
28
            self.iter.len()
521
28
        }
522
    }
523

            
524
    impl<'a, T> std::default::Default for [<$mapname Iter>] <'a, T> {
525
4
        fn default() -> Self {
526
            [<$mapname Iter>] {
527
4
                iter: [].iter(),
528
                values: const { &$crate::n_key_list::deps::Slab::new() },
529
            }
530
4
        }
531
    }
532
}
533
};
534

            
535
// Helper: Generate an expression to access a specific key and return an `Option<&TYPE>` for that
536
// key. This is the part of the macro that parses key descriptions.
537

            
538
{ @access($ex:expr, (Option) $key:ident : $t:ty ) } => {
539
    $ex.key()
540
};
541
{ @access($ex:expr, () $key:ident : $t:ty) } => {
542
    Some($ex.key())
543
};
544
{ @access($ex:expr, (Option) $key:ident : $t:ty { . $field:tt } ) } => {
545
    $ex.$field.as_ref()
546
};
547
{ @access($ex:expr, () $key:ident : $t:ty { . $field:tt } ) } => {
548
   Some(&$ex.$field)
549
};
550
{ @access($ex:expr, (Option) $key:ident : $t:ty { $func:ident () } ) } => {
551
    $ex.$func()
552
};
553
{ @access($ex:expr, () $key:ident : $t:ty { $func:ident () } ) } => {
554
    Some($ex.$func())
555
};
556
}
557

            
558
/// An error returned from an operation on an [`n_key_list`].
559
#[derive(Clone, Debug, thiserror::Error)]
560
#[non_exhaustive]
561
pub enum Error {
562
    /// We tried to insert a value into a set where all keys were optional, but every key on that
563
    /// value was `None`.
564
    #[error("Tried to insert a value with no keys")]
565
    NoKeys,
566
}
567

            
568
#[cfg(test)]
569
mod test {
570
    // @@ begin test lint list maintained by maint/add_warning @@
571
    #![allow(clippy::bool_assert_comparison)]
572
    #![allow(clippy::clone_on_copy)]
573
    #![allow(clippy::dbg_macro)]
574
    #![allow(clippy::mixed_attributes_style)]
575
    #![allow(clippy::print_stderr)]
576
    #![allow(clippy::print_stdout)]
577
    #![allow(clippy::single_char_pattern)]
578
    #![allow(clippy::unwrap_used)]
579
    #![allow(clippy::unchecked_time_subtraction)]
580
    #![allow(clippy::useless_vec)]
581
    #![allow(clippy::needless_pass_by_value)]
582
    #![allow(clippy::string_slice)] // See arti#2571
583
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
584

            
585
    fn sort<T: std::cmp::Ord>(i: impl Iterator<Item = T>) -> Vec<T> {
586
        let mut v: Vec<_> = i.collect();
587
        v.sort();
588
        v
589
    }
590

            
591
    n_key_list! {
592
        #[derive(Clone, Debug)]
593
        struct Tuple2List<A,B> for (A,B) {
594
            first: A { .0 },
595
            second: B { .1 },
596
        }
597
    }
598

            
599
    #[test]
600
    #[allow(clippy::cognitive_complexity)]
601
    fn basic() {
602
        let mut list = Tuple2List::new();
603
        assert!(list.is_empty());
604

            
605
        // add a single element and do some sanity checks
606
        list.insert((0_u32, 99_u16));
607
        assert_eq!(list.len(), 1);
608
        assert_eq!(list.contains_first(&0), true);
609
        assert_eq!(list.contains_second(&99), true);
610
        assert_eq!(list.contains_first(&99), false);
611
        assert_eq!(list.contains_second(&0), false);
612
        assert_eq!(sort(list.by_first(&0)), [&(0, 99)]);
613
        assert_eq!(sort(list.by_second(&99)), [&(0, 99)]);
614
        assert_eq!(list.by_first(&99).len(), 0);
615
        assert_eq!(list.by_second(&0).len(), 0);
616
        list.check_consistency();
617

            
618
        // lookup by a key that has never existed in the map
619
        assert_eq!(list.by_first(&1000000).len(), 0);
620

            
621
        // inserting the same element again should add it to the list
622
        assert_eq!(list.len(), 1);
623
        list.insert((0_u32, 99_u16));
624
        assert_eq!(list.len(), 2);
625
        list.check_consistency();
626

            
627
        // add two new entries
628
        list.insert((12, 34));
629
        list.insert((0, 34));
630
        assert_eq!(list.len(), 4);
631
        assert!(list.capacity() >= 4);
632
        assert_eq!(sort(list.by_first(&0)), [&(0, 34), &(0, 99), &(0, 99)]);
633
        assert_eq!(sort(list.by_first(&12)), [&(12, 34)]);
634
        list.check_consistency();
635

            
636
        // remove some elements
637
        assert_eq!(
638
            list.remove_by_first(&0, |(_, b)| *b == 99),
639
            vec![(0, 99), (0, 99)]
640
        );
641
        assert_eq!(list.remove_by_first(&0, |_| true), vec![(0, 34)]);
642
        assert_eq!(list.len(), 1);
643
        list.check_consistency();
644

            
645
        // test adding an element again
646
        assert_eq!(sort(list.by_first(&12)), [&(12, 34)]);
647
        list.insert((12, 123));
648
        assert_eq!(list.len(), 2);
649
        assert_eq!(sort(list.by_first(&12)), [&(12, 34), &(12, 123)]);
650
        assert_eq!(sort(list.by_second(&34)), [&(12, 34)]);
651
        assert_eq!(sort(list.by_second(&123)), [&(12, 123)]);
652
        list.check_consistency();
653

            
654
        // test iterators
655
        list.insert((56, 78));
656
        assert_eq!(sort(list.values()), [&(12, 34), &(12, 123), &(56, 78)]);
657
        assert_eq!(sort(list.into_values()), [(12, 34), (12, 123), (56, 78)]);
658
    }
659

            
660
    #[test]
661
    fn retain_and_compact() {
662
        let mut list: Tuple2List<String, String> = (1..=1000)
663
            .map(|idx| (format!("A={}", idx), format!("B={}", idx)))
664
            .collect();
665

            
666
        assert_eq!(list.len(), 1000);
667
        let cap_orig = list.capacity();
668
        assert!(cap_orig >= list.len());
669
        list.check_consistency();
670

            
671
        // retain only the values whose first key is 3 characters long; that's 9 values out of 1000
672
        list.retain(|(a, _)| a.len() <= 3);
673
        assert_eq!(list.len(), 9);
674
        // we don't shrink till we next insert
675
        assert_eq!(list.capacity(), cap_orig);
676
        list.check_consistency();
677

            
678
        // insert should cause the list to shrink
679
        list.insert(("A=0".to_string(), "B=0".to_string()));
680
        assert!(list.capacity() < cap_orig);
681
        assert_eq!(list.len(), 10);
682
        for idx in 0..=9 {
683
            assert!(list.contains_first(&format!("A={}", idx)));
684
        }
685
        list.check_consistency();
686
    }
687

            
688
    n_key_list! {
689
        #[derive(Clone, Debug)]
690
        struct AllOptional<A,B> for (Option<A>,Option<B>) {
691
            (Option) first: A { .0 },
692
            (Option) second: B { .1 },
693
        }
694
    }
695

            
696
    #[test]
697
    fn optional() {
698
        let mut list = AllOptional::<u8, u8>::new();
699

            
700
        // should be able to insert values with at least one key
701
        list.insert((Some(1), Some(2)));
702
        list.insert((None, Some(2)));
703
        list.insert((Some(1), None));
704
        list.check_consistency();
705

            
706
        assert_eq!(
707
            sort(list.by_first(&1)),
708
            [&(Some(1), None), &(Some(1), Some(2))],
709
        );
710

            
711
        // check that inserting a value with no keys results in an error
712
        assert!(matches!(
713
            list.try_insert((None, None)),
714
            Err(super::Error::NoKeys),
715
        ));
716
    }
717

            
718
    #[allow(dead_code)]
719
    struct Weekday {
720
        dow: u8,
721
        name: &'static str,
722
        lucky_number: Option<u16>,
723
    }
724
    #[allow(dead_code)]
725
    impl Weekday {
726
        fn dow(&self) -> &u8 {
727
            &self.dow
728
        }
729
        fn name(&self) -> &str {
730
            self.name
731
        }
732
        fn lucky_number(&self) -> Option<&u16> {
733
            self.lucky_number.as_ref()
734
        }
735
    }
736
    n_key_list! {
737
        struct WeekdaySet for Weekday {
738
            idx: u8 { dow() },
739
            (Option) lucky: u16 { lucky_number() },
740
            name: String { name() }
741
        }
742
    }
743

            
744
    n_key_list! {
745
        struct['a] ArrayMap['a] for (String, [&'a u32;10]) {
746
            name: String { .0 }
747
        }
748
    }
749

            
750
    n_key_list! {
751
        struct['a, const N:usize] ArrayMap2['a, N] for (String, [&'a u32;N]) {
752
            name: String { .0 }
753
        }
754
    }
755
}