drop_tracker/
lib.rs

1//! Crate to check if a variable got correctly [dropped]. This crate is mostly useful in unit
2//! tests for code involving [`ManuallyDrop`], [`MaybeUninit`], unsafe memory management,
3//! custom containers, and more.
4//!
5//! [dropped]: https://doc.rust-lang.org/reference/destructors.html
6//! [`ManuallyDrop`]: std::mem::ManuallyDrop
7//! [`MaybeUninit`]: std::mem::MaybeUninit
8//!
9//! # Concepts
10//!
11//! The main struct of this crate is [`DropTracker`]. Once you initialize a tracker, you call
12//! [`DropTracker::track`] on it to get a [`DropItem`]. Each drop item is identified by a key;
13//! the key can be used at any time to check the state of the item and see if it's alive or if
14//! it has been dropped.
15//!
16//! # Examples
17//!
18//! This is how you would test that a container like [`Vec`] drops all its items when the container
19//! is dropped:
20//!
21//! ```
22//! use drop_tracker::DropTracker;
23//!
24//! let mut tracker = DropTracker::new();
25//!
26//! // Create a new vector and add a bunch of elements to it. The elements in this case are
27//! // identified by integer keys (1, 2, 3), but any hashable type would work.
28//! let v = vec![tracker.track(1),
29//!              tracker.track(2),
30//!              tracker.track(3)];
31//!
32//! // Assert that all elements in the vector are alive
33//! tracker.all_alive(1..=3)
34//!        .expect("expected all elements to be alive");
35//!
36//! // Once the vector is dropped, all items should be dropped with it
37//! drop(v);
38//! tracker.all_dropped(1..=3)
39//!        .expect("expected all elements to be dropped");
40//! ```
41//!
42//! This is how you would test a struct that involves [`MaybeUninit`]:
43//!
44//! ```should_panic
45//! # #![allow(dead_code)]
46//! use std::mem::MaybeUninit;
47//!
48//! struct MyOption<T> {
49//!     set: bool,
50//!     data: MaybeUninit<T>,
51//! }
52//!
53//! impl<T> MyOption<T> {
54//!     fn none() -> Self {
55//!         Self { set: false, data: MaybeUninit::uninit() }
56//!     }
57//!
58//!     fn some(x: T) -> Self {
59//!         Self { set: true, data: MaybeUninit::new(x) }
60//!     }
61//! }
62//!
63//! // BUG: MyOption<T> does not implement Drop!
64//! // BUG: The instance inside `data` may be initialized but not be properly destructed!
65//!
66//! // BUG: The following code will silently leak memory:
67//! let opt = MyOption::some(String::from("hello"));
68//! drop(opt); // the String does not get deallocated
69//!
70//! // DropTracker is able to catch this sort of bugs:
71//! use drop_tracker::DropTracker;
72//!
73//! let mut tracker = DropTracker::new();
74//! let opt = MyOption::some(tracker.track("item"));
75//!
76//! tracker.state(&"item")
77//!        .alive()
78//!        .expect("item is expected to be alive"); // works
79//!
80//! drop(opt);
81//!
82//! tracker.state(&"item")
83//!        .dropped()
84//!        .expect("item is expected to be dropped"); // panics, meaning that the bug was detected
85//! ```
86//!
87//! If you want to write more succint code and don't care about the error message, you can also use
88//! the following `assert` methods:
89//!
90//! * [`assert_alive(...)`](DropTracker::assert_alive) equivalent to
91//!   `state(...).alive().expect("error message")`
92//! * [`assert_dropped(...)`](DropTracker::assert_dropped) equivalent to
93//!   `state(...).dropped().expect("error message")`
94//! * [`assert_all_alive(...)`](DropTracker::assert_all_alive) equivalent to
95//!   `all_alive(...).expect("error message")`
96//! * [`assert_all_dropped(...)`](DropTracker::assert_all_dropped) equivalent to
97//!   `all_dropped(...).expect("error message")`
98//!
99//! Here is how the first example above could be rewritten more consisely using `assert` methods:
100//!
101//! ```
102//! use drop_tracker::DropTracker;
103//!
104//! let mut tracker = DropTracker::new();
105//! let v = vec![tracker.track(1),
106//!              tracker.track(2),
107//!              tracker.track(3)];
108//!
109//! tracker.assert_all_alive(1..=3);
110//! drop(v);
111//! tracker.assert_all_dropped(1..=3);
112//! ```
113//!
114//! # Double drop
115//!
116//! [`DropItem`] will panic if it gets dropped twice or more, as this is generally a bug and may
117//! cause undefined behavior. This feature can be used to identify bugs with code using
118//! [`ManuallyDrop`](std::mem::ManuallyDrop), [`MaybeUninit`](std::mem::MaybeUninit) or
119//! [`std::ptr::drop_in_place`], like in the following example:
120//!
121//! ```should_panic
122//! use std::ptr;
123//! use drop_tracker::DropTracker;
124//!
125//! let mut tracker = DropTracker::new();
126//! let mut item = tracker.track("something");
127//!
128//! unsafe { ptr::drop_in_place(&mut item); } // ok
129//! unsafe { ptr::drop_in_place(&mut item); } // panic!
130//! ```
131//!
132//! # Use in collections
133//!
134//! The [`DropItem`] instances returned by [`DropTracker::track`] hold a clone of the key passed
135//! to `track`. The `DropItem`s are [comparable](std::cmp) and [hashable](std::hash) if the
136//! underlying key is. This makes `DropItem` instances usable directly in collections like
137//! [`HashMap`](std::collections::HashMap), [`BTreeMap`](std::collections::BTreeMap),
138//! [`HashSet`](std::collections::HashSet) and many more.
139//!
140//! Here is an example involving [`HashSet`](std::collections::HashSet):
141//!
142//! ```
143//! use drop_tracker::DropTracker;
144//! use std::collections::HashSet;
145//!
146//! let mut tracker = DropTracker::new();
147//!
148//! let mut set = HashSet::from([
149//!     tracker.track(1),
150//!     tracker.track(2),
151//!     tracker.track(3),
152//! ]);
153//!
154//! set.remove(&3);
155//!
156//! tracker.state(&1).alive().expect("first item should be alive");
157//! tracker.state(&2).alive().expect("second item should be alive");
158//! tracker.state(&3).dropped().expect("third item should be dropped");
159//! ```
160//!
161//! Keys are required to be hashable and unique. If you need [`DropItem`] to hold a non-hashable
162//! value, or a repeated value, you can construct a [`DropItem`] with an arbitrary value using
163//! [`DropTracker::track_with_value`]:
164//!
165//! ```
166//! use drop_tracker::DropTracker;
167//!
168//! let mut tracker = DropTracker::new();
169//!
170//! // Construct items identified by integers and holding floats (which are not hashable)
171//! let item1 = tracker.track_with_value(1, 7.52);
172//! let item2 = tracker.track_with_value(2, 3.89);
173//!
174//! // Items compare according to their value
175//! assert!(item1 > item2); // 7.52 > 3.89
176//!
177//! // Items that support comparison can be put in a vector and sorted
178//! let mut v = vec![item1, item2];
179//! v.sort_by(|x, y| x.partial_cmp(y).unwrap());
180//! ```
181
182#![warn(missing_debug_implementations)]
183#![warn(missing_docs)]
184#![warn(pointer_structural_match)]
185#![warn(unreachable_pub)]
186#![warn(unused_crate_dependencies)]
187#![warn(unused_qualifications)]
188
189#![doc(test(attr(deny(warnings))))]
190
191#[cfg(test)]
192mod tests;
193
194mod itemtraits;
195
196use std::borrow::Borrow;
197use std::collections::HashMap;
198use std::collections::hash_map::Entry;
199use std::error::Error;
200use std::fmt;
201use std::hash::Hash;
202use std::iter::FusedIterator;
203use std::mem::MaybeUninit;
204use std::sync::Arc;
205use std::sync::atomic::AtomicBool;
206use std::sync::atomic::Ordering;
207
208/// A type that represents the state of a [`DropItem`]: either alive or dropped.
209///
210/// See the [module documentation](self) for details.
211#[must_use = "you should check whether the status is alive or dropped"]
212#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
213pub enum State {
214    /// The item is alive.
215    Alive,
216    /// The item has been dropped, and its destructor has been called.
217    Dropped,
218}
219
220impl State {
221    /// Returns `true` if the state is [`Alive`](State::Alive).
222    ///
223    /// # Examples
224    ///
225    /// ```
226    /// use drop_tracker::State;
227    ///
228    /// assert!(State::Alive.is_alive());
229    /// assert!(!State::Dropped.is_alive());
230    /// ```
231    #[inline]
232    #[must_use = "if you intended to assert that this is alive, consider `.alive().expect()`"]
233    pub const fn is_alive(&self) -> bool {
234        match self {
235            Self::Alive => true,
236            Self::Dropped => false,
237        }
238    }
239
240    /// Returns `true` if the state is [`Dropped`](State::Dropped).
241    ///
242    /// # Examples
243    ///
244    /// ```
245    /// use drop_tracker::State;
246    ///
247    /// assert!(State::Dropped.is_dropped());
248    /// assert!(!State::Alive.is_dropped());
249    /// ```
250    #[inline]
251    #[must_use = "if you intended to assert that this is dropped, consider `.dropped().expect()`"]
252    pub const fn is_dropped(&self) -> bool {
253        match self {
254            Self::Alive => false,
255            Self::Dropped => true,
256        }
257    }
258
259    /// Returns [`Ok`] if the state is [`Alive`](State::Alive), [`Err`] otherwise.
260    ///
261    /// # Examples
262    ///
263    /// ```
264    /// use drop_tracker::DroppedError;
265    /// use drop_tracker::State;
266    ///
267    /// assert_eq!(State::Alive.alive(), Ok(()));
268    /// assert_eq!(State::Dropped.alive(), Err(DroppedError));
269    /// ```
270    #[inline]
271    #[must_use = "if you intended to assert that this is alive, consider `.alive().expect()`"]
272    pub const fn alive(&self) -> Result<(), DroppedError> {
273        match self {
274            Self::Alive => Ok(()),
275            Self::Dropped => Err(DroppedError),
276        }
277    }
278
279    /// Returns [`Ok`] if the state is [`Dropped`](State::Dropped), [`Err`] otherwise.
280    ///
281    /// # Examples
282    ///
283    /// ```
284    /// use drop_tracker::AliveError;
285    /// use drop_tracker::State;
286    ///
287    /// assert_eq!(State::Dropped.dropped(), Ok(()));
288    /// assert_eq!(State::Alive.dropped(), Err(AliveError));
289    /// ```
290    #[inline]
291    #[must_use = "if you intended to assert that this is dropped, consider `.dropped().expect()`"]
292    pub const fn dropped(&self) -> Result<(), AliveError> {
293        match self {
294            Self::Alive => Err(AliveError),
295            Self::Dropped => Ok(()),
296        }
297    }
298}
299
300// Uses an `AtomicBool` (as opposed to e.g. a `RefCell`) to ensure that `DropTracker` and
301// `DropItem` are `Send`, `Sync` and `UnwindSafe`.
302#[derive(Clone, Debug)]
303struct StateCell(Arc<AtomicBool>);
304
305impl StateCell {
306    #[inline]
307    #[must_use]
308    fn new(state: State) -> Self {
309        Self(Arc::new(AtomicBool::new(state.is_dropped())))
310    }
311
312    #[inline]
313    fn get(&self) -> State {
314        match self.0.load(Ordering::Relaxed) {
315            false => State::Alive,
316            true  => State::Dropped,
317        }
318    }
319
320    #[inline]
321    fn replace(&mut self, state: State) -> State {
322        match self.0.swap(state.is_dropped(), Ordering::Relaxed) {
323            false => State::Alive,
324            true  => State::Dropped,
325        }
326    }
327
328    #[inline]
329    #[must_use]
330    fn is_alive(&self) -> bool {
331        self.get().is_alive()
332    }
333
334    #[inline]
335    #[must_use]
336    fn is_dropped(&self) -> bool {
337        self.get().is_dropped()
338    }
339}
340
341/// Creates [`DropItem`]s and tracks their state.
342///
343/// [`DropItem`]s can be created using [`track`](DropTracker::track) or
344/// [`try_track`](DropTracker::try_track) and their state can be later checked using
345/// [`state`](DropTracker::state).
346///
347/// [`DropItem`]s are identified by keys. A key can be of any type that implement the [`Hash`]
348/// and [`Eq`] traits, which include, for example: [`u32`], [`char`], [`str`], ...
349///
350/// See the [module documentation](self) for details.
351#[derive(Default, Debug)]
352pub struct DropTracker<K> {
353    tracked: HashMap<K, StateCell>,
354}
355
356impl<K> DropTracker<K> {
357    /// Creates a new empty `DropTracker`.
358    ///
359    /// # Examples
360    ///
361    /// ```
362    /// use drop_tracker::DropTracker;
363    ///
364    /// let tracker = DropTracker::<u32>::new();
365    /// assert_eq!(tracker.tracked().count(), 0);
366    /// ```
367    #[must_use]
368    pub fn new() -> Self {
369        Self {
370            tracked: HashMap::new(),
371        }
372    }
373
374    /// Returns an iterator over the keys tracked by this `DropTracker`.
375    ///
376    /// The order of keys returned by this iterator is non deterministic.
377    ///
378    /// # Examples
379    ///
380    /// ```
381    /// # #![allow(unused_variables)]
382    /// use drop_tracker::DropTracker;
383    ///
384    /// let mut tracker = DropTracker::new();
385    /// let item_a = tracker.track("a");
386    /// let item_b = tracker.track("b");
387    /// let item_c = tracker.track("c");
388    ///
389    /// let mut keys = tracker.tracked()
390    ///                       .collect::<Vec<&&str>>();
391    /// keys.sort();
392    /// assert_eq!(keys, [&"a", &"b", &"c"]);
393    /// ```
394    pub fn tracked(&self) -> impl Clone + Iterator<Item = &K> + ExactSizeIterator + FusedIterator {
395        self.tracked.keys()
396    }
397
398    /// Returns an iterator over the keys tracked by this `DropTracker` that are alive.
399    ///
400    /// The order of keys returned by this iterator is non deterministic.
401    ///
402    /// # Examples
403    ///
404    /// ```
405    /// use drop_tracker::DropTracker;
406    ///
407    /// let mut tracker = DropTracker::new();
408    /// let item_a = tracker.track("a");
409    /// let item_b = tracker.track("b");
410    /// let item_c = tracker.track("c");
411    ///
412    /// drop(item_c);
413    ///
414    /// let mut alive_keys = tracker.alive()
415    ///                             .collect::<Vec<&&str>>();
416    /// alive_keys.sort();
417    /// assert_eq!(alive_keys, [&"a", &"b"]);
418    ///
419    /// drop(item_a);
420    /// drop(item_b);
421    ///
422    /// assert_eq!(tracker.alive().count(), 0);
423    /// ```
424    pub fn alive(&self) -> impl Clone + Iterator<Item = &K> + FusedIterator {
425        self.tracked.iter()
426                    .filter(|(_, state)| state.is_alive())
427                    .map(|(key, _)| key)
428    }
429
430    /// Returns an iterator over the keys tracked by this `DropTracker` that have been dropped.
431    ///
432    /// The order of keys returned by this iterator is non deterministic.
433    ///
434    /// # Examples
435    ///
436    /// ```
437    /// # #![allow(unused_variables)]
438    /// use drop_tracker::DropTracker;
439    ///
440    /// let mut tracker = DropTracker::new();
441    /// let item_a = tracker.track("a");
442    /// let item_b = tracker.track("b");
443    /// let item_c = tracker.track("c");
444    ///
445    /// assert_eq!(tracker.dropped().count(), 0);
446    ///
447    /// drop(item_a);
448    /// drop(item_b);
449    ///
450    /// let mut alive_keys = tracker.dropped()
451    ///                             .collect::<Vec<&&str>>();
452    /// alive_keys.sort();
453    /// assert_eq!(alive_keys, [&"a", &"b"]);
454    /// ```
455    pub fn dropped(&self) -> impl Clone + Iterator<Item = &K> + FusedIterator {
456        self.tracked.iter()
457                    .filter(|(_, state)| state.is_dropped())
458                    .map(|(key, _)| key)
459    }
460
461    /// Forgets all the items tracked by this `DropTracker`.
462    ///
463    /// The `DropItem`s previously returned by the tracker will still work normally, but it will no
464    /// longer be possible to query their status after forgetting them.
465    ///
466    /// # Examples
467    ///
468    /// ```
469    /// # #![allow(unused_variables)]
470    /// use drop_tracker::DropTracker;
471    ///
472    /// let mut tracker = DropTracker::new();
473    /// assert_eq!(tracker.tracked().count(), 0);
474    ///
475    /// let item_a = tracker.track("a");
476    /// let item_b = tracker.track("b");
477    /// let item_c = tracker.track("c");
478    /// assert_eq!(tracker.tracked().count(), 3);
479    ///
480    /// tracker.forget_all();
481    /// assert_eq!(tracker.tracked().count(), 0);
482    /// ```
483    pub fn forget_all(&mut self) {
484        self.tracked.clear();
485    }
486
487    /// Forgets all the items tracked by this `DropTracker` that have been dropped.
488    ///
489    /// The `DropItem`s previously returned by the tracker will still work normally, but it will no
490    /// longer be possible to query their status after forgetting them.
491    ///
492    /// # Examples
493    ///
494    /// ```
495    /// # #![allow(unused_variables)]
496    /// use drop_tracker::DropTracker;
497    ///
498    /// let mut tracker = DropTracker::new();
499    /// assert_eq!(tracker.tracked().count(), 0);
500    ///
501    /// let item_a = tracker.track("a");
502    /// let item_b = tracker.track("b");
503    /// let item_c = tracker.track("c");
504    /// assert_eq!(tracker.tracked().count(), 3);
505    ///
506    /// // After dropping an item, the item is still tracked
507    /// drop(item_a);
508    /// drop(item_b);
509    /// assert_eq!(tracker.tracked().count(), 3);
510    ///
511    /// // Use `forget_dropped` to lose track of items that have been dropped
512    /// tracker.forget_dropped();
513    /// assert_eq!(tracker.tracked().count(), 1);
514    ///
515    /// let mut keys = tracker.tracked()
516    ///                       .collect::<Vec<&&str>>();
517    /// keys.sort();
518    /// assert_eq!(keys, [&"c"]);
519    /// ```
520    pub fn forget_dropped(&mut self) {
521        self.tracked.retain(|_, state| state.is_alive())
522    }
523}
524
525impl<K: Hash + Eq> DropTracker<K> {
526    /// Creates a new [`DropItem`] identified by the given key.
527    ///
528    /// The value held by the `DropItem` is a clone of the key. Use
529    /// [`DropTracker::track_with_value`] if you wish to specify a custom value.
530    ///
531    /// # Panics
532    ///
533    /// Panics if the key is already used by another tracked item.
534    ///
535    /// Call [`forget`](DropTracker::forget),
536    /// [`forget_dropped`](DropTracker::forget_dropped) or
537    /// [`forget_all`](DropTracker::forget_all) if you wish to reuse a key from an item you no
538    /// longer need to track.
539    ///
540    /// See [`try_track`](DropTracker::try_track) for a variant of this method that does not panic.
541    ///
542    /// # Examples
543    ///
544    /// ```
545    /// use drop_tracker::DropTracker;
546    /// use drop_tracker::State;
547    ///
548    /// let mut tracker = DropTracker::new();
549    ///
550    /// let item = tracker.track("abc");
551    /// assert_eq!(tracker.state("abc"), State::Alive);
552    ///
553    /// drop(item);
554    /// assert_eq!(tracker.state("abc"), State::Dropped);
555    /// ```
556    ///
557    /// Using the same key twice causes a panic:
558    ///
559    /// ```should_panic
560    /// # #![allow(unused_variables)]
561    /// use drop_tracker::DropTracker;
562    ///
563    /// let mut tracker = DropTracker::new();
564    ///
565    /// let item1 = tracker.track("abc");
566    /// let item2 = tracker.track("abc"); // panics!
567    /// ```
568    ///
569    /// Use [`forget`](DropTracker::forget) to reuse the same key:
570    ///
571    /// ```
572    /// # #![allow(unused_variables)]
573    /// use drop_tracker::DropTracker;
574    ///
575    /// let mut tracker = DropTracker::new();
576    ///
577    /// let item1 = tracker.track("abc");
578    /// let _ = tracker.forget("abc");
579    /// let item2 = tracker.track("abc"); // works
580    /// ```
581    pub fn track(&mut self, key: K) -> DropItem<K>
582        where K: Clone
583    {
584        self.try_track(key).expect("cannot track key")
585    }
586
587    /// Creates a new [`DropItem`] identified by the given key, or [`Err`] if the key is
588    /// already in use.
589    ///
590    /// The value held by the `DropItem` is a clone of the key. Use
591    /// [`DropTracker::try_track_with_value`] if you wish to specify a custom value.
592    ///
593    /// See also [`track`](DropTracker::track).
594    ///
595    /// # Examples
596    ///
597    /// ```
598    /// # #![allow(unused_variables)]
599    /// use drop_tracker::DropTracker;
600    ///
601    /// let mut tracker = DropTracker::new();
602    ///
603    /// let item = tracker.try_track("abc");
604    /// assert!(item.is_ok());
605    ///
606    /// let item = tracker.try_track("abc");
607    /// assert!(item.is_err()); // key is already used
608    /// ```
609    pub fn try_track(&mut self, key: K) -> Result<DropItem<K>, CollisionError>
610        where K: Clone
611    {
612        let value = key.clone();
613        self.try_track_with_value(key, value)
614    }
615
616    /// Creates a new [`DropItem`] identified by the given key and holding the given value.
617    ///
618    /// # Panics
619    ///
620    /// Panics if the key is already used by another tracked item.
621    ///
622    /// Call [`forget`](DropTracker::forget),
623    /// [`forget_dropped`](DropTracker::forget_dropped) or
624    /// [`forget_all`](DropTracker::forget_all) if you wish to reuse a key from an item you no
625    /// longer need to track.
626    ///
627    /// See [`try_track_with_value`](DropTracker::try_track_with_value) for a variant of this
628    /// method that does not panic.
629    ///
630    /// # Examples
631    ///
632    /// ```
633    /// use drop_tracker::DropTracker;
634    /// use drop_tracker::State;
635    ///
636    /// let mut tracker = DropTracker::new();
637    ///
638    /// let item = tracker.track_with_value("abc", vec![1, 2, 3]);
639    /// assert_eq!(tracker.state("abc"), State::Alive);
640    ///
641    /// drop(item);
642    /// assert_eq!(tracker.state("abc"), State::Dropped);
643    /// ```
644    ///
645    /// Using the same key twice causes a panic:
646    ///
647    /// ```should_panic
648    /// # #![allow(unused_variables)]
649    /// use drop_tracker::DropTracker;
650    ///
651    /// let mut tracker = DropTracker::new();
652    ///
653    /// let item1 = tracker.track_with_value("abc", vec![1, 2, 3]);
654    /// let item2 = tracker.track_with_value("abc", vec![4, 5, 6]); // panics!
655    /// ```
656    ///
657    /// Use [`forget`](DropTracker::forget) to reuse the same key:
658    ///
659    /// ```
660    /// # #![allow(unused_variables)]
661    /// use drop_tracker::DropTracker;
662    ///
663    /// let mut tracker = DropTracker::new();
664    ///
665    /// let item1 = tracker.track_with_value("abc", vec![1, 2, 3]);
666    /// let _ = tracker.forget("abc");
667    /// let item2 = tracker.track_with_value("abc", vec![4, 5, 6]); // works
668    /// ```
669    pub fn track_with_value<V>(&mut self, key: K, value: V) -> DropItem<V> {
670        self.try_track_with_value(key, value).expect("cannot track key")
671    }
672
673    /// Creates a new [`DropItem`] identified by the given key and holding the given value, or
674    /// [`Err`] if the key is already in use.
675    ///
676    /// See also [`track_with_value`](DropTracker::track_with_value).
677    ///
678    /// # Examples
679    ///
680    /// ```
681    /// # #![allow(unused_variables)]
682    /// use drop_tracker::DropTracker;
683    ///
684    /// let mut tracker = DropTracker::new();
685    ///
686    /// let item = tracker.try_track_with_value("abc", vec![1, 2, 3]);
687    /// assert!(item.is_ok());
688    ///
689    /// let item = tracker.try_track_with_value("abc", vec![4, 5, 6]);
690    /// assert!(item.is_err()); // key is already used
691    /// ```
692    pub fn try_track_with_value<V>(&mut self, key: K, value: V) -> Result<DropItem<V>, CollisionError> {
693        let state = StateCell::new(State::Alive);
694        match self.tracked.entry(key) {
695            Entry::Occupied(_) => Err(CollisionError),
696            Entry::Vacant(entry) => {
697                entry.insert(state.clone());
698                Ok(DropItem::new(value, state))
699            },
700        }
701    }
702
703    /// Creates multiple new [`DropItem`] structs, each identified by a key from the given
704    /// iterable.
705    ///
706    /// Calling `track_many` is equivalent to calling [`track`](DropItem::track) multiple times.
707    ///
708    /// # Examples
709    ///
710    /// ```
711    /// use drop_tracker::DropTracker;
712    /// use drop_tracker::State;
713    ///
714    /// let mut tracker = DropTracker::new();
715    ///
716    /// let mut items = tracker.track_many(["abc", "def", "ghi"]);
717    ///
718    /// let abc = items.next().unwrap();
719    /// let def = items.next().unwrap();
720    /// let ghi = items.next().unwrap();
721    /// assert_eq!(items.next(), None);
722    /// drop(items);
723    ///
724    /// assert_eq!(abc, "abc");
725    /// assert_eq!(def, "def");
726    /// assert_eq!(ghi, "ghi");
727    ///
728    /// assert_eq!(tracker.state("abc"), State::Alive);
729    /// assert_eq!(tracker.state("def"), State::Alive);
730    /// assert_eq!(tracker.state("ghi"), State::Alive);
731    ///
732    /// drop(def);
733    ///
734    /// assert_eq!(tracker.state("abc"), State::Alive);
735    /// assert_eq!(tracker.state("def"), State::Dropped);
736    /// assert_eq!(tracker.state("ghi"), State::Alive);
737    ///
738    /// # drop(abc);
739    /// # drop(ghi);
740    /// ```
741    pub fn track_many<'a, Iter>(&'a mut self, keys: Iter) -> impl Iterator<Item = DropItem<K>> + 'a
742        where Iter: IntoIterator<Item = K> + 'a,
743              K: Clone
744    {
745        keys.into_iter().map(|key| self.track(key))
746    }
747}
748
749impl<K: Hash + Eq> DropTracker<K> {
750    /// Checks the state of a [`DropItem`] tracked by this `DropTracker`: [alive](State::Alive) or
751    /// [dropped](State::Dropped).
752    ///
753    /// # Panics
754    ///
755    /// Panics if the given key is not tracked.
756    ///
757    /// See [`try_state`](DropTracker::try_state) for a variant of this method that does not panic.
758    ///
759    /// # Examples
760    ///
761    /// ```
762    /// use drop_tracker::DropTracker;
763    /// use drop_tracker::State;
764    ///
765    /// let mut tracker = DropTracker::new();
766    ///
767    /// let item = tracker.track("abc");
768    /// assert_eq!(tracker.state("abc"), State::Alive);
769    ///
770    /// drop(item);
771    /// assert_eq!(tracker.state("abc"), State::Dropped);
772    /// ```
773    ///
774    /// Querying a key that is not tracked causes a panic:
775    ///
776    /// ```should_panic
777    /// # #![allow(unused_variables)]
778    /// use drop_tracker::DropTracker;
779    ///
780    /// let mut tracker = DropTracker::new();
781    ///
782    /// let item = tracker.track("abc");
783    /// let state = tracker.state("def"); // panics!
784    /// ```
785    pub fn state<Q>(&self, key: &Q) -> State
786        where K: Borrow<Q>,
787              Q: Hash + Eq + ?Sized
788    {
789        self.try_state(key).expect("cannot get state")
790    }
791
792    /// Checks the state of a [`DropItem`] tracked by this `DropTracker`: [alive](State::Alive) or
793    /// [dropped](State::Dropped). Returns [`Err`] it the given key is not tracked.
794    ///
795    /// See also [`state`](DropTracker::state).
796    ///
797    /// # Examples
798    ///
799    /// ```
800    /// use drop_tracker::DropTracker;
801    /// use drop_tracker::NotTrackedError;
802    /// use drop_tracker::State;
803    ///
804    /// let mut tracker = DropTracker::new();
805    ///
806    /// let item = tracker.track("abc");
807    /// assert_eq!(tracker.try_state("abc"), Ok(State::Alive));
808    /// assert_eq!(tracker.try_state("def"), Err(NotTrackedError));
809    ///
810    /// drop(item);
811    /// assert_eq!(tracker.try_state("abc"), Ok(State::Dropped));
812    /// assert_eq!(tracker.try_state("def"), Err(NotTrackedError));
813    /// ```
814    pub fn try_state<Q>(&self, key: &Q) -> Result<State, NotTrackedError>
815        where K: Borrow<Q>,
816              Q: Hash + Eq + ?Sized
817    {
818        self.tracked.get(key)
819                    .ok_or(NotTrackedError)
820                    .map(|state| state.get())
821    }
822
823    /// Forgets an item tracked by this `DropTracker`, and returns its current state
824    /// ([alive](State::Alive) or [dropped](State::Dropped)).
825    ///
826    /// The `DropItem`s previously returned by the tracker will still work normally, but it will no
827    /// longer be possible to query their status after forgetting them.
828    ///
829    /// # Panics
830    ///
831    /// Panics if the given key is not tracked.
832    ///
833    /// See [`try_forget`](DropTracker::try_forget) for a variant of this method that does not panic.
834    ///
835    /// # Examples
836    ///
837    /// ```
838    /// # #![allow(unused_variables)]
839    /// use drop_tracker::DropTracker;
840    /// use drop_tracker::State;
841    ///
842    /// let mut tracker = DropTracker::new();
843    ///
844    /// let item = tracker.track("a");
845    /// assert!(tracker.is_tracked("a"));
846    ///
847    /// assert_eq!(tracker.forget("a"), State::Alive);
848    /// assert!(!tracker.is_tracked("a"));
849    /// ```
850    ///
851    /// Forgetting a key that is not tracked causes a panic:
852    ///
853    /// ```should_panic
854    /// # #![allow(unused_variables)]
855    /// use drop_tracker::DropTracker;
856    ///
857    /// let mut tracker = DropTracker::new();
858    ///
859    /// let item = tracker.track("abc");
860    /// let state = tracker.forget("def"); // panics!
861    /// ```
862    pub fn forget<Q>(&mut self, key: &Q) -> State
863        where K: Borrow<Q>,
864              Q: Hash + Eq + ?Sized
865    {
866        self.try_forget(key).expect("cannot forget item")
867    }
868
869    /// Forgets an item tracked by this `DropTracker`, and returns its current state
870    /// ([alive](State::Alive) or [dropped](State::Dropped)), or [`Err`] if the item is not
871    /// tracked.
872    ///
873    /// The `DropItem`s previously returned by the tracker will still work normally, but it will no
874    /// longer be possible to query their status after forgetting them.
875    ///
876    /// See also [`forget`](DropTracker::forget).
877    ///
878    /// # Examples
879    ///
880    /// ```
881    /// # #![allow(unused_variables)]
882    /// use drop_tracker::DropTracker;
883    /// use drop_tracker::NotTrackedError;
884    /// use drop_tracker::State;
885    ///
886    /// let mut tracker = DropTracker::new();
887    ///
888    /// let item = tracker.track("a");
889    /// assert!(tracker.is_tracked("a"));
890    ///
891    /// assert_eq!(tracker.try_forget("a"), Ok(State::Alive));
892    /// assert_eq!(tracker.try_forget("b"), Err(NotTrackedError));
893    /// ```
894    pub fn try_forget<Q>(&mut self, key: &Q) -> Result<State, NotTrackedError>
895        where K: Borrow<Q>,
896              Q: Hash + Eq + ?Sized
897    {
898        self.tracked.remove(key)
899                    .ok_or(NotTrackedError)
900                    .map(|state| state.get())
901    }
902
903    /// Returns [`true`] if an item identified by the given key is tracked by this `DropTracker`,
904    /// [`false`] otherwise.
905    ///
906    /// # Examples
907    ///
908    /// ```
909    /// # #![allow(unused_variables)]
910    /// use drop_tracker::DropTracker;
911    ///
912    /// let mut tracker = DropTracker::new();
913    /// assert!(!tracker.is_tracked("abc"));
914    ///
915    /// let item = tracker.track("abc");
916    /// assert!(tracker.is_tracked("abc"));
917    /// ```
918    #[must_use]
919    pub fn is_tracked<Q>(&self, key: &Q) -> bool
920        where K: Borrow<Q>,
921              Q: Hash + Eq + ?Sized
922    {
923        self.try_state(key).is_ok()
924    }
925
926    /// Returns [`Ok`] if all the given keys point to items that are [alive](State::Alive),
927    /// [`Err`] otherwise.
928    ///
929    /// An error may be returned in two cases: either a key is not tracked, or it has been dropped.
930    ///
931    /// This method returns `Ok` if the sequence of keys passed is empty.
932    ///
933    /// # Examples
934    ///
935    /// ```
936    /// # #![allow(unused_variables)]
937    /// use drop_tracker::DropTracker;
938    /// use drop_tracker::NotAllAliveError;
939    ///
940    /// let mut tracker = DropTracker::new();
941    ///
942    /// let item1 = tracker.track(1);
943    /// let item2 = tracker.track(2);
944    /// let item3 = tracker.track(3);
945    /// let item4 = tracker.track(4);
946    ///
947    /// drop(item3);
948    /// drop(item4);
949    ///
950    /// assert_eq!(tracker.all_alive([1, 2]), Ok(()));
951    ///
952    /// assert_eq!(tracker.all_alive([1, 2, 3, 4, 5, 6]),
953    ///            Err(NotAllAliveError {
954    ///                dropped: vec![3, 4],
955    ///                untracked: vec![5, 6],
956    ///            }));
957    /// ```
958    ///
959    /// Passing an empty set of keys returns `Ok`:
960    ///
961    /// ```
962    /// use drop_tracker::DropTracker;
963    ///
964    /// let tracker = DropTracker::<()>::new();
965    /// assert_eq!(tracker.all_alive([(); 0]), Ok(()));
966    /// ```
967    pub fn all_alive<Q, Item, Iter>(&self, iter: Iter) -> Result<(), NotAllAliveError<Item>>
968        where K: Borrow<Q>,
969              Q: Hash + Eq + ?Sized,
970              Item: Borrow<Q>,
971              Iter: IntoIterator<Item = Item>
972    {
973        // Vec won't allocate any memory until items are pushed to it, so if this method does not
974        // fail, no memory will be allocated
975        let mut err = NotAllAliveError {
976            dropped: Vec::new(),
977            untracked: Vec::new(),
978        };
979
980        for key in iter {
981            match self.try_state(key.borrow()) {
982                Ok(State::Alive) => (),
983                Ok(State::Dropped) => err.dropped.push(key),
984                Err(NotTrackedError) => err.untracked.push(key),
985            }
986        }
987
988        if err.dropped.is_empty() && err.untracked.is_empty() {
989            Ok(())
990        } else {
991            Err(err)
992        }
993    }
994
995    /// Returns [`Ok`] if all the given keys point to items that are [dropped](State::Dropped),
996    /// [`Err`] otherwise.
997    ///
998    /// An error may be returned in two cases: either a key is not tracked, or it is alive.
999    ///
1000    /// This method returns `Ok` if the sequence of keys passed is empty.
1001    ///
1002    /// # Examples
1003    ///
1004    /// ```
1005    /// # #![allow(unused_variables)]
1006    /// use drop_tracker::DropTracker;
1007    /// use drop_tracker::NotAllDroppedError;
1008    ///
1009    /// let mut tracker = DropTracker::new();
1010    ///
1011    /// let item1 = tracker.track(1);
1012    /// let item2 = tracker.track(2);
1013    /// let item3 = tracker.track(3);
1014    /// let item4 = tracker.track(4);
1015    ///
1016    /// drop(item3);
1017    /// drop(item4);
1018    ///
1019    /// assert_eq!(tracker.all_dropped([3, 4]), Ok(()));
1020    ///
1021    /// assert_eq!(tracker.all_dropped([1, 2, 3, 4, 5, 6]),
1022    ///            Err(NotAllDroppedError {
1023    ///                alive: vec![1, 2],
1024    ///                untracked: vec![5, 6],
1025    ///            }));
1026    /// ```
1027    ///
1028    /// Passing an empty set of keys returns `Ok`:
1029    ///
1030    /// ```
1031    /// use drop_tracker::DropTracker;
1032    ///
1033    /// let tracker = DropTracker::<()>::new();
1034    /// assert_eq!(tracker.all_dropped([(); 0]), Ok(()));
1035    /// ```
1036    pub fn all_dropped<Q, Item, Iter>(&self, iter: Iter) -> Result<(), NotAllDroppedError<Item>>
1037        where K: Borrow<Q>,
1038              Q: Hash + Eq + ?Sized,
1039              Item: Borrow<Q>,
1040              Iter: IntoIterator<Item = Item>
1041    {
1042        // Vec won't allocate any memory until items are pushed to it, so if this method does not
1043        // fail, no memory will be allocated
1044        let mut err = NotAllDroppedError {
1045            alive: Vec::new(),
1046            untracked: Vec::new(),
1047        };
1048
1049        for key in iter {
1050            match self.try_state(key.borrow()) {
1051                Ok(State::Alive) => err.alive.push(key),
1052                Ok(State::Dropped) => (),
1053                Err(NotTrackedError) => err.untracked.push(key),
1054            }
1055        }
1056
1057        if err.alive.is_empty() && err.untracked.is_empty() {
1058            Ok(())
1059        } else {
1060            Err(err)
1061        }
1062    }
1063
1064    /// Returns [`Ok`] if all the keys tracked are [alive](State::Alive), [`Err`] otherwise.
1065    ///
1066    /// The error returned references an arbitrary keys that was found [dropped](State::Dropped).
1067    ///
1068    /// If the tracker is empty, this method returns `Ok`.
1069    ///
1070    /// # Examples
1071    ///
1072    /// ```
1073    /// # #![allow(unused_variables)]
1074    /// use drop_tracker::DropTracker;
1075    /// use drop_tracker::SomeDroppedError;
1076    ///
1077    /// let mut tracker = DropTracker::new();
1078    ///
1079    /// let item1 = tracker.track(1);
1080    /// let item2 = tracker.track(2);
1081    /// let item3 = tracker.track(3);
1082    ///
1083    /// assert_eq!(tracker.fully_alive(), Ok(()));
1084    ///
1085    /// drop(item1);
1086    ///
1087    /// assert_eq!(tracker.fully_alive(), Err(SomeDroppedError { dropped: &1 }));
1088    /// ```
1089    ///
1090    /// Calling `fully_alive()` on an empty tracker always returns `Ok`:
1091    ///
1092    /// ```
1093    /// use drop_tracker::DropTracker;
1094    ///
1095    /// let tracker = DropTracker::<()>::new();
1096    /// assert_eq!(tracker.fully_alive(), Ok(()));
1097    /// ```
1098    pub fn fully_alive(&self) -> Result<(), SomeDroppedError<'_, K>> {
1099        let dropped = self.tracked.iter()
1100                          .find(|(_, state)| state.is_dropped())
1101                          .map(|(key, _)| key);
1102        match dropped {
1103            None => Ok(()),
1104            Some(dropped) => Err(SomeDroppedError { dropped }),
1105        }
1106    }
1107
1108    /// Returns [`Ok`] if all the keys tracked are [dropped](State::Dropped), [`Err`] otherwise.
1109    ///
1110    /// The error returned references an arbitrary keys that was found [alive](State::Alive).
1111    ///
1112    /// If the tracker is empty, this method returns `Ok`.
1113    ///
1114    /// # Examples
1115    ///
1116    /// ```
1117    /// # #![allow(unused_variables)]
1118    /// use drop_tracker::DropTracker;
1119    /// use drop_tracker::SomeAliveError;
1120    ///
1121    /// let mut tracker = DropTracker::new();
1122    ///
1123    /// let item1 = tracker.track(1);
1124    /// let item2 = tracker.track(2);
1125    /// let item3 = tracker.track(3);
1126    ///
1127    /// drop(item1);
1128    /// drop(item2);
1129    ///
1130    /// assert_eq!(tracker.fully_dropped(), Err(SomeAliveError { alive: &3 }));
1131    ///
1132    /// drop(item3);
1133    ///
1134    /// assert_eq!(tracker.fully_dropped(), Ok(()));
1135    /// ```
1136    ///
1137    /// Calling `fully_dropped()` on an empty tracker always returns `Ok`:
1138    ///
1139    /// ```
1140    /// use drop_tracker::DropTracker;
1141    ///
1142    /// let tracker = DropTracker::<()>::new();
1143    /// assert_eq!(tracker.fully_dropped(), Ok(()));
1144    /// ```
1145    pub fn fully_dropped(&self) -> Result<(), SomeAliveError<'_, K>> {
1146        let alive = self.tracked.iter()
1147                        .find(|(_, state)| state.is_alive())
1148                        .map(|(key, _)| key);
1149        match alive {
1150            None => Ok(()),
1151            Some(alive) => Err(SomeAliveError { alive }),
1152        }
1153    }
1154
1155    /// Checks that all the given key points to an item that is [alive](State::Alive), panics
1156    /// otherwise.
1157    ///
1158    /// `assert_alive(...)` is a shortcut for `state(...).alive().unwrap()`. See
1159    /// [`state()`](DropTracker::state) for more details.
1160    ///
1161    /// # Panics
1162    ///
1163    /// If the key is not tracked, or if it has been dropped.
1164    ///
1165    /// # Examples
1166    ///
1167    /// ```should_panic
1168    /// # #![allow(unused_variables)]
1169    /// use drop_tracker::DropTracker;
1170    ///
1171    /// let mut tracker = DropTracker::new();
1172    ///
1173    /// let item2 = tracker.track(1);
1174    /// let item2 = tracker.track(2);
1175    ///
1176    /// drop(item2);
1177    ///
1178    /// tracker.assert_alive(&1); // succeeds
1179    /// tracker.assert_alive(&2); // panics (item was dropped)
1180    /// tracker.assert_alive(&3); // panics (key is not tracked)
1181    /// ```
1182    pub fn assert_alive<Q>(&self, key: &Q)
1183        where K: Borrow<Q>,
1184              Q: Hash + Eq + ?Sized
1185    {
1186        let state = match self.try_state(key) {
1187            Ok(state) => state,
1188            Err(err) => panic!("{err}"),
1189        };
1190        match state.alive() {
1191            Ok(()) => (),
1192            Err(err) => panic!("{err}"),
1193        }
1194    }
1195
1196    /// Checks that all the given key points to an item that is [dropped](State::Dropped), panics
1197    /// otherwise.
1198    ///
1199    /// `assert_dropped(...)` is a shortcut for `state(...).dropped().unwrap()`. See
1200    /// [`state()`](DropTracker::state) for more details.
1201    ///
1202    /// # Panics
1203    ///
1204    /// If the key is not tracked, or if it is alive.
1205    ///
1206    /// # Examples
1207    ///
1208    /// ```should_panic
1209    /// # #![allow(unused_variables)]
1210    /// use drop_tracker::DropTracker;
1211    ///
1212    /// let mut tracker = DropTracker::new();
1213    ///
1214    /// let item1 = tracker.track(1);
1215    /// let item2 = tracker.track(2);
1216    ///
1217    /// drop(item1);
1218    ///
1219    /// tracker.assert_dropped(&1); // succeeds
1220    /// tracker.assert_dropped(&2); // panics (item is alive)
1221    /// tracker.assert_dropped(&3); // panics (key is not tracked)
1222    /// ```
1223    pub fn assert_dropped<Q>(&self, key: &Q)
1224        where K: Borrow<Q>,
1225              Q: Hash + Eq + ?Sized
1226    {
1227        let state = match self.try_state(key) {
1228            Ok(state) => state,
1229            Err(err) => panic!("{err}"),
1230        };
1231        match state.dropped() {
1232            Ok(()) => (),
1233            Err(err) => panic!("{err}"),
1234        }
1235    }
1236
1237    /// Checks that all the given keys point to items that are [alive](State::Alive), panics
1238    /// otherwise.
1239    ///
1240    /// `assert_all_alive(...)` is a shortcut for `all_alive(...).unwrap()`. See
1241    /// [`all_alive()`](DropTracker::all_alive) for more details.
1242    ///
1243    /// # Panics
1244    ///
1245    /// If a key is not tracked, or if it has been dropped.
1246    ///
1247    /// # Examples
1248    ///
1249    /// ```should_panic
1250    /// # #![allow(unused_variables)]
1251    /// use drop_tracker::DropTracker;
1252    ///
1253    /// let mut tracker = DropTracker::new();
1254    ///
1255    /// let item1 = tracker.track(1);
1256    /// let item2 = tracker.track(2);
1257    /// let item3 = tracker.track(3);
1258    /// let item4 = tracker.track(4);
1259    ///
1260    /// drop(item3);
1261    /// drop(item4);
1262    ///
1263    /// tracker.assert_all_alive([1, 2]); // succeeds
1264    /// tracker.assert_all_alive([3, 4]); // panics (items were dropped)
1265    /// tracker.assert_all_alive([5, 6]); // panics (keys are not tracked)
1266    /// ```
1267    ///
1268    /// Passing an empty set of keys succeeds:
1269    ///
1270    /// ```
1271    /// use drop_tracker::DropTracker;
1272    ///
1273    /// let tracker = DropTracker::<()>::new();
1274    /// tracker.assert_all_alive([(); 0]);
1275    /// ```
1276    pub fn assert_all_alive<Q, Item, Iter>(&self, iter: Iter)
1277        where K: Borrow<Q>,
1278              Q: Hash + Eq + ?Sized,
1279              Item: Borrow<Q> + fmt::Debug,
1280              Iter: IntoIterator<Item = Item>
1281    {
1282        match self.all_alive(iter) {
1283            Ok(()) => (),
1284            Err(err) => panic!("{err}"),
1285        }
1286    }
1287
1288    /// Checks that all the given keys point to items that are [dropped](State::Dropped), panics
1289    /// otherwise.
1290    ///
1291    /// `assert_all_dropped(...)` is a shortcut for `all_dropped(...).unwrap()`. See
1292    /// [`all_dropped()`](DropTracker::all_dropped) for more details.
1293    ///
1294    /// # Panics
1295    ///
1296    /// If a key is not tracked, or if it is alive.
1297    ///
1298    /// # Examples
1299    ///
1300    /// ```should_panic
1301    /// # #![allow(unused_variables)]
1302    /// use drop_tracker::DropTracker;
1303    ///
1304    /// let mut tracker = DropTracker::new();
1305    ///
1306    /// let item1 = tracker.track(1);
1307    /// let item2 = tracker.track(2);
1308    /// let item3 = tracker.track(3);
1309    /// let item4 = tracker.track(4);
1310    ///
1311    /// drop(item1);
1312    /// drop(item2);
1313    ///
1314    /// tracker.assert_all_dropped([1, 2]); // succeeds
1315    /// tracker.assert_all_dropped([3, 4]); // panics (items are alive)
1316    /// tracker.assert_all_dropped([5, 6]); // panics (keys are not tracked)
1317    /// ```
1318    ///
1319    /// Passing an empty set of keys succeeds:
1320    ///
1321    /// ```
1322    /// use drop_tracker::DropTracker;
1323    ///
1324    /// let tracker = DropTracker::<()>::new();
1325    /// tracker.assert_all_dropped([(); 0]);
1326    /// ```
1327    pub fn assert_all_dropped<Q, Item, Iter>(&self, iter: Iter)
1328        where K: Borrow<Q>,
1329              Q: Hash + Eq + ?Sized,
1330              Item: Borrow<Q> + fmt::Debug,
1331              Iter: IntoIterator<Item = Item>
1332    {
1333        match self.all_dropped(iter) {
1334            Ok(()) => (),
1335            Err(err) => panic!("{err}"),
1336        }
1337    }
1338
1339    /// Checks that all the keys tracked are [alive](State::Alive), panics otherwise.
1340    ///
1341    /// `assert_fully_alive()` is a shortcut for `fully_alive().unwrap()`. See
1342    /// [`fully_alive()`](DropTracker::fully_alive) for more details.
1343    ///
1344    /// # Panics
1345    ///
1346    /// If one or more items were found to have been [dropped](State::Dropped).
1347    ///
1348    /// # Examples
1349    ///
1350    /// Calling `assert_fully_alive()` when all items are alive succeeds:
1351    ///
1352    /// ```
1353    /// # #![allow(unused_variables)]
1354    /// use drop_tracker::DropTracker;
1355    ///
1356    /// let mut tracker = DropTracker::new();
1357    ///
1358    /// let item1 = tracker.track(1);
1359    /// let item2 = tracker.track(2);
1360    ///
1361    /// tracker.assert_fully_alive(); // succeeds
1362    /// ```
1363    ///
1364    /// Calling `assert_fully_alive()` when one or more items are dropped causes a panic:
1365    ///
1366    /// ```should_panic
1367    /// # #![allow(unused_variables)]
1368    /// use drop_tracker::DropTracker;
1369    ///
1370    /// let mut tracker = DropTracker::new();
1371    ///
1372    /// let item1 = tracker.track(1);
1373    /// let item2 = tracker.track(2);
1374    ///
1375    /// drop(item1);
1376    ///
1377    /// tracker.assert_fully_alive(); // panics
1378    /// ```
1379    ///
1380    /// Calling `assert_fully_alive()` when the tracker is empty succeeds:
1381    ///
1382    /// ```
1383    /// use drop_tracker::DropTracker;
1384    ///
1385    /// let tracker = DropTracker::<()>::new();
1386    /// tracker.assert_fully_alive(); // succeeds
1387    /// ```
1388    pub fn assert_fully_alive(&self)
1389        where K: fmt::Debug
1390    {
1391        match self.fully_alive() {
1392            Ok(()) => (),
1393            Err(err) => panic!("{err}"),
1394        }
1395    }
1396
1397    /// Checks that all the keys tracked are [dropped](State::Dropped), panics otherwise.
1398    ///
1399    /// `assert_fully_dropped()` is a shortcut for `fully_dropped().unwrap()`. See
1400    /// [`fully_dropped()`](DropTracker::fully_dropped) for more details.
1401    ///
1402    /// # Panics
1403    ///
1404    /// If one or more items were found [alive](State::Alive).
1405    ///
1406    /// # Examples
1407    ///
1408    /// Calling `assert_fully_dropped()` when items are alive causes a panic:
1409    ///
1410    /// ```should_panic
1411    /// # #![allow(unused_variables)]
1412    /// use drop_tracker::DropTracker;
1413    ///
1414    /// let mut tracker = DropTracker::new();
1415    ///
1416    /// let item1 = tracker.track(1);
1417    /// let item2 = tracker.track(2);
1418    ///
1419    /// tracker.assert_fully_dropped(); // panics
1420    /// ```
1421    ///
1422    /// Calling `assert_fully_dropped()` when all items are dropped succeeds:
1423    ///
1424    /// ```
1425    /// use drop_tracker::DropTracker;
1426    ///
1427    /// let mut tracker = DropTracker::new();
1428    ///
1429    /// let item1 = tracker.track(1);
1430    /// let item2 = tracker.track(2);
1431    ///
1432    /// drop(item1);
1433    /// drop(item2);
1434    ///
1435    /// tracker.assert_fully_dropped(); // succeeds
1436    /// ```
1437    ///
1438    /// Calling `assert_fully_dropped()` when the tracker is empty succeeds:
1439    ///
1440    /// ```
1441    /// use drop_tracker::DropTracker;
1442    ///
1443    /// let tracker = DropTracker::<()>::new();
1444    /// tracker.assert_fully_dropped(); // succeeds
1445    /// ```
1446    pub fn assert_fully_dropped(&self)
1447        where K: fmt::Debug
1448    {
1449        match self.fully_dropped() {
1450            Ok(()) => (),
1451            Err(err) => panic!("{err}"),
1452        }
1453    }
1454}
1455
1456/// An item that will notify the parent [`DropTracker`] once it gets dropped.
1457///
1458/// `DropItem` instances are created by [`DropTracker::track`], [`DropTracker::track_with_value`],
1459/// and related functions. `DropItem` instances may contain an "underlying value" that affects the
1460/// item behavior when used with standard traits. The underlying value is either:
1461///
1462/// * a clone of `key` when constructing an item using `track(key)` (implicit); or
1463/// * `value` when constructing an item using `track_with_value(key, value)` (explicit).
1464///
1465/// To check whether an item is alive or has been dropped, use [`DropTracker::state`] or see the
1466/// documentation for [`DropTracker`] for alternatives.
1467///
1468/// # Coercing and borrowing
1469///
1470/// `DropItem` instances may be [_coerced_](std::ops::Deref) and [_borrowed_](std::borrow::Borrow)
1471/// as the the underlying value type. This means that, for example, if you create a `DropItem`
1472/// using `track(String::from("abc"))`, you may call all of the `String` methods on that item.
1473///
1474/// `DropItem` also implements the standard traits [`PartialEq`](std::cmp::PartialEq),
1475/// [`Eq`](std::cmp::Eq), [`PartialOrd`](std::cmp::PartialOrd), [`Ord`](std::cmp::Ord) and
1476/// [`Hash`](std::hash::Hash), [`Display`](std::fmt::Display), [`Debug`](std::fmt::Debug) if the
1477/// type of the underlying value implements them.
1478///
1479/// # Cloning
1480///
1481/// `DropItem` does not implement the [`Clone`] trait as it would introduce ambiguity with respect
1482/// to understanding whether the item has been dropped or is still alive when using
1483/// [`DropTracker::state`].
1484///
1485/// # Double drop
1486///
1487/// `DropItem` instances can be dropped twice or more. Doing so will cause a panic, but will not
1488/// cause undefined behavior (unless you're calling drop on an invalid memory location). The panic
1489/// on double drop is an useful feature to detect logic errors in destructors.
1490///
1491/// # Safety
1492///
1493/// Borrowing or performing operations on the underlying value of a `DropItem` is generally safe
1494/// when using safe Rust code. However, `DropItem`s are often used in unsafe code and are used to
1495/// detect potential bugs. In those circumstances, it is possible to trigger undefined behavior.
1496/// In particular, borrowing or performing operations on a `DropItem` while another thread is
1497/// dropping will result in undefined behavior (although it must be noted that this is a bug in the
1498/// caller code and is not something that should happen in safe Rust code).
1499///
1500/// Only [`Drop`](std::ops::Drop) on a `DropItem` is guaranteed to be safe in all circumstances.
1501///
1502/// # Examples
1503///
1504/// ```
1505/// use drop_tracker::DropTracker;
1506///
1507/// let mut tracker = DropTracker::<u32>::new();
1508///
1509/// // Create an item using `123u32` as the key. Implicitly, this also sets its value to `123u32`
1510/// let item = tracker.track(123);
1511///
1512/// // Check that the item is alive
1513/// tracker.state(&123).alive().expect("item should be alive");
1514///
1515/// // Dereference the value of the item
1516/// assert_eq!(*item, 123);
1517/// assert!(!item.is_power_of_two());
1518///
1519/// // Drop the item and check that it really got dropped
1520/// drop(item);
1521/// tracker.state(&123).dropped().expect("item should be dropped");
1522///
1523/// // Create a new item, this time using an explicit `String` value
1524/// let abc_item = tracker.track_with_value(111, String::from("abc"));
1525///
1526/// // Comparison with other items using `String` work using the underlying `String`
1527/// // operations
1528/// assert_eq!(abc_item, tracker.track_with_value(222, String::from("abc")));
1529/// assert_ne!(abc_item, tracker.track_with_value(333, String::from("def")));
1530/// assert!(abc_item < tracker.track_with_value(444, String::from("def")));
1531///
1532/// // Display, debug and hashing also work using the underlying `String` operations
1533/// assert_eq!(format!("{}", abc_item), "abc");
1534/// assert_eq!(format!("{:?}", abc_item), "DropItem { value: \"abc\", state: Alive }");
1535///
1536/// use std::collections::hash_map::DefaultHasher;
1537/// use std::hash::Hash;
1538/// use std::hash::Hasher;
1539/// fn hash<T: Hash + ?Sized>(x: &T) -> u64 {
1540///     let mut hasher = DefaultHasher::new();
1541///     x.hash(&mut hasher);
1542///     hasher.finish()
1543/// }
1544/// assert_eq!(hash(&abc_item), hash(&"abc"));
1545///
1546/// // Methods on `String` can be called transparently on items
1547/// assert_eq!(abc_item.to_ascii_uppercase(), "ABC");
1548/// ```
1549///
1550/// Using hashable items in a set, with an implicit underlying value:
1551///
1552/// ```
1553/// use drop_tracker::DropTracker;
1554/// use std::collections::HashSet;
1555///
1556/// let mut tracker = DropTracker::new();
1557///
1558/// let mut set = HashSet::from([
1559///     tracker.track(1),
1560///     tracker.track(2),
1561///     tracker.track(3),
1562/// ]);
1563///
1564/// set.remove(&3);
1565///
1566/// tracker.state(&1).alive().expect("first item should be alive");
1567/// tracker.state(&2).alive().expect("second item should be alive");
1568/// tracker.state(&3).dropped().expect("third item should be dropped");
1569/// ```
1570///
1571/// Using hashable items in a set, with an explicit underlying value:
1572///
1573/// ```
1574/// use drop_tracker::DropTracker;
1575/// use std::collections::HashSet;
1576///
1577/// let mut tracker = DropTracker::new();
1578///
1579/// let mut set = HashSet::from([
1580///     tracker.track_with_value(1, String::from("first")),
1581///     tracker.track_with_value(2, String::from("second")),
1582///     tracker.track_with_value(3, String::from("third")),
1583/// ]);
1584///
1585/// set.remove("third");
1586///
1587/// tracker.state(&1).alive().expect("first item should be alive");
1588/// tracker.state(&2).alive().expect("second item should be alive");
1589/// tracker.state(&3).dropped().expect("third item should be dropped");
1590/// ```
1591#[must_use = "if you don't use this item, it will get automatically dropped"]
1592pub struct DropItem<V> {
1593    value: MaybeUninit<V>,
1594    state: Option<StateCell>,
1595}
1596
1597impl<V> DropItem<V> {
1598    const fn new(value: V, state: StateCell) -> Self {
1599        Self {
1600            value: MaybeUninit::new(value),
1601            state: Some(state),
1602        }
1603    }
1604}
1605
1606impl<V> Drop for DropItem<V> {
1607    fn drop(&mut self) {
1608        // The use of an Option might seem redundant, but it's actually needed to safely detect and
1609        // report double drops. Without the Option, we would be touching shared memory behind an Rc
1610        // that probably does not exist anymore, causing memory corruption. The Option makes this a
1611        // bit safer (assuming that the DropItem memory has not been moved or altered), and also
1612        // prevents a double drop on the Rc.
1613        match self.state.take() {
1614            Some(mut state) => {
1615                if state.replace(State::Dropped).is_dropped() {
1616                    panic!("item dropped twice");
1617                }
1618                // SAFETY: `state` was `Some(State::Alive)`, which means that `value` has not been
1619                // dropped yet and that `value` is initialized.
1620                unsafe { self.value.assume_init_drop() };
1621            },
1622            None => {
1623                panic!("item dropped twice");
1624            },
1625        }
1626    }
1627}
1628
1629/// Error signaling that an item was expected to have been dropped, but it's [alive](State::Alive).
1630///
1631/// See [`State::dropped`] for more information and examples.
1632#[derive(PartialEq, Eq, Debug)]
1633pub struct AliveError;
1634
1635impl fmt::Display for AliveError {
1636    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1637        fmt::Display::fmt("item is alive", f)
1638    }
1639}
1640
1641impl Error for AliveError {
1642}
1643
1644/// Error signaling that an item was expected to be alive, but it was [dropped](State::Dropped).
1645///
1646/// See [`State::alive`] for more information and examples.
1647#[derive(PartialEq, Eq, Debug)]
1648pub struct DroppedError;
1649
1650impl fmt::Display for DroppedError {
1651    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1652        fmt::Display::fmt("item is dropped", f)
1653    }
1654}
1655
1656impl Error for DroppedError {
1657}
1658
1659/// Error returned when trying to place multiple items with the same key inside the same [`DropTracker`].
1660///
1661/// See [`DropTracker::try_track`] for more information and examples.
1662#[derive(PartialEq, Eq, Debug)]
1663pub struct CollisionError;
1664
1665impl fmt::Display for CollisionError {
1666    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1667        fmt::Display::fmt("another item with the same key is already tracked", f)
1668    }
1669}
1670
1671impl Error for CollisionError {
1672}
1673
1674/// Error returned when failing to query the status of an item with a key that is not known to [`DropTracker`].
1675///
1676/// See [`DropTracker::try_state`] for more information and examples.
1677#[derive(PartialEq, Eq, Debug)]
1678pub struct NotTrackedError;
1679
1680impl fmt::Display for NotTrackedError {
1681    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1682        fmt::Display::fmt("item is not tracked", f)
1683    }
1684}
1685
1686impl Error for NotTrackedError {
1687}
1688
1689/// Error returned when failing to assert that a set of items is all [alive](State::Alive).
1690///
1691/// See [`DropTracker::all_alive`] for more information and examples.
1692#[derive(PartialEq, Eq, Debug)]
1693pub struct NotAllAliveError<K> {
1694    /// Sequence of keys that were expected to be alive, but were dropped.
1695    pub dropped: Vec<K>,
1696    /// Sequence of keys that were expected to be alive, but are not tracked by the
1697    /// [`DropTracker`].
1698    pub untracked: Vec<K>,
1699}
1700
1701impl<K: fmt::Debug> fmt::Display for NotAllAliveError<K> {
1702    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1703        write!(f, "not all items are alive: ")?;
1704        if !self.dropped.is_empty() {
1705            write!(f, "dropped: {:?}", &self.dropped)?;
1706        }
1707        if !self.untracked.is_empty() {
1708            if !self.dropped.is_empty() {
1709                write!(f, ", ")?;
1710            }
1711            write!(f, "not tracked: {:?}", &self.untracked)?;
1712        }
1713        Ok(())
1714    }
1715}
1716
1717impl<K: fmt::Debug> Error for NotAllAliveError<K> {
1718}
1719
1720/// Error returned when failing to assert that a set of items is all [dropped](State::Dropped).
1721///
1722/// See [`DropTracker::all_dropped`] for more information and examples.
1723#[derive(PartialEq, Eq, Debug)]
1724pub struct NotAllDroppedError<K> {
1725    /// Sequence of keys that were expected to be dropped, but are alive.
1726    pub alive: Vec<K>,
1727    /// Sequence of keys that were expected to be dropped, but are not tracked by the
1728    /// [`DropTracker`].
1729    pub untracked: Vec<K>,
1730}
1731
1732impl<K: fmt::Debug> fmt::Display for NotAllDroppedError<K> {
1733    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1734        write!(f, "not all items are dropped: ")?;
1735        if !self.alive.is_empty() {
1736            write!(f, "alive: {:?}", &self.alive)?;
1737        }
1738        if !self.untracked.is_empty() {
1739            if !self.alive.is_empty() {
1740                write!(f, ", ")?;
1741            }
1742            write!(f, "not tracked: {:?}", &self.untracked)?;
1743        }
1744        Ok(())
1745    }
1746}
1747
1748impl<K: fmt::Debug> Error for NotAllDroppedError<K> {
1749}
1750
1751/// Error returned when failing to assert that all tracked items are [dropped](State::Dropped).
1752///
1753/// See [`DropTracker::fully_dropped`] for more information and examples.
1754#[derive(PartialEq, Eq, Debug)]
1755pub struct SomeAliveError<'a, K> {
1756    /// Reference to the first key that was found [alive](State::Alive).
1757    pub alive: &'a K,
1758}
1759
1760impl<'a, K: fmt::Debug> fmt::Display for SomeAliveError<'a, K> {
1761    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1762        write!(f, "item is alive: {:?}", self.alive)
1763    }
1764}
1765
1766impl<'a, K: fmt::Debug> Error for SomeAliveError<'a, K> {
1767}
1768
1769/// Error returned when failing to assert that all tracked items are [alive](State::Alive).
1770///
1771/// See [`DropTracker::fully_alive`] for more information and examples.
1772#[derive(PartialEq, Eq, Debug)]
1773pub struct SomeDroppedError<'a, K> {
1774    /// Reference to the first key that was found to have been be [dropped](State::Dropped).
1775    pub dropped: &'a K,
1776}
1777
1778impl<'a, K: fmt::Debug> fmt::Display for SomeDroppedError<'a, K> {
1779    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1780        write!(f, "item is dropped: {:?}", self.dropped)
1781    }
1782}
1783
1784impl<'a, K: fmt::Debug> Error for SomeDroppedError<'a, K> {
1785}