use std::{collections::HashMap, fmt::Debug, num::NonZeroU16};
use zenoh_config::TransportWeight;
use zenoh_protocol::core::{Locator, WhatAmI, ZenohIdProto};
use zenoh_result::ZResult;
pub const PID: u64 = 1; pub const WAI: u64 = 1 << 1; pub const LOC: u64 = 1 << 2; pub const WGT: u64 = 1 << 3; pub const GWY: u64 = 1 << 4;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct LinkState {
pub(crate) psid: u64,
pub(crate) sn: u64,
pub(crate) zid: Option<ZenohIdProto>,
pub(crate) whatami: Option<WhatAmI>,
pub(crate) locators: Option<Vec<Locator>>,
pub(crate) links: Vec<u64>,
pub(crate) link_weights: Option<Vec<u16>>,
pub(crate) is_gateway: bool,
}
#[derive(Default, Copy, Clone, PartialEq, Eq)]
pub(crate) struct LinkEdgeWeight(pub(crate) Option<NonZeroU16>);
impl Debug for LinkEdgeWeight {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.0 {
Some(w) => w.fmt(f),
None => self.0.fmt(f),
}
}
}
impl LinkEdgeWeight {
const DEFAULT_LINK_WEIGHT: u16 = 100;
pub(crate) fn new(val: NonZeroU16) -> Self {
LinkEdgeWeight(Some(val))
}
pub(crate) fn from_raw(val: u16) -> Self {
LinkEdgeWeight(NonZeroU16::new(val))
}
pub(crate) fn value(&self) -> u16 {
match self.0 {
Some(v) => v.get(),
None => Self::DEFAULT_LINK_WEIGHT,
}
}
pub(crate) fn as_raw(&self) -> u16 {
match self.0 {
Some(v) => v.get(),
None => 0,
}
}
pub(crate) fn is_set(&self) -> bool {
self.0.is_some()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct LocalLinkState {
pub(crate) sn: u64,
pub(crate) zid: ZenohIdProto,
pub(crate) whatami: WhatAmI,
pub(crate) locators: Option<Vec<Locator>>,
pub(crate) links: HashMap<ZenohIdProto, LinkEdgeWeight>,
pub(crate) is_gateway: bool,
}
impl LinkState {
#[cfg(test)]
#[doc(hidden)]
#[allow(dead_code)]
pub fn rand() -> Self {
use rand::Rng;
const MIN: usize = 1;
const MAX: usize = 16;
let mut rng = rand::thread_rng();
let psid: u64 = rng.gen();
let sn: u64 = rng.gen();
let zid = if rng.gen_bool(0.5) {
Some(ZenohIdProto::default())
} else {
None
};
let whatami = if rng.gen_bool(0.5) {
Some(WhatAmI::rand())
} else {
None
};
let locators = if rng.gen_bool(0.5) {
let n = rng.gen_range(MIN..=MAX);
let locators = (0..n).map(|_| Locator::rand()).collect::<Vec<Locator>>();
Some(locators)
} else {
None
};
let n = rng.gen_range(MIN..=MAX);
let links = (0..n).map(|_| rng.gen()).collect::<Vec<u64>>();
let link_weights = if rng.gen_bool(0.5) {
let n = rng.gen_range(MIN..=MAX);
let weights = (0..n).map(|_| rng.gen()).collect::<Vec<u16>>();
Some(weights)
} else {
None
};
let is_gateway = rng.gen_bool(0.5);
Self {
psid,
sn,
zid,
whatami,
locators,
links,
link_weights,
is_gateway,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct LinkStateList {
pub(crate) link_states: Vec<LinkState>,
}
impl LinkStateList {
#[cfg(test)]
#[doc(hidden)]
#[allow(dead_code)]
pub fn rand() -> Self {
use rand::Rng;
const MIN: usize = 1;
const MAX: usize = 16;
let mut rng = rand::thread_rng();
let n = rng.gen_range(MIN..=MAX);
let link_states = (0..n)
.map(|_| LinkState::rand())
.collect::<Vec<LinkState>>();
Self { link_states }
}
}
pub(crate) fn link_weights_from_config(
link_weights: Vec<TransportWeight>,
network_name: &str,
) -> ZResult<HashMap<ZenohIdProto, LinkEdgeWeight>> {
let mut link_weights_by_zid = HashMap::new();
for lw in link_weights {
if link_weights_by_zid
.insert(lw.dst_zid.into(), LinkEdgeWeight::new(lw.weight))
.is_some()
{
bail!(
"{} config contains a duplicate zid value for transport weight: {}",
network_name,
lw.dst_zid
);
}
}
Ok(link_weights_by_zid)
}
impl From<LinkEdgeWeight> for Option<u16> {
fn from(value: LinkEdgeWeight) -> Self {
value.is_set().then_some(value.value())
}
}
#[derive(PartialEq, Debug, serde::Serialize)]
pub(crate) struct LinkInfo {
pub(crate) src_weight: Option<u16>,
pub(crate) dst_weight: Option<u16>,
pub(crate) actual_weight: u16,
}