Skip to main content

rig_core/effect/
key.rs

1//! A family-typed handler key. A `Key<F>` is a
2//! [`HandlerKey`] plus a proof, at the type level, of the family the
3//! handler under it serves; it holds no reference to a dispatcher.
4//!
5//! ```
6//! use rig_core::effect::{Key, family};
7//!
8//! let key = Key::<family::Completion>::new_unchecked("model".into());
9//! assert_eq!(key.as_str(), "model");
10//! ```
11
12use std::{fmt, hash::Hash, marker::PhantomData};
13
14use serde::{Deserialize, Serialize};
15
16use super::{Family, HandlerKey};
17
18/// A handler key tagged with its effect family. Serializes as the underlying
19/// string without the family tag. Deserialization and [`Self::new_unchecked`]
20/// do not validate a registration; hosts must ensure the key serves `F`.
21/// Implements `Send + Sync` independently of `F`.
22#[derive(Serialize, Deserialize)]
23#[serde(transparent, bound = "")]
24pub struct Key<F: Family> {
25    raw: HandlerKey,
26    #[serde(skip)]
27    _family: PhantomData<fn() -> F>,
28}
29
30impl<F: Family> Key<F> {
31    /// Assert that `raw` serves `F`. The one place a family is asserted
32    /// rather than proven: for a host that registered the handler itself
33    /// and knows what it serves. A wrong assertion fails at bind time
34    /// (`HandlerUnavailable`) or at the first dispatch, not silently.
35    pub const fn new_unchecked(raw: HandlerKey) -> Self {
36        Self {
37            raw,
38            _family: PhantomData,
39        }
40    }
41
42    /// The wire key.
43    pub const fn raw(&self) -> &HandlerKey {
44        &self.raw
45    }
46
47    /// The wire key, by value.
48    pub fn into_raw(self) -> HandlerKey {
49        self.raw
50    }
51
52    /// The key as a string.
53    pub fn as_str(&self) -> &str {
54        self.raw.as_str()
55    }
56}
57
58impl<F: Family> From<Key<F>> for HandlerKey {
59    fn from(key: Key<F>) -> Self {
60        key.raw
61    }
62}
63
64impl<F: Family> AsRef<HandlerKey> for Key<F> {
65    fn as_ref(&self) -> &HandlerKey {
66        &self.raw
67    }
68}
69
70// Written by hand: a derive would demand `F: Clone` and friends.
71impl<F: Family> Clone for Key<F> {
72    fn clone(&self) -> Self {
73        Self::new_unchecked(self.raw.clone())
74    }
75}
76impl<F: Family> PartialEq for Key<F> {
77    fn eq(&self, other: &Self) -> bool {
78        self.raw == other.raw
79    }
80}
81impl<F: Family> Eq for Key<F> {}
82impl<F: Family> PartialOrd for Key<F> {
83    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
84        Some(self.cmp(other))
85    }
86}
87impl<F: Family> Ord for Key<F> {
88    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
89        self.raw.cmp(&other.raw)
90    }
91}
92impl<F: Family> Hash for Key<F> {
93    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
94        self.raw.hash(state);
95    }
96}
97impl<F: Family> fmt::Debug for Key<F> {
98    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99        write!(f, "Key<{}>({:?})", F::FAMILY, self.raw.as_str())
100    }
101}
102impl<F: Family> fmt::Display for Key<F> {
103    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104        fmt::Display::fmt(&self.raw, f)
105    }
106}
107
108// The phantom is `fn() -> F`, so the key crosses threads for every `F`.
109const _: () = {
110    const fn assert_send_sync<T: Send + Sync + 'static>() {}
111    assert_send_sync::<Key<super::family::Completion>>();
112};