//! WS Index //! //! use std::fmt::Debug; use std::ops::Deref; use std::sync::atomic::{AtomicUsize, Ordering}; use super::SubId; /// Indexable trait pub trait Indexable { /// The type of the index, it is unknown and it is up to the Manager's /// generic type type Type: PartialOrd + Ord + Send + Sync + Debug; /// To indexes fn to_indexes(&self) -> Vec>; } #[derive(Debug, Ord, PartialOrd, PartialEq, Eq, Clone)] /// Index /// /// The Index is a sorted structure that is used to quickly find matches /// /// The counter is used to make sure each Index is unique, even if the prefix /// are the same, and also to make sure that earlier indexes matches first pub struct Index where T: PartialOrd + Ord + Send + Sync + Debug, { prefix: T, counter: SubscriptionGlobalId, id: super::SubId, } impl From<&Index> for super::SubId where T: PartialOrd + Ord + Send + Sync + Debug, { fn from(val: &Index) -> Self { val.id.clone() } } impl Deref for Index where T: PartialOrd + Ord + Send + Sync + Debug, { type Target = T; fn deref(&self) -> &Self::Target { &self.prefix } } impl Index where T: PartialOrd + Ord + Send + Sync + Debug, { /// Compare the pub fn cmp_prefix(&self, other: &Index) -> std::cmp::Ordering { self.prefix.cmp(&other.prefix) } /// Returns a globally unique id for the Index pub fn unique_id(&self) -> usize { self.counter.0 } } impl From<(T, SubId, SubscriptionGlobalId)> for Index where T: PartialOrd + Ord + Send + Sync + Debug, { fn from((prefix, id, counter): (T, SubId, SubscriptionGlobalId)) -> Self { Self { prefix, id, counter, } } } impl From<(T, SubId)> for Index where T: PartialOrd + Ord + Send + Sync + Debug, { fn from((prefix, id): (T, SubId)) -> Self { Self { prefix, id, counter: Default::default(), } } } impl From for Index where T: PartialOrd + Ord + Send + Sync + Debug, { fn from(prefix: T) -> Self { Self { prefix, id: Default::default(), counter: SubscriptionGlobalId(0), } } } static COUNTER: AtomicUsize = AtomicUsize::new(0); /// Dummy type /// /// This is only use so each Index is unique, with the same prefix. /// /// The prefix is used to leverage the BTree to find things quickly, but each /// entry/key must be unique, so we use this dummy type to make sure each Index /// is unique. /// /// Unique is also used to make sure that the indexes are sorted by creation order #[derive(Debug, Ord, PartialOrd, PartialEq, Eq, Clone, Copy)] pub struct SubscriptionGlobalId(usize); impl Default for SubscriptionGlobalId { fn default() -> Self { Self(COUNTER.fetch_add(1, Ordering::Relaxed)) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_index_from_tuple() { let sub_id = SubId::from("test_sub_id"); let prefix = "test_prefix"; let index: Index<&str> = Index::from((prefix, sub_id.clone())); assert_eq!(index.prefix, "test_prefix"); assert_eq!(index.id, sub_id); } #[test] fn test_index_cmp_prefix() { let sub_id = SubId::from("test_sub_id"); let index1: Index<&str> = Index::from(("a", sub_id.clone())); let index2: Index<&str> = Index::from(("b", sub_id.clone())); assert_eq!(index1.cmp_prefix(&index2), std::cmp::Ordering::Less); } #[test] fn test_sub_id_from_str() { let sub_id = SubId::from("test_sub_id"); assert_eq!(sub_id.0, "test_sub_id"); } #[test] fn test_sub_id_deref() { let sub_id = SubId::from("test_sub_id"); assert_eq!(&*sub_id, "test_sub_id"); } }