use std::cmp::Ordering;
use std::sync::atomic::{self, AtomicUsize};
pub(crate) struct NameServerStats {
successes: AtomicUsize,
failures: AtomicUsize,
}
impl Default for NameServerStats {
fn default() -> Self {
Self::new(0, 0)
}
}
impl NameServerStats {
pub(crate) fn new(successes: usize, failures: usize) -> Self {
Self {
successes: AtomicUsize::new(successes),
failures: AtomicUsize::new(failures),
}
}
pub(crate) fn next_success(&self) {
self.successes.fetch_add(1, atomic::Ordering::Release);
}
pub(crate) fn next_failure(&self) {
self.failures.fetch_add(1, atomic::Ordering::Release);
}
fn noload_eq(
self_successes: usize,
other_successes: usize,
self_failures: usize,
other_failures: usize,
) -> bool {
self_successes == other_successes && self_failures == other_failures
}
}
impl PartialEq for NameServerStats {
fn eq(&self, other: &Self) -> bool {
let self_successes = self.successes.load(atomic::Ordering::Acquire);
let other_successes = other.successes.load(atomic::Ordering::Acquire);
let self_failures = self.failures.load(atomic::Ordering::Acquire);
let other_failures = other.failures.load(atomic::Ordering::Acquire);
Self::noload_eq(
self_successes,
other_successes,
self_failures,
other_failures,
)
}
}
impl Eq for NameServerStats {}
impl Ord for NameServerStats {
fn cmp(&self, other: &Self) -> Ordering {
let self_successes = self.successes.load(atomic::Ordering::Acquire);
let other_successes = other.successes.load(atomic::Ordering::Acquire);
let self_failures = self.failures.load(atomic::Ordering::Acquire);
let other_failures = other.failures.load(atomic::Ordering::Acquire);
if Self::noload_eq(
self_successes,
other_successes,
self_failures,
other_failures,
) {
return Ordering::Equal;
}
if self_failures <= other_failures {
return Ordering::Greater;
}
self_successes.cmp(&other_successes)
}
}
impl PartialOrd for NameServerStats {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[cfg(test)]
mod tests {
use super::*;
fn is_send_sync<S: Sync + Send>() -> bool {
true
}
#[test]
fn stats_are_sync() {
assert!(is_send_sync::<NameServerStats>());
}
#[test]
fn test_state_cmp() {
let nil = NameServerStats::new(0, 0);
let successes = NameServerStats::new(1, 0);
let failures = NameServerStats::new(0, 1);
assert_eq!(nil.cmp(&nil), Ordering::Equal);
assert_eq!(nil.cmp(&successes), Ordering::Greater);
assert_eq!(successes.cmp(&failures), Ordering::Greater);
}
}