use std::marker::PhantomData;
use crate::OrbitTyped;
use crate::fleet::{Fleet, NodeId};
use crate::ring::cursor::{RingCursor, RingFrameSource, RingLoss, RingPoll, RingRead, poll_ring};
use crate::ring::{Frame, RingTopology};
struct FleetRingSource<'a, T: OrbitTyped> {
fleet: &'a Fleet,
_t: PhantomData<T>
}
struct FleetLaneSource<'a, T: OrbitTyped> {
fleet: &'a Fleet,
node_id: NodeId,
_t: PhantomData<T>
}
impl<'a, T: OrbitTyped> FleetLaneSource<'a, T> {
fn new(
fleet: &'a Fleet,
node_id: NodeId
) -> Self {
Self { fleet, node_id, _t: PhantomData }
}
}
impl<T: OrbitTyped> RingFrameSource for FleetLaneSource<'_, T> {
fn kind(&self) -> u8 {
T::KIND
}
fn head(&self) -> u64 {
self.fleet.lane_head::<T>(self.node_id)
}
fn capacity(&self) -> usize {
self.fleet.ring_capacity::<T>()
}
fn read_at(
&self,
counter: u64
) -> Option<Frame> {
self.fleet.read_lane_at::<T>(self.node_id, counter)
}
fn read_state_at(
&self,
counter: u64
) -> RingRead {
self.fleet.read_lane_state_at::<T>(self.node_id, counter)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FleetLaneCursor {
lanes: Vec<RingCursor>,
initial_counter: u64
}
impl FleetLaneCursor {
pub const fn from_counter(initial_counter: u64) -> Self {
Self { lanes: Vec::new(), initial_counter }
}
pub fn minimum_next_counter(&self) -> u64 {
self.lanes.iter().map(|cursor| cursor.next_counter()).min().unwrap_or(self.initial_counter)
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct FleetLanePoll {
pub frames: Vec<Frame>,
pub loss: RingLoss
}
impl<'a, T: OrbitTyped> FleetRingSource<'a, T> {
fn new(fleet: &'a Fleet) -> Self {
Self { fleet, _t: PhantomData }
}
}
impl<T: OrbitTyped> RingFrameSource for FleetRingSource<'_, T> {
fn kind(&self) -> u8 {
T::KIND
}
fn head(&self) -> u64 {
self.fleet.head::<T>()
}
fn capacity(&self) -> usize {
self.fleet.ring_capacity::<T>()
}
fn read_at(
&self,
counter: u64
) -> Option<Frame> {
self.fleet.read_at::<T>(counter)
}
fn read_state_at(
&self,
counter: u64
) -> RingRead {
self.fleet.read_state_at::<T>(counter)
}
}
impl Fleet {
pub fn cursor_at_head<T: OrbitTyped>(&self) -> RingCursor {
RingCursor::from_counter(self.head::<T>())
}
pub const fn cursor_from_start<T: OrbitTyped>(&self) -> RingCursor {
let _ = self;
let _ = PhantomData::<T>;
RingCursor::from_start()
}
pub fn poll_ring<T: OrbitTyped>(
&self,
cursor: &mut RingCursor
) -> RingPoll {
poll_ring(&FleetRingSource::<T>::new(self), cursor)
}
pub fn lane_cursor_at_head<T: OrbitTyped>(&self) -> FleetLaneCursor {
self.assert_per_node::<T>();
let lanes = (0..self.fleet_capacity())
.map(|node| RingCursor::from_counter(self.lane_head::<T>(NodeId::new(node))))
.collect();
FleetLaneCursor { lanes, initial_counter: 0 }
}
pub fn lane_cursor_from_start<T: OrbitTyped>(&self) -> FleetLaneCursor {
self.assert_per_node::<T>();
FleetLaneCursor {
lanes: vec![RingCursor::from_start(); usize::from(self.fleet_capacity())],
initial_counter: 0
}
}
pub fn poll_lanes<T: OrbitTyped>(
&self,
cursor: &mut FleetLaneCursor
) -> FleetLanePoll {
self.assert_per_node::<T>();
if cursor.lanes.is_empty() {
cursor.lanes = vec![
RingCursor::from_counter(cursor.initial_counter);
usize::from(self.fleet_capacity())
];
}
assert_eq!(
cursor.lanes.len(),
usize::from(self.fleet_capacity()),
"lane cursor belongs to a different fleet capacity"
);
let mut combined = FleetLanePoll::default();
for (node, lane_cursor) in cursor.lanes.iter_mut().enumerate() {
let source = FleetLaneSource::<T>::new(self, NodeId::new(node as u16));
let poll = poll_ring(&source, lane_cursor);
combined.frames.extend(poll.frames);
combined.loss.overwritten =
combined.loss.overwritten.saturating_add(poll.loss.overwritten);
combined.loss.unavailable =
combined.loss.unavailable.saturating_add(poll.loss.unavailable);
}
combined
}
fn assert_per_node<T: OrbitTyped>(&self) {
assert_eq!(
T::RING_SPEC.topology,
RingTopology::PerNode,
"lane cursor requires a per-node ring"
);
}
}