#![forbid(unsafe_code)]
use futures::StreamExt as _;
use crate::mixnet::acquire::{TransportAcquirable, TransportError};
use crate::mixnet::pools::{Pools, ProvenBirth};
pub(crate) const QUARTET_SIZE: usize = 4;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub(crate) enum Role {
IndexerSweep,
PriceFetch,
IndexerClient,
Spare,
}
pub(crate) struct Quartet {
pub(crate) sweep: ProvenBirth,
pub(crate) price: ProvenBirth,
pub(crate) indexer: ProvenBirth,
pub(crate) spare: ProvenBirth,
}
pub(crate) async fn prove_quartet<A>(pools: &Pools, acquirer: &A) -> Result<Quartet, TransportError>
where
A: TransportAcquirable + ?Sized,
{
let mut acquisitions = (0..QUARTET_SIZE)
.map(|_| pools.acquire_proven(acquirer))
.collect::<futures::stream::FuturesUnordered<_>>();
let mut proven: Vec<ProvenBirth> = Vec::with_capacity(QUARTET_SIZE);
while let Some(outcome) = acquisitions.next().await {
match outcome {
Ok(birth) => proven.push(birth),
Err(refusal) => {
drop(acquisitions);
for birth in proven {
birth.transport.stop().await;
}
return Err(refusal);
}
}
}
let mut assigned = proven.into_iter();
let mut take = |role: Role| {
let birth = assigned.next().expect("every acquisition yielded a birth");
pools.assign_role(role, birth.lease.node().clone());
birth
};
Ok(Quartet {
sweep: take(Role::IndexerSweep),
price: take(Role::PriceFetch),
indexer: take(Role::IndexerClient),
spare: take(Role::Spare),
})
}