tor_basic_utils/
n_key_set.rs

1//! Declaration for an n-keyed set type, allowing access to each of its members by each of N different keys.
2
3// Re-export dependencies that we use to make this macro work.
4#[doc(hidden)]
5pub mod deps {
6    pub use paste::paste;
7    pub use slab::Slab;
8}
9
10/// Declare a structure that can hold elements with multiple unique keys.
11///
12/// Each element can be looked up or removed by any of its keys. The keys
13/// themselves can be any type that supports `Hash`, `Eq`, and `Clone`. Elements
14/// can have multiple keys of the same type: for example, a person can have a
15/// username `String` and an irc_handle `String`.
16///
17/// All keys in the set must be unique: if a new element is inserted that has
18/// the same value for any key as a previous element, the old element is
19/// removed.
20///
21/// Keys may be accessed from elements either by field access or by an accessor
22/// function.
23///
24/// Keys may be optional.  If all keys are optional, then we require
25/// additionally that every element must have at least one key.
26///
27/// # Examples
28///
29/// ```
30/// use tor_basic_utils::n_key_set;
31///
32/// // We declare a person struct with several different fields.
33/// pub struct Person {
34///     username: String,
35///     irc_handle: String,
36///     student_id: Option<u64>,
37///     favorite_joke: Option<String>,
38/// }
39///
40/// n_key_set! {
41///     pub struct PersonSet for Person {
42///         // See note on "Key syntax" below.  The ".foo" syntax
43///         // here means that the value for the key is returned
44///         // by accessing a given field.
45///         username: String { .username },
46///         irc_handle: String { .irc_handle },
47///         (Option) student_id: u64 { .student_id }
48///     }
49/// }
50///
51/// let mut people = PersonSet::new();
52/// people.insert(Person {
53///     username: "mina".into(),
54///     irc_handle: "pashMina".into(),
55///     student_id: None,
56///     favorite_joke: None
57/// });
58/// assert!(people.by_username("mina").is_some());
59/// assert!(people.by_irc_handle("pashMina").is_some());
60/// ```
61///
62/// # Key syntax
63///
64/// You can tell the map to access the keys of an element in any of several ways.
65///
66/// * `name : type { func() }` - A key whose name is `name` and type is `type`,
67///   that can be accessed from a given element by calling `element.func()`.
68/// * `name : type { .field }` - A key whose name is `name` and type is `type`,
69///   that can be accessed from a given element by calling `&element.field`.
70/// * `name : type` - Short for as `name : type { name() }`.
71///
72/// If a key declaration is preceded with `(Option)`, then the
73/// key is treated as optional, and accessor functions are expected to return
74/// `Option<&Type>`.
75///
76/// # Additional features
77///
78/// You can put generic parameters and `where` constraints on your structure.
79/// The `where` clause (if present) must be wrapped in square brackets.
80///
81/// If you need to use const generics or lifetimes in your structure, you
82/// need to use square brackets instead of angle brackets, and specify both the
83/// generic parameters *and* the type that you are implementing. (This is due to
84/// limitations in the Rust macro system.)  For example:
85///
86/// ```
87/// # use tor_basic_utils::n_key_set;
88/// n_key_set!{
89///     struct['a, T, const N: usize] ArrayMap2['a, T, N] for (String, [&'a T;N])
90///         [ where T: Clone + 'a ]
91///     {
92///          name: String { .0 }
93///     }
94/// }
95/// ```
96#[macro_export]
97macro_rules! n_key_set {
98{
99    $(#[$meta:meta])*
100    $vis:vis struct $mapname:ident $(<$($P:ident),*>)? for $V:ty
101    $( where [ $($constr:tt)+ ] )?
102    {
103        $($body:tt)+
104    }
105} => {
106n_key_set!{
107    $(#[$meta])*
108    $vis struct [$($($P),*)?] $mapname [$($($P),*)?] for $V
109    $( [ where $($constr)+ ] )?
110    {
111        $( $body )+
112    }
113}
114};
115{
116        $(#[$meta:meta])*
117        $vis:vis struct [$($($G:tt)+)?] $mapname:ident [$($($P:tt)+)?] for $V:ty
118        $( [ where $($constr:tt)+ ])?
119        {
120            $( $(( $($flag:ident)+ ))? $key:ident : $KEY:ty $({ $($source:tt)+ })? ),+
121            $(,)?
122        }
123} => {
124$crate::n_key_set::deps::paste!{
125   $( #[$meta] )*
126    #[doc = concat!(
127        "A set of elements of type ", stringify!($V), " whose members can be accessed by multiple keys.",
128        "\n\nThe keys are:",
129        $( " * `", stringify!($key), "` (`",stringify!($KEY),"`)\n" ,
130           $(" (", stringify!($($flag)+), ")", )?
131         )+
132        "\
133Each member has a value for *each* required key, and up to one value
134for *each* optional key.
135The set contains at most one member for any value of a given key.
136
137# Requirements
138
139Key types must have consistent `Hash` and `Eq` implementations, as
140they will be used as keys in a `HashMap`.
141
142If all keys are optional, then every element in this set
143must have at least one non-None key.
144
145An element must not change its keys over time through interior
146mutability.
147
148⚠️ If *any* of these rules is violated, the consequences are unspecified,
149and could include panics or wrong answers (but not memory-unsafety).
150        
151# Limitations
152
153This could be more efficient in space and time.
154        ",
155    )]
156    $vis struct $mapname $(<$($G)*>)?
157        where $( $KEY : std::hash::Hash + Eq + Clone , )+  $($($constr)+)?
158    {
159        // The $key fields here are a set of maps from each of the key values to
160        // the position of that value within the Slab.
161        //
162        // Invariants:
163        //    * There is an entry K=>idx in the map `$key` if and only if
164        //      values[idx].$accessor() == K.
165        //    * Every value in `values` has at least one key.
166        //
167        // TODO: Dare we have these HashMaps key based on a reference to V
168        // instead? That would create a self-referential structure and require
169        // unsafety.  Probably best to avoid that for now.
170        $([<$key _map>]: std::collections::HashMap<$KEY, usize> , )+
171
172        // A map from the indices to the values.
173        values: $crate::n_key_set::deps::Slab<$V>,
174    }
175
176    #[allow(dead_code)] // May be needed if this is not public.
177    impl $(<$($G)*>)? $mapname $(<$($P)*>)?
178        where $( $KEY : std::hash::Hash + Eq + Clone , )+  $($($constr)+)?
179    {
180        #[doc = concat!("Construct a new ", stringify!($mapname))]
181        $vis fn new() -> Self {
182            Self::with_capacity(0)
183        }
184        #[doc = concat!("Construct a new ", stringify!($mapname), " with a given capacity.")]
185
186        $vis fn with_capacity(n: usize) -> Self {
187            Self {
188                $([<$key _map>]: std::collections::HashMap::with_capacity(n),)*
189                values: $crate::n_key_set::deps::Slab::with_capacity(n),
190            }
191        }
192        $(
193        #[doc = concat!("Return a reference to the element whose `", stringify!($key), "` is `key`.")]
194        ///
195        /// Return None if there is no such element.
196        $vis fn [<by_ $key>] <BorrowAsKey_>(&self, key: &BorrowAsKey_) -> Option<&$V>
197            where $KEY : std::borrow::Borrow<BorrowAsKey_>,
198                  BorrowAsKey_: std::hash::Hash + Eq + ?Sized
199        {
200            self.[<$key _map>].get(key).map(|idx| self.values.get(*idx).expect("inconsistent state"))
201        }
202
203        #[doc = concat!("Return a mutable reference to the element whose `", stringify!($key),
204                        "` is `key`.")]
205        ///
206        /// Return None if there is no such element.
207        ///
208        /// # Correctness hazard!
209        ///
210        /// This function can put this set into an inconsistent state if the
211        /// mutable reference is used to change any of the keys. Doing this does
212        /// not risk Rust safety violations (such as undefined behavior), but it
213        /// may nonetheless make your program incorrect by causing other
214        /// functions on this object to panic or give incorrect results.
215        ///
216        /// If you cannot prove to yourself that this won't happen, then you
217        /// should use `modify_by_*` instead.
218        $vis fn [<by_ $key _mut_hazardous>] <BorrowAsKey_>(
219            &mut self,
220            key: &BorrowAsKey_
221        ) -> Option<&mut $V>
222            where $KEY : std::borrow::Borrow<BorrowAsKey_>,
223                  BorrowAsKey_: std::hash::Hash + Eq + ?Sized
224        {
225            self.[<$key _map>]
226                .get(key)
227                .map(|idx| self.values.get_mut(*idx).expect("inconsistent state"))
228        }
229
230        #[doc = concat!("Return true if this set contains an element whose `", stringify!($key),
231                        "` is `key`.")]
232        $vis fn [<contains_ $key>] <BorrowAsKey_>(&mut self, $key: &BorrowAsKey_) -> bool
233        where $KEY : std::borrow::Borrow<BorrowAsKey_>,
234              BorrowAsKey_: std::hash::Hash + Eq + ?Sized
235        {
236            self.[<$key _map>].get($key).is_some()
237        }
238
239        #[doc = concat!("Remove the element whose `", stringify!($key), "` is `key`")]
240        ///
241        /// Return that element on success, and None if there is no such element.
242        $vis fn [<remove_by_ $key>] <BorrowAsKey_>(&mut self, $key: &BorrowAsKey_) -> Option<$V>
243            where $KEY : std::borrow::Borrow<BorrowAsKey_>,
244                  BorrowAsKey_: std::hash::Hash + Eq + ?Sized
245        {
246            self.[<$key _map>]
247                .get($key)
248                .copied()
249                .map(|old_idx| self.remove_at(old_idx).expect("inconsistent state"))
250        }
251
252
253        #[doc = concat!("Modify the element with the given value for `", stringify!($key),
254                        " by applying `func` to it.")]
255        ///
256        /// `func` is allowed to change the keys for this value.  All indices
257        /// are updated to refer to the new keys.  If the new keys conflict with
258        /// any previous values, those values are replaced and returned in a
259        /// vector.
260        ///
261        /// If `func` causes the value to have no keys at all, then the value
262        /// itself is also removed and returned in the result vector.
263        ///
264        /// Note that because this function needs to copy all key values and check whether
265        /// they have changed, it is not terribly efficient.
266        $vis fn [<modify_by_$key>] <BorrowAsKey_, F_>(
267            &mut self,
268            $key: &BorrowAsKey_,
269            func: F_) -> Vec<$V>
270        where
271            $KEY : std::borrow::Borrow<BorrowAsKey_>,
272            BorrowAsKey_: std::hash::Hash + Eq + ?Sized,
273            F_: FnOnce(&mut $V)
274        {
275            if let Some(idx) = self.[<$key _map>].get($key) {
276                self.modify_at(*idx, func)
277            } else {
278                Vec::new()
279            }
280        }
281        )+
282
283        /// Return an iterator over the elements in this container.
284        $vis fn values(&self) -> impl Iterator<Item=&$V> + '_ {
285            self.values.iter().map(|(_, v)| v)
286        }
287
288        /// Consume this container and return an iterator of its values.
289        $vis fn into_values(self) -> impl Iterator<Item=$V> {
290            self.values.into_iter().map(|(_, v)| v)
291        }
292
293        /// Try to insert the value `value`.
294        ///
295        /// Remove any previous values that shared any keys with `value`, and
296        /// return them in a vector on success.
297        ///
298        /// Return `Err(Error::NoKeys)` if all the keys are optional,
299        /// and `value` has no keys at all.
300        $vis fn try_insert(&mut self, value: $V) -> Result<Vec<$V>, $crate::n_key_set::Error> {
301            if self.capacity() > 32 && self.len() < self.capacity() / 4 {
302                // We're have the opportunity to free up a fair amount of space; let's take it.
303                self.compact()
304            }
305
306            // First, remove all the elements that have at least one key in common with `value`.
307            let mut replaced = Vec::new();
308            $(
309                replaced.extend(
310                    $crate::n_key_set!( @access(value, ($($($flag)+)?) $key : $KEY $({$($source)+})?) )
311                    .and_then(|key| self.[<remove_by_$key>](key))
312                );
313            )*
314
315            // Now insert the new value, and add it to all of the maps.
316            let new_idx = self.values.insert(value);
317            let value_ref = self.values.get(new_idx).expect("we just inserted this");
318            let mut some_key_found = false;
319            $(
320                $crate::n_key_set!( @access(value_ref, ($($($flag)+)?) $key : $KEY $({$($source)+})?) )
321                    .map(|key| {
322                        self.[<$key _map>].insert(key.to_owned(), new_idx);
323                        some_key_found = true;
324                    });
325            )*
326            // If we didn't find any key on the newly added value, that's
327            // an invariant violation.
328            if ! some_key_found {
329                self.values.remove(new_idx); // Restore the set to a correct state.
330                return Err($crate::n_key_set::Error::NoKeys);
331            }
332
333            Ok(replaced)
334        }
335
336        /// Try to insert the value `value`.
337        ///
338        /// Remove any previous values that shared any keys with `value`, and
339        /// return them in a vector.
340        ///
341        /// # Panics
342        ///
343        /// Panics if all the keys are optional, and `value` has no keys at all.
344        $vis fn insert(&mut self, value: $V) -> Vec<$V> {
345            self.try_insert(value)
346                .expect("Tried to add a value with no key!")
347        }
348
349        /// Return the number of elements in this container.
350        $vis fn len(&self) -> usize {
351            self.values.len()
352        }
353
354        /// Return true if there are no elements in this container.
355        $vis fn is_empty(&self) -> bool {
356            self.values.len() == 0
357        }
358
359        /// Return the number of elements for which this container has allocated
360        /// storage.
361        $vis fn capacity(&self) -> usize {
362            self.values.capacity()
363        }
364
365        /// Remove every element that does not satisfy the predicate `pred`.
366        $vis fn retain<F>(&mut self, mut pred: F)
367            where F: FnMut(&$V) -> bool,
368        {
369            for idx in 0..self.values.capacity() {
370                if self.values.get(idx).map(&mut pred) == Some(false) {
371                    self.remove_at(idx);
372                }
373            }
374        }
375
376        /// Helper: remove the item stored at index `idx`, and remove it from
377        /// every key map.
378        ///
379        /// If there was no element at `idx`, do nothing.
380        ///
381        /// Return the element removed (if any).
382        fn remove_at(&mut self, idx: usize) -> Option<$V> {
383            if let Some(removed) = self.values.try_remove(idx) {
384                $(
385                let $key = $crate::n_key_set!( @access(removed, ($($($flag)+)?) $key : $KEY $({$($source)+})?) );
386                if let Some($key) = $key {
387                    let old_idx = self.[<$key _map>].remove($key);
388                    assert_eq!(old_idx, Some(idx));
389                }
390                )*
391                Some(removed)
392            } else {
393                None
394            }
395        }
396
397        /// Change the value at `idx` by applying `func` to it.
398        ///
399        /// `func` is allowed to change the keys for this value.  All indices
400        /// are updated to refer to the new keys.  If the new keys conflict with
401        /// any previous values, those values are replaced and returned in a
402        /// vector.
403        ///
404        /// If `func` causes the value to have no keys at all, then the value
405        /// itself is also removed and returned in the result vector.
406        ///
407        /// # Panics
408        ///
409        /// Panics if `idx` is not present in this set.
410        fn modify_at<F_>(&mut self, idx: usize, func: F_) -> Vec<$V>
411        where
412            F_: FnOnce(&mut $V)
413        {
414            let value = self.values.get_mut(idx).expect("invalid index");
415            $(
416            let [<orig_$key>] = $crate::n_key_set!( @access(value, ($($($flag)+)?) $key : $KEY $({$($source)+})?) )
417                .map(|elt| elt.to_owned()) ;
418            )+
419
420            func(value);
421
422            // Check whether any keys have changed, and whether there still are
423            // any keys.
424            $(
425                let [<new_$key>] = $crate::n_key_set!( @access( value, ($($($flag)+)?) $key : $KEY $({$($source)+})?) ) ;
426            )+
427            let keys_changed = $(
428                 [<orig_$key>].as_ref().map(std::borrow::Borrow::borrow) != [<new_$key>]
429            )||+ ;
430
431            if keys_changed {
432                let found_any_keys = $( [<new_$key>].is_some() )||+ ;
433
434                // Remove this value from every place that it was before.
435                //
436                // We can't use remove_at, since we have changed the keys in the
437                // value: we have to remove them manually from each index
438                // instead.
439                $(
440                    if let Some(orig) = [<orig_ $key>] {
441                        let removed = self.[<$key _map>].remove(&orig);
442                        assert_eq!(removed, Some(idx));
443                    }
444                )+
445                // Remove the value from its previous place in the index.  (This
446                // results in an extra copy when we call insert(), but if we
447                // didn't do it, we'd need to reimplement `insert()`.)
448                let removed = self.values.remove(idx);
449                if found_any_keys {
450                    // This item belongs: put it back and return the vector of
451                    // whatever was replaced.j
452                    self.insert(removed)
453                } else {
454                    // This item does not belong any longer, since all its keys
455                    // were removed.
456                    vec![removed]
457                }
458            } else {
459                // We did not change any keys, so we know we have not replaced
460                // any items.
461                vec![]
462            }
463        }
464
465        /// Re-index all the values in this map, so that the map can use a more
466        /// compact representation.
467        ///
468        /// This should be done infrequently; it's expensive.
469        fn compact(&mut self) {
470            let old_value = std::mem::replace(self, Self::with_capacity(self.len()));
471            for item in old_value.into_values() {
472                self.insert(item);
473            }
474        }
475
476        /// Assert that this set appears to be in an internally consistent state.
477        ///
478        /// This method can be somewhat expensive, and it should never fail unless
479        /// your code has a bug.
480        ///
481        /// # Panics
482        ///
483        /// Panics if it finds bugs in this object, or constraint violations in
484        /// its elements.  See the (type documentation)[Self#Requirements] for a
485        /// list of constraints.
486        $vis fn check_invariants(&self) {
487            #![allow(noop_method_call)] // permit borrow when it does nothing.
488            use std::borrow::Borrow;
489            // Make sure that every entry in the $key map points to a
490            // value with the right value for that $key.
491            $(
492                for (k,idx) in self.[<$key _map>].iter() {
493                    let val = self.values.get(*idx).expect("Dangling entry in hashmap.");
494                    // Can't use assert_eq!; k might not implement Debug.
495                    assert!(
496                        Some((k).borrow()) ==
497                        $crate::n_key_set!( @access(val, ($($($flag)+)?) $key : $KEY $({$($source)+})?) ),
498                        "Inconsistent key between hashmap and value."
499                    )
500                }
501            )+
502
503            // Make sure that every value has an entry in the $key map that
504            // points to it, for each of its keys.
505            //
506            // This is slightly redundant, but we don't care too much about
507            // efficiency here.
508            for (idx, val) in self.values.iter() {
509                let mut found_any_key = false;
510                $(
511                if let Some(k) = $crate::n_key_set!( @access(val, ($($($flag)+)?) $key : $KEY $({$($source)+})?) ) {
512                    found_any_key = true;
513                    assert!(
514                        self.[<$key _map>].get(k) == Some(&idx),
515                        "Value not found at correct index"
516                    )
517                }
518                stringify!($key);
519                )+
520                assert!(found_any_key, "Found a value with no keys.");
521            }
522        }
523    }
524
525    impl $(<$($G)*>)? Default for $mapname $(<$($P)*>)?
526        where $( $KEY : std::hash::Hash + Eq + Clone , )*  $($($constr)+)?
527    {
528        fn default() -> Self {
529            $mapname::new()
530        }
531    }
532
533    impl $(<$($G)*>)? FromIterator<$V> for $mapname $(<$($P)*>)?
534        where $( $KEY : std::hash::Hash + Eq + Clone , )*  $($($constr)+)?
535    {
536        fn from_iter<IntoIter_>(iter: IntoIter_) -> Self
537        where
538            IntoIter_: IntoIterator<Item = $V>
539        {
540            let iter = iter.into_iter();
541            let mut set = Self::with_capacity(iter.size_hint().0);
542            for value in iter {
543                set.insert(value);
544            }
545            set
546        }
547    }
548}
549};
550
551// Helper: Generate an expression to access a specific key and return
552// an Option<&TYPE> for that key.  This is the part of the macro
553// that parses key descriptions.
554
555{ @access($ex:expr, (Option) $key:ident : $t:ty ) } => {
556    $ex.key()
557};
558{ @access($ex:expr, () $key:ident : $t:ty) } => {
559    Some($ex.key())
560};
561{ @access($ex:expr, (Option) $key:ident : $t:ty { . $field:tt } ) } => {
562    $ex.$field.as_ref()
563};
564{ @access($ex:expr, () $key:ident : $t:ty { . $field:tt } ) } => {
565   Some(&$ex.$field)
566};
567{ @access($ex:expr, (Option) $key:ident : $t:ty { $func:ident () } ) } => {
568    $ex.$func()
569};
570{ @access($ex:expr, () $key:ident : $t:ty { $func:ident () } ) } => {
571    Some($ex.$func())
572};
573}
574
575/// An error returned from an operation on an `n_key_set`.
576#[derive(Clone, Debug, thiserror::Error)]
577#[non_exhaustive]
578pub enum Error {
579    /// We tried to insert a value into a set where all keys were optional, but
580    /// every key on that value was `None`.
581    #[error("Tried to insert a value with no keys")]
582    NoKeys,
583}
584
585#[cfg(test)]
586mod test {
587    // @@ begin test lint list maintained by maint/add_warning @@
588    #![allow(clippy::bool_assert_comparison)]
589    #![allow(clippy::clone_on_copy)]
590    #![allow(clippy::dbg_macro)]
591    #![allow(clippy::mixed_attributes_style)]
592    #![allow(clippy::print_stderr)]
593    #![allow(clippy::print_stdout)]
594    #![allow(clippy::single_char_pattern)]
595    #![allow(clippy::unwrap_used)]
596    #![allow(clippy::unchecked_duration_subtraction)]
597    #![allow(clippy::useless_vec)]
598    #![allow(clippy::needless_pass_by_value)]
599    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
600
601    n_key_set! {
602        #[derive(Clone, Debug)]
603        struct Tuple2Set<A,B> for (A,B) {
604            first: A { .0 },
605            second: B { .1 },
606        }
607    }
608
609    #[test]
610    fn basic() {
611        let mut set = Tuple2Set::new();
612        assert!(set.is_empty());
613
614        set.insert((0_u32, 99_u16));
615        assert_eq!(set.contains_first(&0), true);
616        assert_eq!(set.contains_second(&99), true);
617        assert_eq!(set.contains_first(&99), false);
618        assert_eq!(set.contains_second(&0), false);
619        assert_eq!(set.by_first(&0), Some(&(0, 99)));
620        assert_eq!(set.by_second(&99), Some(&(0, 99)));
621        assert_eq!(set.by_first(&99), None);
622        assert_eq!(set.by_second(&0), None);
623
624        assert_eq!(set.insert((12, 34)), vec![]);
625        assert_eq!(set.len(), 2);
626        assert!(set.capacity() >= 2);
627        assert_eq!(set.by_first(&0), Some(&(0, 99)));
628        assert_eq!(set.by_first(&12), Some(&(12, 34)));
629        assert_eq!(set.remove_by_second(&99), Some((0, 99)));
630        assert_eq!(set.len(), 1);
631
632        // no overlap in these next few inserts.
633        set.insert((34, 56));
634        set.insert((56, 78));
635        set.insert((78, 90));
636        assert_eq!(set.len(), 4);
637        // This insert replaces (12, 34)
638        assert_eq!(set.insert((12, 123)), vec![(12, 34)]);
639        // This one replaces (12,123) and (34,56).
640        let mut replaced = set.insert((12, 56));
641        replaced.sort();
642        assert_eq!(replaced, vec![(12, 123), (34, 56)]);
643        assert_eq!(set.len(), 3);
644        assert_eq!(set.is_empty(), false);
645        set.check_invariants();
646
647        // Test our iterators
648        let mut all_members: Vec<_> = set.values().collect();
649        all_members.sort();
650        assert_eq!(all_members, vec![&(12, 56), &(56, 78), &(78, 90)]);
651
652        let mut drained_members: Vec<_> = set.into_values().collect();
653        drained_members.sort();
654        assert_eq!(drained_members, vec![(12, 56), (56, 78), (78, 90)]);
655    }
656
657    #[test]
658    fn retain_and_compact() {
659        let mut set: Tuple2Set<String, String> = (1..=1000)
660            .map(|idx| (format!("A={}", idx), format!("B={}", idx)))
661            .collect();
662
663        assert_eq!(set.len(), 1000);
664        let cap_orig = set.capacity();
665        assert!(cap_orig >= set.len());
666
667        // Retain only the values whose first key is 3 characters long.
668        // That's 9 values out of 1000.
669        set.retain(|(a, _)| a.len() <= 3);
670        assert_eq!(set.len(), 9);
671        // We don't shrink till we next insert.
672        assert_eq!(set.capacity(), cap_orig);
673        set.check_invariants();
674
675        assert!(set
676            .insert(("A=0".to_string(), "B=0".to_string()))
677            .is_empty());
678        assert!(set.capacity() < cap_orig);
679        assert_eq!(set.len(), 10);
680        for idx in 0..=9 {
681            assert!(set.contains_first(&format!("A={}", idx)));
682        }
683        set.check_invariants();
684    }
685
686    #[test]
687    fn modify_value() {
688        let mut set: Tuple2Set<i32, i32> = (1..=100).map(|idx| (idx, idx * idx)).collect();
689        set.check_invariants();
690
691        let v = set.modify_by_first(&30, |elt| elt.1 = 256);
692        set.check_invariants();
693        // one element was replaced.
694        assert_eq!(v.len(), 1);
695        assert_eq!(v[0], (16, 256));
696        assert_eq!(set.by_second(&256).unwrap(), &(30, 256));
697        assert_eq!(set.by_first(&30).unwrap(), &(30, 256));
698
699        let v = set.modify_by_first(&30, |elt| *elt = (-100, -100));
700        set.check_invariants();
701        // no elements were replaced.
702        assert_eq!(v.len(), 0);
703        assert_eq!(set.by_first(&30), None);
704        assert_eq!(set.by_second(&256), None);
705        assert_eq!(set.by_first(&-100).unwrap(), &(-100, -100));
706        assert_eq!(set.by_second(&-100).unwrap(), &(-100, -100));
707
708        set.check_invariants();
709    }
710
711    #[allow(dead_code)]
712    struct Weekday {
713        dow: u8,
714        name: &'static str,
715        lucky_number: Option<u16>,
716    }
717    #[allow(dead_code)]
718    impl Weekday {
719        // TODO: I wish this could return u8
720        fn dow(&self) -> &u8 {
721            &self.dow
722        }
723        fn name(&self) -> &str {
724            self.name
725        }
726        // TODO: I wish this could return Option<u16>
727        fn lucky_number(&self) -> Option<&u16> {
728            self.lucky_number.as_ref()
729        }
730    }
731    n_key_set! {
732        struct WeekdaySet for Weekday {
733            idx: u8 { dow() },
734            (Option) lucky: u16 { lucky_number() },
735            name: String { name() }
736        }
737    }
738
739    n_key_set! {
740        struct['a] ArrayMap['a] for (String, [&'a u32;10]) {
741            name: String { .0 }
742        }
743    }
744
745    n_key_set! {
746        struct['a, const N:usize] ArrayMap2['a, N] for (String, [&'a u32;N]) {
747            name: String { .0 }
748        }
749    }
750}