sefer_region/handle.rs
1//! [`Handle`] — the typed, copyable reference to a value in a [`Region`].
2//!
3//! [`Region`]: crate::Region
4
5use core::marker::PhantomData;
6
7/// An opaque, copyable reference to a value stored in a [`Region`].
8///
9/// A handle wraps a `slotmap::DefaultKey` (an index plus a generation) and is
10/// `Copy` and unconditionally `Send + Sync` regardless of `T` — it owns no `T`,
11/// it only names one. The `PhantomData<fn() -> T>` keeps the handle *typed* (so
12/// a `Handle<A>` cannot be passed to a `Region<B>`) while staying covariant in
13/// `T` and free of any drop/auto-trait obligations.
14///
15/// [`Region`]: crate::Region
16pub struct Handle<T> {
17 /// Crate-visible so [`Region`](crate::Region) can build and read a handle,
18 /// never exposed publicly.
19 pub(crate) key: slotmap::DefaultKey,
20 _ty: PhantomData<fn() -> T>,
21}
22
23impl<T> Handle<T> {
24 /// Crate-internal constructor wrapping a raw slotmap key.
25 pub(crate) fn from_key(key: slotmap::DefaultKey) -> Self {
26 Self {
27 key,
28 _ty: PhantomData,
29 }
30 }
31}
32
33// Hand-written impls: a handle is "a slotmap key", so these must hold for
34// *every* `T`, not only `T: Clone`/`Eq`/… that `#[derive]` would (wrongly)
35// require. They delegate to the inner `key` and hold unconditionally in `T`.
36impl<T> Clone for Handle<T> {
37 fn clone(&self) -> Self {
38 *self
39 }
40}
41impl<T> Copy for Handle<T> {}
42impl<T> PartialEq for Handle<T> {
43 fn eq(&self, other: &Self) -> bool {
44 self.key == other.key
45 }
46}
47impl<T> Eq for Handle<T> {}
48impl<T> core::hash::Hash for Handle<T> {
49 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
50 self.key.hash(state);
51 }
52}
53impl<T> core::fmt::Debug for Handle<T> {
54 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
55 f.debug_struct("Handle").field("key", &self.key).finish()
56 }
57}