paxakos 0.13.0

Rust implementation of Paxos consensus algorithm
Documentation
use std::future::Future;
use std::ops::RangeBounds;

use num_traits::One;
use pin_project::pin_project;

use crate::Number;

pub fn usize_delta<N: Number>(minuend: N, subtrahend: N) -> usize {
    try_usize_delta(minuend, subtrahend)
        .unwrap_or_else(|| panic!("Out of usize range: {}", minuend - subtrahend))
}

pub fn try_usize_delta<N: Number>(minuend: N, subtrahend: N) -> Option<usize> {
    assert!(minuend >= subtrahend);

    std::convert::TryInto::<usize>::try_into(minuend - subtrahend).ok()
}

pub fn usize_remainder<N: Number>(dividend: N, divisor: N) -> usize {
    try_usize_remainder(dividend, divisor)
        .unwrap_or_else(|| panic!("Out of usize range: {}", dividend % divisor))
}

pub fn try_usize_remainder<N: Number>(dividend: N, divisor: N) -> Option<usize> {
    std::convert::TryInto::<usize>::try_into(dividend % divisor).ok()
}

pub fn from_usize<N: Number>(n: usize, quantity: &str) -> N {
    N::try_from(n).unwrap_or_else(|_| panic!("{quantity} out of range"))
}

#[pin_project]
pub struct Race<A, B, T>
where
    A: Future<Output = T>,
    B: Future<Output = T>,
{
    #[pin]
    first: A,
    #[pin]
    second: B,
}

impl<A, B, T> Race<A, B, T>
where
    A: Future<Output = T>,
    B: Future<Output = T>,
{
    pub fn between(first: A, second: B) -> Self {
        Race { first, second }
    }
}

impl<A, B, T> Future for Race<A, B, T>
where
    A: Future<Output = T>,
    B: Future<Output = T>,
{
    type Output = T;

    fn poll(
        self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Self::Output> {
        let this = self.project();

        match this.first.poll(cx) {
            std::task::Poll::Pending => this.second.poll(cx),
            ready => ready,
        }
    }
}

#[derive(Copy, Debug)]
pub struct PhantomSend<T>(std::marker::PhantomData<T>);

unsafe impl<T> Send for PhantomSend<T> {}

impl<T> PhantomSend<T> {
    pub fn new() -> Self {
        Self(std::marker::PhantomData)
    }
}

impl<T> Default for PhantomSend<T> {
    fn default() -> Self {
        Self(Default::default())
    }
}

impl<T> Clone for PhantomSend<T> {
    fn clone(&self) -> Self {
        Self(self.0)
    }
}

pub struct NumberIter<N: Number> {
    next: Option<N>,
    last: N,
}

impl<N: Number> NumberIter<N> {
    pub fn from_range<R: RangeBounds<N>>(range: R) -> Self {
        let next = match range.start_bound() {
            std::ops::Bound::Included(n) => Some(*n),
            std::ops::Bound::Excluded(n) => {
                if *n == N::min_value() {
                    None
                } else {
                    Some(*n - One::one())
                }
            }
            std::ops::Bound::Unbounded => Some(N::min_value()),
        };

        let last = match range.end_bound() {
            std::ops::Bound::Included(n) => Some(*n),
            std::ops::Bound::Excluded(n) => {
                if *n == N::min_value() {
                    None
                } else {
                    Some(*n - One::one())
                }
            }
            std::ops::Bound::Unbounded => Some(N::max_value()),
        };

        match (next, last) {
            (Some(n), Some(last)) if n <= last => NumberIter { next, last },
            _ => NumberIter {
                next: None,
                last: N::min_value(),
            },
        }
    }
}

impl<N: Number> std::iter::Iterator for NumberIter<N> {
    type Item = N;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(n) = self.next {
            if n == self.last {
                self.next = None;
            } else {
                self.next = Some(n + One::one());
            }

            Some(n)
        } else {
            None
        }
    }
}