#![allow(dead_code)]
use rand::RngExt;
use rand::rng;
use std::cmp::Ordering;
use std::fmt::Debug;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub(crate) struct PowerOfTwoSelector;
impl PowerOfTwoSelector {
pub(crate) fn new() -> Self {
Self
}
pub(crate) fn select_with_rng<T, S, F, R>(
&self,
candidates: &[T],
mut score_lookup: F,
rng: &mut R,
) -> Option<usize>
where
F: FnMut(&T) -> S,
S: PartialOrd,
R: RngExt + ?Sized,
{
if candidates.is_empty() {
return None;
}
if candidates.len() == 1 {
return Some(0);
}
let total_candidates = candidates.len();
let first_index = rng.random_range(0..total_candidates);
let mut second_index = rng.random_range(0..total_candidates - 1);
if second_index >= first_index {
second_index += 1;
}
let first_score = score_lookup(&candidates[first_index]);
let second_score = score_lookup(&candidates[second_index]);
let is_first_preferred = match first_score.partial_cmp(&second_score) {
Some(Ordering::Less | Ordering::Equal) => true,
Some(Ordering::Greater) => false,
None => first_score.partial_cmp(&first_score).is_some(),
};
if is_first_preferred {
return Some(first_index);
}
Some(second_index)
}
pub(crate) fn select_index<T, S, F>(&self, candidates: &[T], score_lookup: F) -> Option<usize>
where
F: FnMut(&T) -> S,
S: PartialOrd,
{
let mut local_rng = rng();
self.select_with_rng(candidates, score_lookup, &mut local_rng)
}
pub(crate) fn select<'a, T, S, F>(&self, candidates: &'a [T], score_lookup: F) -> Option<&'a T>
where
F: FnMut(&T) -> S,
S: PartialOrd,
{
let selected_index = self.select_index(candidates, score_lookup)?;
candidates.get(selected_index)
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::SeedableRng;
use rand::rngs::SmallRng;
use std::collections::HashMap;
#[test]
fn traits() {
static_assertions::assert_impl_all!(
PowerOfTwoSelector: Send,
Sync,
Debug,
Clone,
Copy,
PartialEq,
Eq,
Default
);
let selector: PowerOfTwoSelector = Default::default();
let cloned_selector = selector;
assert_eq!(
selector, cloned_selector,
"selector must equal its copy/clone"
);
}
#[test]
fn empty_candidates_returns_none() {
let selector = PowerOfTwoSelector::new();
let candidates: [String; 0] = [];
let selected_index = selector.select_index(&candidates, |_| 10.0);
assert_eq!(
selected_index, None,
"empty candidate slice must return None for select_index"
);
let selected_ref = selector.select(&candidates, |_| 10.0);
assert_eq!(
selected_ref, None,
"empty candidate slice must return None for select"
);
}
#[test]
fn single_candidate_returns_first() {
let selector = PowerOfTwoSelector::new();
let candidates = vec!["10.0.0.1:15000"];
let mut lookup_invoked = false;
let selected_index = selector.select_index(&candidates, |_| {
lookup_invoked = true;
50.0
});
assert_eq!(
selected_index,
Some(0),
"single candidate must return index 0"
);
assert!(
!lookup_invoked,
"score lookup must not be called when only 1 candidate exists"
);
let selected_ref = selector.select(&candidates, |_| 50.0);
assert_eq!(
selected_ref,
Some(&"10.0.0.1:15000"),
"single candidate must return reference to element 0"
);
}
#[test]
fn two_candidates_picks_lower_score() {
let selector = PowerOfTwoSelector::new();
let candidates = vec!["fast_endpoint", "slow_endpoint"];
let score_map: HashMap<&str, f64> = [("fast_endpoint", 10.0), ("slow_endpoint", 100.0)]
.into_iter()
.collect();
for _ in 0..50 {
let selected = selector.select(&candidates, |candidate| {
*score_map
.get(candidate)
.expect("candidate score must exist in map")
});
assert_eq!(
selected,
Some(&"fast_endpoint"),
"fast endpoint with lower score must be selected"
);
}
}
#[test]
fn integer_and_tuple_multi_criteria_scoring() {
let selector = PowerOfTwoSelector::new();
struct Node {
name: &'static str,
distance: u32,
active_requests: usize,
}
let candidates = vec![
Node {
name: "local_idle",
distance: 0,
active_requests: 0,
},
Node {
name: "local_busy",
distance: 0,
active_requests: 5,
},
Node {
name: "remote_idle",
distance: 1,
active_requests: 0,
},
];
for _ in 0..20 {
let selected = selector
.select(&candidates, |node| (node.distance, node.active_requests))
.expect("selection succeeds");
assert_ne!(
selected.name, "remote_idle",
"remote node must not beat local nodes"
);
}
}
#[test]
fn nan_floating_point_score_handling() {
let selector = PowerOfTwoSelector::new();
let candidates = vec!["valid_score", "nan_score"];
for _ in 0..50 {
let selected = selector.select(&candidates, |candidate| match *candidate {
"valid_score" => 10.0,
"nan_score" => f64::NAN,
_ => unreachable!(),
});
assert_eq!(
selected,
Some(&"valid_score"),
"valid finite score must beat NaN score"
);
}
let nan_candidates = vec!["nan_1", "nan_2"];
let selected = selector.select(&nan_candidates, |_| f64::NAN);
assert!(
selected == Some(&"nan_1") || selected == Some(&"nan_2"),
"when both scores are NaN, selection must still return a valid candidate"
);
}
#[test]
fn tie_breaking_picks_sampled_candidate() {
let selector = PowerOfTwoSelector::new();
let candidates = vec!["endpoint_a", "endpoint_b"];
let selected = selector.select(&candidates, |_| 42.0);
assert!(
selected == Some(&"endpoint_a") || selected == Some(&"endpoint_b"),
"tie breaking must select one of the valid candidates"
);
}
#[test]
fn deterministic_seeded_rng_selection() {
let selector = PowerOfTwoSelector::new();
let candidates = vec!["endpoint_0", "endpoint_1", "endpoint_2", "endpoint_3"];
let scores = [100.0, 50.0, 80.0, 10.0];
let mut seeded_rng = SmallRng::seed_from_u64(12345);
let selected_index = selector
.select_with_rng(
&candidates,
|candidate| {
let index = candidates
.iter()
.position(|c| c == candidate)
.expect("candidate in list");
scores[index]
},
&mut seeded_rng,
)
.expect("selection must succeed");
assert!(
selected_index < candidates.len(),
"selected index must be valid"
);
}
#[test]
fn mutable_closure_score_lookup() {
let selector = PowerOfTwoSelector::new();
let candidates = vec!["endpoint_0", "endpoint_1", "endpoint_2"];
let mut lookup_count = 0usize;
let selected = selector.select(&candidates, |_| {
lookup_count += 1;
25.0
});
assert!(selected.is_some(), "selection must succeed");
assert_eq!(
lookup_count, 2,
"P2C must evaluate exactly 2 candidate scores for 3 candidates"
);
}
#[test]
fn distribution_across_multiple_replicas() {
let selector = PowerOfTwoSelector::new();
let candidates = vec!["node_0", "node_1", "node_2", "node_3"];
let scores = [10.0, 10.0, 20.0, 20.0];
let mut selection_counts = vec![0usize; candidates.len()];
let total_iterations = 10_000;
for _ in 0..total_iterations {
let selected_index = selector
.select_index(&candidates, |candidate| {
let index = candidates
.iter()
.position(|c| c == candidate)
.expect("candidate in list");
scores[index]
})
.expect("selection must succeed for non-empty list");
selection_counts[selected_index] += 1;
}
assert!(
selection_counts[0] > selection_counts[2],
"low-score node_0 ({}) must be selected more often than higher-score node_2 ({})",
selection_counts[0],
selection_counts[2]
);
assert!(
selection_counts[1] > selection_counts[3],
"low-score node_1 ({}) must be selected more often than higher-score node_3 ({})",
selection_counts[1],
selection_counts[3]
);
for (index, count) in selection_counts.iter().enumerate() {
assert!(
*count > 0,
"node_{index} should receive at least some traffic under P2C"
);
}
}
}