use std::collections::{BTreeMap, BTreeSet, HashMap};
use crate::{
network::Network,
ospf::OspfImpl,
types::{Prefix, RouterId, ASN},
};
#[cfg(feature = "rand")]
use rand::{prelude::*, rngs::StdRng};
pub trait RouteSampler {
fn sample<P: Prefix, Q, Ospf: OspfImpl>(
&mut self,
net: &Network<P, Q, Ospf>,
) -> impl IntoIterator<Item = (RouterId, usize)>;
}
impl RouteSampler for Vec<(RouterId, usize)> {
fn sample<P: Prefix, Q, Ospf: OspfImpl>(
&mut self,
_net: &Network<P, Q, Ospf>,
) -> impl IntoIterator<Item = (RouterId, usize)> {
self.iter().copied()
}
}
impl RouteSampler for &[(RouterId, usize)] {
fn sample<P: Prefix, Q, Ospf: OspfImpl>(
&mut self,
_net: &Network<P, Q, Ospf>,
) -> impl IntoIterator<Item = (RouterId, usize)> {
self.iter().copied()
}
}
impl RouteSampler for HashMap<RouterId, usize> {
fn sample<P: Prefix, Q, Ospf: OspfImpl>(
&mut self,
_net: &Network<P, Q, Ospf>,
) -> impl IntoIterator<Item = (RouterId, usize)> {
self.iter().map(|(r, l)| (*r, *l))
}
}
impl RouteSampler for BTreeMap<RouterId, usize> {
fn sample<P: Prefix, Q, Ospf: OspfImpl>(
&mut self,
_net: &Network<P, Q, Ospf>,
) -> impl IntoIterator<Item = (RouterId, usize)> {
self.iter().map(|(r, l)| (*r, *l))
}
}
#[derive(Clone, Debug, Default)]
pub struct EqualPreference {
int: BTreeSet<ASN>,
ext: Option<BTreeSet<ASN>>,
}
impl EqualPreference {
pub fn new() -> Self {
Self::default()
}
pub fn internal_asn(mut self, asn: impl Into<ASN>) -> Self {
self.int.insert(asn.into());
self
}
pub fn internal_asns(mut self, asns: impl IntoIterator<Item = ASN>) -> Self {
self.int.extend(asns);
self
}
pub fn external_asns(mut self, asns: impl IntoIterator<Item = ASN>) -> Self {
self.ext.get_or_insert_default().extend(asns);
self
}
}
impl RouteSampler for EqualPreference {
fn sample<P: Prefix, Q, Ospf: OspfImpl>(
&mut self,
net: &Network<P, Q, Ospf>,
) -> impl IntoIterator<Item = (RouterId, usize)> {
let ases = net.ases();
let ases: Vec<ASN> = if let Some(ext) = &self.ext {
ases.intersection(ext).copied().collect()
} else {
ases.into_iter()
.filter(|asn| !self.int.contains(asn))
.collect()
};
ases.into_iter()
.flat_map(|asn| net.routers_in_as(asn).map(|r| (r.router_id(), 0)))
}
}
#[derive(Clone, Debug, Default)]
pub struct UniquePreference {
int: BTreeSet<ASN>,
ext: Option<BTreeSet<ASN>>,
#[cfg(feature = "rand")]
rng: Option<StdRng>,
}
impl UniquePreference {
pub fn new() -> Self {
Self::default()
}
pub fn internal_asn(mut self, asn: impl Into<ASN>) -> Self {
self.int.insert(asn.into());
self
}
pub fn internal_asns(mut self, asns: impl IntoIterator<Item = ASN>) -> Self {
self.int.extend(asns);
self
}
pub fn external_asns(mut self, asns: impl IntoIterator<Item = ASN>) -> Self {
self.ext.get_or_insert_default().extend(asns);
self
}
#[cfg(feature = "rand")]
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
pub fn shuffle(mut self) -> Self {
if self.rng.is_none() {
self.rng = Some(StdRng::from_entropy());
}
self
}
#[cfg(feature = "rand")]
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
pub fn seeded(mut self, seed: u64) -> Self {
if self.rng.is_none() {
self.rng = Some(StdRng::seed_from_u64(seed));
}
self
}
}
impl RouteSampler for UniquePreference {
fn sample<P: Prefix, Q, Ospf: OspfImpl>(
&mut self,
net: &Network<P, Q, Ospf>,
) -> impl IntoIterator<Item = (RouterId, usize)> {
let ases = net.ases();
#[allow(unused_mut)]
let mut ases: Vec<ASN> = if let Some(ext) = &self.ext {
ases.intersection(ext).copied().collect()
} else {
ases.into_iter()
.filter(|asn| !self.int.contains(asn))
.collect()
};
#[cfg(feature = "rand")]
if let Some(rng) = self.rng.as_mut() {
ases.shuffle(rng);
}
ases.into_iter().enumerate().flat_map(|(path_len, asn)| {
net.routers_in_as(asn)
.map(move |r| (r.router_id(), path_len))
})
}
}
#[derive(Clone, Debug, Default)]
pub struct SingleBestOthersEqual {
int: BTreeSet<ASN>,
ext: Option<BTreeSet<ASN>>,
#[cfg(feature = "rand")]
rng: Option<StdRng>,
}
impl SingleBestOthersEqual {
pub fn new() -> Self {
Self::default()
}
pub fn internal_asn(mut self, asn: impl Into<ASN>) -> Self {
self.int.insert(asn.into());
self
}
pub fn internal_asns(mut self, asns: impl IntoIterator<Item = ASN>) -> Self {
self.int.extend(asns);
self
}
pub fn external_asns(mut self, asns: impl IntoIterator<Item = ASN>) -> Self {
self.ext.get_or_insert_default().extend(asns);
self
}
#[cfg(feature = "rand")]
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
pub fn shuffle(mut self) -> Self {
if self.rng.is_none() {
self.rng = Some(StdRng::from_entropy());
}
self
}
#[cfg(feature = "rand")]
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
pub fn seeded(mut self, seed: u64) -> Self {
if self.rng.is_none() {
self.rng = Some(StdRng::seed_from_u64(seed));
}
self
}
}
impl RouteSampler for SingleBestOthersEqual {
fn sample<P: Prefix, Q, Ospf: OspfImpl>(
&mut self,
net: &Network<P, Q, Ospf>,
) -> impl IntoIterator<Item = (RouterId, usize)> {
let ases = net.ases();
#[allow(unused_mut)]
let mut ases: Vec<ASN> = if let Some(ext) = &self.ext {
ases.intersection(ext).copied().collect()
} else {
ases.into_iter()
.filter(|asn| !self.int.contains(asn))
.collect()
};
#[cfg(feature = "rand")]
if let Some(rng) = self.rng.as_mut() {
ases.shuffle(rng);
}
ases.into_iter().enumerate().flat_map(|(path_len, asn)| {
net.routers_in_as(asn)
.map(move |r| (r.router_id(), if path_len == 0 { 0 } else { 2 }))
})
}
}