use {
auto_impl::auto_impl,
hrw_hash::HrwNode,
parking_lot::RwLock,
std::{borrow::Borrow, collections::HashMap, fmt, hash::Hash, ops::Deref, sync::Arc},
};
#[auto_impl(&)]
pub trait KeyspaceNode: fmt::Debug + Hash + PartialEq + Eq {
type Id: fmt::Debug + Hash + PartialEq + Eq + Clone;
fn id(&self) -> &Self::Id;
fn capacity(&self) -> usize {
1
}
}
macro_rules! impl_keyspace_node {
($($t:ty),+) => {
$(
impl KeyspaceNode for $t {
type Id = $t;
fn id(&self) -> &Self::Id {
self
}
fn capacity(&self) -> usize {
1
}
}
)+
};
}
impl_keyspace_node!(String, &'static str, u8, u16, u32, u64, usize);
#[derive(Debug, Hash)]
pub struct NodeRef<N>(Option<Arc<N>>);
impl<N: KeyspaceNode> HrwNode for NodeRef<N> {
fn capacity(&self) -> usize {
match self.0.as_ref() {
Some(node) => node.capacity(),
None => 0,
}
}
}
impl<N> Default for NodeRef<N> {
fn default() -> Self {
Self(None)
}
}
impl<N: KeyspaceNode> Clone for NodeRef<N> {
fn clone(&self) -> Self {
match self.0.as_ref() {
Some(node) => NodeRef(Some(Arc::clone(node))),
None => NodeRef(None),
}
}
}
impl<N> From<N> for NodeRef<N> {
fn from(node: N) -> Self {
Self(Some(Arc::new(node)))
}
}
impl<N> Deref for NodeRef<N> {
type Target = Arc<N>;
fn deref(&self) -> &Self::Target {
self.0.as_ref().expect("Cannot deref an empty NodeRef")
}
}
impl<N> AsRef<N> for NodeRef<N> {
fn as_ref(&self) -> &N {
self.0.as_ref().expect("Cannot reference an empty NodeRef")
}
}
impl<N> Borrow<N> for NodeRef<N> {
fn borrow(&self) -> &N {
self.0.as_ref().expect("Cannot borrow from empty NodeRef")
}
}
impl<T: PartialEq> PartialEq for NodeRef<T> {
fn eq(&self, other: &Self) -> bool {
match (self.0.as_ref(), other.0.as_ref()) {
(Some(a), Some(b)) => a.as_ref() == b.as_ref(),
(None, None) => true,
_ => false,
}
}
}
impl<T: PartialEq> Eq for NodeRef<T> {}
impl<T: PartialEq> PartialEq<T> for NodeRef<T> {
fn eq(&self, other: &T) -> bool {
match self.0.as_ref() {
Some(node) => node.as_ref() == other,
None => false,
}
}
}
impl<T: PartialEq> PartialEq<Arc<T>> for NodeRef<T> {
fn eq(&self, other: &Arc<T>) -> bool {
match self.0.as_ref() {
Some(node) => node.as_ref() == other.as_ref(),
None => false,
}
}
}
impl<T: PartialEq> PartialEq<&T> for NodeRef<T> {
fn eq(&self, other: &&T) -> bool {
match self.0.as_ref() {
Some(node) => node.as_ref() == *other,
None => false,
}
}
}
impl PartialEq<&str> for NodeRef<String> {
fn eq(&self, other: &&str) -> bool {
match self.0.as_ref() {
Some(node) => node.as_str() == *other,
None => false,
}
}
}
impl<T: PartialEq> PartialEq<Vec<&T>> for NodeRef<Vec<T>> {
fn eq(&self, other: &Vec<&T>) -> bool {
match self.0.as_ref() {
Some(nodes) => nodes.iter().zip(other.iter()).all(|(a, b)| a == *b),
None => other.is_empty(),
}
}
}
impl PartialEq<Vec<&str>> for NodeRef<Vec<String>> {
fn eq(&self, other: &Vec<&str>) -> bool {
match self.0.as_ref() {
Some(nodes) => nodes
.iter()
.zip(other.iter())
.all(|(a, b)| a.as_str() == *b),
None => other.is_empty(),
}
}
}
impl<N: KeyspaceNode> NodeRef<N> {
pub fn new(node: N) -> Self {
Self(Some(Arc::new(node)))
}
pub fn inner(&self) -> &N {
self.0
.as_ref()
.expect("Cannot get inner node from an empty NodeRef")
}
}
#[derive(Debug, Clone)]
pub(crate) struct Nodes<N: KeyspaceNode>(Arc<RwLock<HashMap<N::Id, NodeRef<N>>>>);
impl<N: KeyspaceNode> Default for Nodes<N> {
fn default() -> Self {
Self::new()
}
}
#[allow(unused)]
impl<N: KeyspaceNode> Nodes<N> {
pub fn new() -> Self {
Self(Arc::new(RwLock::new(HashMap::new())))
}
pub fn from_iter<I>(nodes: I) -> Self
where
I: IntoIterator<Item = N>,
{
Self(Arc::new(RwLock::new(HashMap::from_iter(
nodes
.into_iter()
.map(|node| (node.id().clone(), NodeRef::new(node))),
))))
}
pub fn insert(&self, node: N) -> Option<NodeRef<N>> {
self.0.write().insert(node.id().clone(), NodeRef::new(node))
}
pub fn remove(&self, id: &N::Id) -> Option<NodeRef<N>> {
self.0.write().remove(id)
}
pub fn get(&self, id: N::Id) -> Option<NodeRef<N>> {
self.0.read().get(&id).and_then(|node| Some(node.clone()))
}
pub fn len(&self) -> usize {
self.0.read().len()
}
pub fn contains(&self, id: &N::Id) -> bool {
self.0.read().contains_key(id)
}
pub fn keys(&self) -> Vec<N::Id> {
self.0.read().keys().map(|key| key.clone()).collect()
}
pub fn values(&self) -> Vec<NodeRef<N>> {
self.0.read().values().cloned().collect()
}
}
#[cfg(test)]
mod tests {
use {
super::*,
std::{
net::{IpAddr, SocketAddr},
str::FromStr,
},
};
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
struct Node {
id: String,
addr: SocketAddr,
capacity: usize,
}
impl Node {
fn new(id: &str, ip: &str, port: u16, capacity: usize) -> Self {
let addr = SocketAddr::new(IpAddr::from_str(&ip).unwrap(), port);
Self {
id: id.to_string(),
addr,
capacity,
}
}
}
impl ToString for Node {
fn to_string(&self) -> String {
format!("{}|{}", self.addr, self.id)
}
}
impl KeyspaceNode for Node {
type Id = String;
fn id(&self) -> &Self::Id {
&self.id
}
fn capacity(&self) -> usize {
self.capacity
}
}
#[test]
fn basic_ops() {
let nodes = Nodes::new();
let node1 = Node::new("node1", "127.0.0.1", 2048, 10);
let res = nodes.insert(node1.clone());
assert!(res.is_none(), "Node should be inserted");
let res = nodes.insert(Node::new("node2", "127.0.0.1", 2049, 10));
assert!(res.is_none(), "Node should be inserted");
let res = nodes.insert(Node::new("node3", "127.0.0.1", 2050, 10));
assert!(res.is_none(), "Node should be inserted");
assert_eq!(nodes.len(), 3, "There should be 3 nodes");
assert!(nodes.keys().contains(&"node1".to_string()));
assert!(nodes.keys().contains(&"node2".to_string()));
assert!(nodes.keys().contains(&"node3".to_string()));
let node1a = Node::new("node1", "127.0.0.2", 2048, 10);
let res = nodes.insert(node1a.clone());
assert_eq!(res.unwrap(), node1);
assert!(nodes.contains(&node1a.id()));
}
}