use std::ops::{Deref, RangeFull};
use crate::{
common::{ReplicaId, SigningKey, VerifyingKey, ViewNumber},
facade::{self, Receiver, Transport},
};
pub struct Config<T: Transport> {
inner: ConfigInner<T>,
verifying_key: Vec<(T::Address, VerifyingKey)>,
}
enum ConfigInner<T: Transport> {
Shard(facade::Config<T>, usize),
Global(facade::Config<T>),
}
impl<T: Transport> Clone for Config<T> {
fn clone(&self) -> Self {
Self {
inner: match &self.inner {
ConfigInner::Shard(config, group_id) => {
ConfigInner::Shard(config.clone(), *group_id)
}
ConfigInner::Global(config) => ConfigInner::Global(config.clone()),
},
verifying_key: self.verifying_key.clone(),
}
}
}
impl<T: Transport> Config<T> {
pub fn for_shard(config: facade::Config<T>, group_id: usize) -> Self {
if config.group.is_empty() {
assert_eq!(group_id, 0);
}
Self {
verifying_key: config
.signing_key
.iter()
.map(|(address, key)| (address.clone(), key.verifying_key()))
.collect(),
inner: ConfigInner::Shard(config, group_id),
}
}
pub fn for_global(config: facade::Config<T>) -> Self {
Self {
verifying_key: config
.signing_key
.iter()
.map(|(address, key)| (address.clone(), key.verifying_key()))
.collect(),
inner: ConfigInner::Global(config),
}
}
pub fn signing_key(&self, receiver: &impl Receiver<T>) -> &SigningKey {
&match &self.inner {
ConfigInner::Shard(config, _) => config,
ConfigInner::Global(config) => config,
}
.signing_key
.iter()
.find(|(address, _)| address == receiver.get_address())
.unwrap()
.1
}
pub fn verifying_key(&self, remote: &T::Address) -> Option<&VerifyingKey> {
self.verifying_key
.iter()
.find(|(address, _)| address == remote)
.map(|(_, key)| key)
}
pub fn replica<I: ReplicaIndex<T>>(&self, at: I) -> &I::Output {
I::index(
match &self.inner {
ConfigInner::Shard(config, group_id) => {
&config.replica[config
.group
.get(*group_id)
.cloned()
.unwrap_or(0..config.replica.len())]
}
ConfigInner::Global(config) => &*config.replica,
},
at,
)
}
pub fn view_primary(&self, view_number: ViewNumber) -> ReplicaId {
(view_number as usize % self.replica(..).len()) as _
}
}
impl<T: Transport> Deref for Config<T> {
type Target = facade::Config<T>;
fn deref(&self) -> &Self::Target {
match &self.inner {
ConfigInner::Shard(config, _) => config,
ConfigInner::Global(config) => config,
}
}
}
pub trait ReplicaIndex<T: Transport> {
type Output: ?Sized;
fn index(replica: &[T::Address], at: Self) -> &Self::Output;
}
impl<T: Transport> ReplicaIndex<T> for ReplicaId {
type Output = T::Address;
fn index(replica: &[T::Address], at: Self) -> &Self::Output {
&replica[at as usize]
}
}
impl<T: Transport> ReplicaIndex<T> for RangeFull {
type Output = [T::Address];
fn index(replica: &[T::Address], _at: Self) -> &Self::Output {
replica
}
}