Skip to main content

rig_core/effect/
key.rs

1//! A family-typed handler key: vocabulary, not runtime. 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    #[track_caller]
36    pub const fn new_unchecked(raw: HandlerKey) -> Self {
37        Self {
38            raw,
39            _family: PhantomData,
40        }
41    }
42
43    /// The wire key.
44    pub const fn raw(&self) -> &HandlerKey {
45        &self.raw
46    }
47
48    /// The wire key, by value.
49    pub fn into_raw(self) -> HandlerKey {
50        self.raw
51    }
52
53    /// The key as a string.
54    pub fn as_str(&self) -> &str {
55        self.raw.as_str()
56    }
57}
58
59impl<F: Family> From<Key<F>> for HandlerKey {
60    fn from(key: Key<F>) -> Self {
61        key.raw
62    }
63}
64
65impl<F: Family> AsRef<HandlerKey> for Key<F> {
66    fn as_ref(&self) -> &HandlerKey {
67        &self.raw
68    }
69}
70
71// Written by hand: a derive would demand `F: Clone` and friends.
72impl<F: Family> Clone for Key<F> {
73    fn clone(&self) -> Self {
74        Self::new_unchecked(self.raw.clone())
75    }
76}
77impl<F: Family> PartialEq for Key<F> {
78    fn eq(&self, other: &Self) -> bool {
79        self.raw == other.raw
80    }
81}
82impl<F: Family> Eq for Key<F> {}
83impl<F: Family> PartialOrd for Key<F> {
84    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
85        Some(self.cmp(other))
86    }
87}
88impl<F: Family> Ord for Key<F> {
89    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
90        self.raw.cmp(&other.raw)
91    }
92}
93impl<F: Family> Hash for Key<F> {
94    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
95        self.raw.hash(state);
96    }
97}
98impl<F: Family> fmt::Debug for Key<F> {
99    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100        write!(f, "Key<{}>({:?})", F::FAMILY, self.raw.as_str())
101    }
102}
103impl<F: Family> fmt::Display for Key<F> {
104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105        fmt::Display::fmt(&self.raw, f)
106    }
107}
108
109// The phantom is `fn() -> F`, so the key crosses threads for every `F`.
110const _: () = {
111    const fn assert_send_sync<T: Send + Sync + 'static>() {}
112    assert_send_sync::<Key<super::family::Completion>>();
113};