cdk_common/pub_sub/
index.rs

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