use crate::transport::{FrameLabel, context::PolicySignalsProvider};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum ChannelDirection {
Bidirectional,
SendOnly,
RecvOnly,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Channel(pub u64);
impl Channel {
pub const fn new(id: u64) -> Self {
Self(id)
}
pub const fn raw(&self) -> u64 {
self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ChannelKey {
pub frame_label: FrameLabel,
pub instance: u16,
}
impl ChannelKey {
pub const fn new(frame_label: FrameLabel, instance: u16) -> Self {
Self {
frame_label,
instance,
}
}
}
pub trait ChannelStore {
fn register(&mut self, key: ChannelKey, channel: Channel) -> Result<(), TransportOpsError>;
fn get(&self, key: ChannelKey) -> Option<Channel>;
fn get_key(&self, channel: Channel) -> Option<ChannelKey>;
fn next_instance(&mut self, frame_label: FrameLabel) -> Result<u16, TransportOpsError>;
fn current_instance(&self, frame_label: FrameLabel) -> Option<u16>;
fn unregister(&mut self, channel: Channel);
fn clear(&mut self);
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TransportOpsError {
ChannelNotFound,
OpenFailed,
WriteFailed { expected: usize, actual: usize },
AlreadyFinished,
InvalidState,
Protocol(u64),
ChannelStoreFull,
}
impl core::fmt::Display for TransportOpsError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::ChannelNotFound => write!(f, "channel not found"),
Self::OpenFailed => write!(f, "failed to open channel"),
Self::WriteFailed { expected, actual } => {
write!(
f,
"write failed: expected {} bytes, wrote {}",
expected, actual
)
}
Self::AlreadyFinished => write!(f, "channel already finished"),
Self::InvalidState => write!(f, "invalid operation for channel state"),
Self::Protocol(code) => write!(f, "protocol error: {}", code),
Self::ChannelStoreFull => write!(f, "channel store is full"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for TransportOpsError {}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct IngressEvidence {
pub frame_label: crate::transport::FrameLabel,
pub instance: u16,
pub has_fin: bool,
pub channel: Channel,
}
pub trait BindingSlot {
fn poll_incoming_for_lane(&mut self, logical_lane: u8) -> Option<IngressEvidence>;
fn on_recv<'a>(
&'a mut self,
channel: Channel,
scratch: &'a mut [u8],
) -> Result<crate::transport::wire::Payload<'a>, TransportOpsError>;
fn policy_signals_provider(&self) -> Option<&dyn PolicySignalsProvider>;
}
pub(crate) enum BindingHandle<'a> {
None(NoBinding),
Borrowed(&'a mut dyn BindingSlot),
}
impl BindingHandle<'_> {
#[inline(always)]
pub(crate) const fn uses_binding_storage(&self) -> bool {
matches!(self, Self::Borrowed(_))
}
}
pub(crate) trait BindingArg<'a> {
fn into_binding_handle(self) -> BindingHandle<'a>;
}
impl<'a> BindingArg<'a> for BindingHandle<'a> {
#[inline(always)]
fn into_binding_handle(self) -> BindingHandle<'a> {
self
}
}
impl<'a> BindingArg<'a> for NoBinding {
#[inline(always)]
fn into_binding_handle(self) -> BindingHandle<'a> {
BindingHandle::None(self)
}
}
impl<'a, B> BindingArg<'a> for &'a mut B
where
B: BindingSlot + 'a,
{
#[inline(always)]
fn into_binding_handle(self) -> BindingHandle<'a> {
BindingHandle::Borrowed(self)
}
}
impl BindingSlot for BindingHandle<'_> {
#[inline(always)]
fn poll_incoming_for_lane(&mut self, logical_lane: u8) -> Option<IngressEvidence> {
match self {
Self::None(binding) => binding.poll_incoming_for_lane(logical_lane),
Self::Borrowed(binding) => binding.poll_incoming_for_lane(logical_lane),
}
}
#[inline(always)]
fn on_recv<'a>(
&'a mut self,
channel: Channel,
scratch: &'a mut [u8],
) -> Result<crate::transport::wire::Payload<'a>, TransportOpsError> {
match self {
Self::None(binding) => binding.on_recv(channel, scratch),
Self::Borrowed(binding) => binding.on_recv(channel, scratch),
}
}
#[inline(always)]
fn policy_signals_provider(&self) -> Option<&dyn PolicySignalsProvider> {
match self {
Self::None(binding) => binding.policy_signals_provider(),
Self::Borrowed(binding) => binding.policy_signals_provider(),
}
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct NoBinding;
impl BindingSlot for NoBinding {
#[inline(always)]
fn poll_incoming_for_lane(&mut self, _logical_lane: u8) -> Option<IngressEvidence> {
None
}
#[inline(always)]
fn on_recv<'a>(
&'a mut self,
_channel: Channel,
_scratch: &'a mut [u8],
) -> Result<crate::transport::wire::Payload<'a>, TransportOpsError> {
Ok(crate::transport::wire::Payload::new(&[]))
}
#[inline(always)]
fn policy_signals_provider(&self) -> Option<&dyn PolicySignalsProvider> {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::policy_runtime::PolicySlot;
use crate::transport::context::PolicySignals;
#[test]
fn channel_key_uses_frame_label_not_logical_label() {
let key = ChannelKey::new(FrameLabel::new(200), 7);
assert_eq!(key.frame_label.raw(), 200);
assert_eq!(key.instance, 7);
}
#[test]
fn no_binding_policy_signals_are_zero_for_all_slots() {
let binding = NoBinding;
for slot in [
PolicySlot::Forward,
PolicySlot::EndpointRx,
PolicySlot::EndpointTx,
PolicySlot::Rendezvous,
PolicySlot::Route,
] {
let signals = binding
.policy_signals_provider()
.map(|provider| provider.signals(slot))
.unwrap_or(PolicySignals::ZERO);
assert_eq!(signals, PolicySignals::ZERO);
}
}
}