cdk_common/pub_sub/
index.rs

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