use std::fmt;
use std::marker::PhantomData;
use tokio::sync::mpsc;
use super::control_policy::{ControlAuthorizer, ControlGate, ControlPolicy};
use super::BACnetRouter;
use crate::layer::{
AdmissionReceiver, QueueAdmissionCounters, ReceivedApdu, ReceivedNetworkControl,
};
pub struct RouterOptions<
A = mpsc::Receiver<ReceivedApdu>,
C = mpsc::Receiver<ReceivedNetworkControl>,
> {
policy: ControlPolicy,
authorizer: Option<ControlAuthorizer>,
network_control: bool,
receivers: PhantomData<fn() -> (A, C)>,
}
impl RouterOptions {
pub fn new() -> Self {
Self {
policy: ControlPolicy::default(),
authorizer: None,
network_control: false,
receivers: PhantomData,
}
}
}
impl Default for RouterOptions {
fn default() -> Self {
Self::new()
}
}
impl<A, C> RouterOptions<A, C> {
pub fn track_admission(self) -> RouterOptions<AdmissionReceiver<ReceivedApdu>, C> {
self.receivers()
}
pub fn control_policy(mut self, policy: ControlPolicy) -> Self {
self.policy = policy;
self
}
pub fn control_authorizer(mut self, authorizer: ControlAuthorizer) -> Self {
self.authorizer = Some(authorizer);
self
}
pub fn network_control_receiver(
mut self,
) -> RouterOptions<A, mpsc::Receiver<ReceivedNetworkControl>> {
self.network_control = true;
self.receivers()
}
pub fn network_control_receiver_with_admission(
mut self,
) -> RouterOptions<A, AdmissionReceiver<ReceivedNetworkControl>> {
self.network_control = true;
self.receivers()
}
pub(super) fn control_gate(&self) -> ControlGate {
ControlGate::new(self.policy, self.authorizer.clone())
}
pub(super) fn wants_network_control(&self) -> bool {
self.network_control
}
fn receivers<A2, C2>(self) -> RouterOptions<A2, C2> {
RouterOptions {
policy: self.policy,
authorizer: self.authorizer,
network_control: self.network_control,
receivers: PhantomData,
}
}
}
impl<A, C> fmt::Debug for RouterOptions<A, C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RouterOptions")
.field("policy", &self.policy)
.field(
"authorizer",
&self.authorizer.as_ref().map(|_| "<callback>"),
)
.field("network_control", &self.network_control)
.field("apdus", &std::any::type_name::<A>())
.field("controls", &std::any::type_name::<C>())
.finish()
}
}
pub struct StartedRouter<
A = mpsc::Receiver<ReceivedApdu>,
C = mpsc::Receiver<ReceivedNetworkControl>,
> {
pub router: BACnetRouter,
pub apdus: A,
pub network_control: Option<C>,
}
pub trait LocalApduReceiver: sealed::Sealed<ReceivedApdu> {}
impl LocalApduReceiver for mpsc::Receiver<ReceivedApdu> {}
impl LocalApduReceiver for AdmissionReceiver<ReceivedApdu> {}
pub trait NetworkControlReceiver: sealed::Sealed<ReceivedNetworkControl> {}
impl NetworkControlReceiver for mpsc::Receiver<ReceivedNetworkControl> {}
impl NetworkControlReceiver for AdmissionReceiver<ReceivedNetworkControl> {}
pub(super) mod sealed {
use super::*;
pub trait Sealed<T>: Sized {
const TRACKED: bool;
fn from_queue(rx: mpsc::Receiver<T>, counters: QueueAdmissionCounters) -> Self;
}
impl<T> Sealed<T> for mpsc::Receiver<T> {
const TRACKED: bool = false;
fn from_queue(rx: mpsc::Receiver<T>, _: QueueAdmissionCounters) -> Self {
rx
}
}
impl Sealed<ReceivedApdu> for AdmissionReceiver<ReceivedApdu> {
const TRACKED: bool = true;
fn from_queue(rx: mpsc::Receiver<ReceivedApdu>, counters: QueueAdmissionCounters) -> Self {
AdmissionReceiver::from_apdu_parts(rx, counters)
}
}
impl Sealed<ReceivedNetworkControl> for AdmissionReceiver<ReceivedNetworkControl> {
const TRACKED: bool = true;
fn from_queue(
rx: mpsc::Receiver<ReceivedNetworkControl>,
counters: QueueAdmissionCounters,
) -> Self {
AdmissionReceiver::from_parts(rx, counters)
}
}
}
#[cfg(test)]
#[path = "options_tests.rs"]
mod tests;