pub struct DropItem<V> { /* private fields */ }
Expand description
An item that will notify the parent DropTracker
once it gets dropped.
DropItem
instances are created by DropTracker::track
, DropTracker::track_with_value
,
and related functions. DropItem
instances may contain an “underlying value” that affects the
item behavior when used with standard traits. The underlying value is either:
- a clone of
key
when constructing an item usingtrack(key)
(implicit); or value
when constructing an item usingtrack_with_value(key, value)
(explicit).
To check whether an item is alive or has been dropped, use DropTracker::state
or see the
documentation for DropTracker
for alternatives.
§Coercing and borrowing
DropItem
instances may be coerced and borrowed
as the the underlying value type. This means that, for example, if you create a DropItem
using track(String::from("abc"))
, you may call all of the String
methods on that item.
DropItem
also implements the standard traits PartialEq
,
Eq
, PartialOrd
, Ord
and
Hash
, Display
, Debug
if the
type of the underlying value implements them.
§Cloning
DropItem
does not implement the Clone
trait as it would introduce ambiguity with respect
to understanding whether the item has been dropped or is still alive when using
DropTracker::state
.
§Double drop
DropItem
instances can be dropped twice or more. Doing so will cause a panic, but will not
cause undefined behavior (unless you’re calling drop on an invalid memory location). The panic
on double drop is an useful feature to detect logic errors in destructors.
§Safety
Borrowing or performing operations on the underlying value of a DropItem
is generally safe
when using safe Rust code. However, DropItem
s are often used in unsafe code and are used to
detect potential bugs. In those circumstances, it is possible to trigger undefined behavior.
In particular, borrowing or performing operations on a DropItem
while another thread is
dropping will result in undefined behavior (although it must be noted that this is a bug in the
caller code and is not something that should happen in safe Rust code).
Only Drop
on a DropItem
is guaranteed to be safe in all circumstances.
§Examples
use drop_tracker::DropTracker;
let mut tracker = DropTracker::<u32>::new();
// Create an item using `123u32` as the key. Implicitly, this also sets its value to `123u32`
let item = tracker.track(123);
// Check that the item is alive
tracker.state(&123).alive().expect("item should be alive");
// Dereference the value of the item
assert_eq!(*item, 123);
assert!(!item.is_power_of_two());
// Drop the item and check that it really got dropped
drop(item);
tracker.state(&123).dropped().expect("item should be dropped");
// Create a new item, this time using an explicit `String` value
let abc_item = tracker.track_with_value(111, String::from("abc"));
// Comparison with other items using `String` work using the underlying `String`
// operations
assert_eq!(abc_item, tracker.track_with_value(222, String::from("abc")));
assert_ne!(abc_item, tracker.track_with_value(333, String::from("def")));
assert!(abc_item < tracker.track_with_value(444, String::from("def")));
// Display, debug and hashing also work using the underlying `String` operations
assert_eq!(format!("{}", abc_item), "abc");
assert_eq!(format!("{:?}", abc_item), "DropItem { value: \"abc\", state: Alive }");
use std::collections::hash_map::DefaultHasher;
use std::hash::Hash;
use std::hash::Hasher;
fn hash<T: Hash + ?Sized>(x: &T) -> u64 {
let mut hasher = DefaultHasher::new();
x.hash(&mut hasher);
hasher.finish()
}
assert_eq!(hash(&abc_item), hash(&"abc"));
// Methods on `String` can be called transparently on items
assert_eq!(abc_item.to_ascii_uppercase(), "ABC");
Using hashable items in a set, with an implicit underlying value:
use drop_tracker::DropTracker;
use std::collections::HashSet;
let mut tracker = DropTracker::new();
let mut set = HashSet::from([
tracker.track(1),
tracker.track(2),
tracker.track(3),
]);
set.remove(&3);
tracker.state(&1).alive().expect("first item should be alive");
tracker.state(&2).alive().expect("second item should be alive");
tracker.state(&3).dropped().expect("third item should be dropped");
Using hashable items in a set, with an explicit underlying value:
use drop_tracker::DropTracker;
use std::collections::HashSet;
let mut tracker = DropTracker::new();
let mut set = HashSet::from([
tracker.track_with_value(1, String::from("first")),
tracker.track_with_value(2, String::from("second")),
tracker.track_with_value(3, String::from("third")),
]);
set.remove("third");
tracker.state(&1).alive().expect("first item should be alive");
tracker.state(&2).alive().expect("second item should be alive");
tracker.state(&3).dropped().expect("third item should be dropped");