use crate::pv::application::NodeTableResponseEntry;
use crate::pv::network::NodeAddress;
use crate::pv::{LongAddress, NodeID};
use schemars::{JsonSchema, Schema, SchemaGenerator};
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::borrow::Cow;
use std::collections::BTreeMap;
#[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct NodeTable(pub(crate) BTreeMap<NodeID, LongAddress>);
impl JsonSchema for NodeTable {
fn schema_name() -> Cow<'static, str> {
"NodeTable".into()
}
fn schema_id() -> Cow<'static, str> {
concat!(module_path!(), "::NodeTable").into()
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
schemars::json_schema!({
"type": "array",
"uniqueItems": true,
"items": gen.subschema_for::<NodeTableEntry>(),
})
}
}
#[derive(Debug, Clone, Eq, PartialEq, JsonSchema, Serialize, Deserialize)]
struct NodeTableEntry {
pub node_id: NodeID,
pub long_address: LongAddress,
}
impl From<(NodeID, LongAddress)> for NodeTableEntry {
fn from((node_id, long_address): (NodeID, LongAddress)) -> Self {
Self {
node_id,
long_address,
}
}
}
impl From<(&NodeID, &LongAddress)> for NodeTableEntry {
fn from((&node_id, &long_address): (&NodeID, &LongAddress)) -> Self {
Self {
node_id,
long_address,
}
}
}
impl From<NodeTableEntry> for (NodeID, LongAddress) {
fn from(value: NodeTableEntry) -> Self {
(value.node_id, value.long_address)
}
}
impl Serialize for NodeTable {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let entries: Vec<NodeTableEntry> = self.0.iter().map(NodeTableEntry::from).collect();
entries.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for NodeTable {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let entries = <Vec<NodeTableEntry>>::deserialize(deserializer)?;
let len = entries.len();
let output: Self = Self(
entries
.into_iter()
.map(<(NodeID, LongAddress)>::from)
.collect(),
);
if output.0.len() == len {
Ok(output)
} else {
Err(D::Error::custom(
"node_ids must be unique within a node table",
))
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct NodeTableBuilder {
expected_next: Option<NodeID>,
table: NodeTable,
}
impl NodeTableBuilder {
pub fn push(
&mut self,
start_address: NodeAddress,
entries: &[NodeTableResponseEntry],
) -> Option<NodeTable> {
if NodeAddress::from(self.expected_next) != start_address {
self.expected_next = Default::default();
self.table = Default::default();
if start_address == NodeAddress::ZERO {
return None;
}
}
for entry in entries {
let Ok(node_id) = entry.node_id.try_into() else {
self.expected_next = None;
return None;
};
self.table.0.insert(node_id, entry.long_address);
}
if entries.is_empty() {
let mut table = Default::default();
std::mem::swap(&mut self.table, &mut table);
self.expected_next = None;
Some(table)
} else {
let last = self.table.0.last_entry().unwrap();
self.expected_next = last.key().successor();
if self.expected_next.is_none() {
self.table = Default::default();
}
None
}
}
}