#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GossipFanout {
Bounded(usize),
Sqrt,
Unbounded,
}
impl GossipFanout {
#[allow(
clippy::cast_precision_loss,
clippy::cast_sign_loss,
clippy::cast_possible_truncation
)]
pub fn resolve(&self, n: usize) -> usize {
match self {
GossipFanout::Bounded(k) => (*k).min(n),
GossipFanout::Sqrt => (n as f64).sqrt().floor() as usize,
GossipFanout::Unbounded => n,
}
}
pub fn default_for(n: usize) -> Self {
if n > 32 {
GossipFanout::Sqrt
} else {
GossipFanout::Unbounded
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bounded_capped_at_cluster_size() {
let f = GossipFanout::Bounded(5);
assert_eq!(f.resolve(1000), 5);
assert_eq!(f.resolve(3), 3);
}
#[test]
fn test_bounded_zero_cluster() {
let f = GossipFanout::Bounded(5);
assert_eq!(f.resolve(0), 0);
}
#[test]
fn test_sqrt_100_nodes() {
let f = GossipFanout::Sqrt;
assert_eq!(f.resolve(100), 10);
}
#[test]
fn test_sqrt_1000_nodes() {
let f = GossipFanout::Sqrt;
assert_eq!(f.resolve(1000), 31);
}
#[test]
fn test_sqrt_zero() {
let f = GossipFanout::Sqrt;
assert_eq!(f.resolve(0), 0);
}
#[test]
fn test_unbounded_returns_n() {
let f = GossipFanout::Unbounded;
assert_eq!(f.resolve(8), 8);
assert_eq!(f.resolve(1000), 1000);
}
#[test]
fn test_default_for_small_cluster() {
assert_eq!(GossipFanout::default_for(10), GossipFanout::Unbounded);
assert_eq!(GossipFanout::default_for(32), GossipFanout::Unbounded);
}
#[test]
fn test_default_for_large_cluster() {
assert_eq!(GossipFanout::default_for(33), GossipFanout::Sqrt);
assert_eq!(GossipFanout::default_for(1000), GossipFanout::Sqrt);
}
#[test]
fn test_eq_and_copy() {
let a = GossipFanout::Bounded(3);
let b = a;
assert_eq!(a, b);
}
}