cdk_common/pub_sub/
index.rs

1use std::fmt::Debug;
2use std::ops::Deref;
3use std::sync::atomic::{AtomicUsize, Ordering};
4
5use super::SubId;
6
7/// Indexable trait
8pub trait Indexable {
9    /// The type of the index, it is unknown and it is up to the Manager's
10    /// generic type
11    type Type: PartialOrd + Ord + Send + Sync + Debug;
12
13    /// To indexes
14    fn to_indexes(&self) -> Vec<Index<Self::Type>>;
15}
16
17#[derive(Debug, Ord, PartialOrd, PartialEq, Eq, Clone)]
18/// Index
19///
20/// The Index is a sorted structure that is used to quickly find matches
21///
22/// The counter is used to make sure each Index is unique, even if the prefix
23/// are the same, and also to make sure that earlier indexes matches first
24pub struct Index<T>
25where
26    T: PartialOrd + Ord + Send + Sync + Debug,
27{
28    prefix: T,
29    counter: SubscriptionGlobalId,
30    id: super::SubId,
31}
32
33impl<T> From<&Index<T>> for super::SubId
34where
35    T: PartialOrd + Ord + Send + Sync + Debug,
36{
37    fn from(val: &Index<T>) -> Self {
38        val.id.clone()
39    }
40}
41
42impl<T> Deref for Index<T>
43where
44    T: PartialOrd + Ord + Send + Sync + Debug,
45{
46    type Target = T;
47
48    fn deref(&self) -> &Self::Target {
49        &self.prefix
50    }
51}
52
53impl<T> Index<T>
54where
55    T: PartialOrd + Ord + Send + Sync + Debug,
56{
57    /// Compare the
58    pub fn cmp_prefix(&self, other: &Index<T>) -> std::cmp::Ordering {
59        self.prefix.cmp(&other.prefix)
60    }
61
62    /// Returns a globally unique id for the Index
63    pub fn unique_id(&self) -> usize {
64        self.counter.0
65    }
66}
67
68impl<T> From<(T, SubId, SubscriptionGlobalId)> for Index<T>
69where
70    T: PartialOrd + Ord + Send + Sync + Debug,
71{
72    fn from((prefix, id, counter): (T, SubId, SubscriptionGlobalId)) -> Self {
73        Self {
74            prefix,
75            id,
76            counter,
77        }
78    }
79}
80
81impl<T> From<(T, SubId)> for Index<T>
82where
83    T: PartialOrd + Ord + Send + Sync + Debug,
84{
85    fn from((prefix, id): (T, SubId)) -> Self {
86        Self {
87            prefix,
88            id,
89            counter: Default::default(),
90        }
91    }
92}
93
94impl<T> From<T> for Index<T>
95where
96    T: PartialOrd + Ord + Send + Sync + Debug,
97{
98    fn from(prefix: T) -> Self {
99        Self {
100            prefix,
101            id: Default::default(),
102            counter: SubscriptionGlobalId(0),
103        }
104    }
105}
106
107static COUNTER: AtomicUsize = AtomicUsize::new(0);
108
109/// Dummy type
110///
111/// This is only use so each Index is unique, with the same prefix.
112///
113/// The prefix is used to leverage the BTree to find things quickly, but each
114/// entry/key must be unique, so we use this dummy type to make sure each Index
115/// is unique.
116///
117/// Unique is also used to make sure that the indexes are sorted by creation order
118#[derive(Debug, Ord, PartialOrd, PartialEq, Eq, Clone, Copy)]
119pub struct SubscriptionGlobalId(usize);
120
121impl Default for SubscriptionGlobalId {
122    fn default() -> Self {
123        Self(COUNTER.fetch_add(1, Ordering::Relaxed))
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130
131    #[test]
132    fn test_index_from_tuple() {
133        let sub_id = SubId::from("test_sub_id");
134        let prefix = "test_prefix";
135        let index: Index<&str> = Index::from((prefix, sub_id.clone()));
136        assert_eq!(index.prefix, "test_prefix");
137        assert_eq!(index.id, sub_id);
138    }
139
140    #[test]
141    fn test_index_cmp_prefix() {
142        let sub_id = SubId::from("test_sub_id");
143        let index1: Index<&str> = Index::from(("a", sub_id.clone()));
144        let index2: Index<&str> = Index::from(("b", sub_id.clone()));
145        assert_eq!(index1.cmp_prefix(&index2), std::cmp::Ordering::Less);
146    }
147
148    #[test]
149    fn test_sub_id_from_str() {
150        let sub_id = SubId::from("test_sub_id");
151        assert_eq!(sub_id.0, "test_sub_id");
152    }
153
154    #[test]
155    fn test_sub_id_deref() {
156        let sub_id = SubId::from("test_sub_id");
157        assert_eq!(&*sub_id, "test_sub_id");
158    }
159}