orbit_core/fleet/
cursor.rs1use std::marker::PhantomData;
2
3use crate::OrbitTyped;
4use crate::fleet::{Fleet, NodeId};
5use crate::ring::cursor::{
6 RingCursor, RingFrameSource, RingLoss, RingPoll, RingRead, poll_ring,
7};
8use crate::ring::{Frame, RingTopology};
9
10struct FleetRingSource<'a, T: OrbitTyped> {
11 fleet: &'a Fleet,
12 _t: PhantomData<T>,
13}
14
15struct FleetLaneSource<'a, T: OrbitTyped> {
16 fleet: &'a Fleet,
17 node_id: NodeId,
18 _t: PhantomData<T>,
19}
20
21impl<'a, T: OrbitTyped> FleetLaneSource<'a, T> {
22 fn new(
23 fleet: &'a Fleet,
24 node_id: NodeId,
25 ) -> Self {
26 Self { fleet, node_id, _t: PhantomData }
27 }
28}
29
30impl<T: OrbitTyped> RingFrameSource for FleetLaneSource<'_, T> {
31 fn kind(&self) -> u8 {
32 T::KIND
33 }
34
35 fn head(&self) -> u64 {
36 self.fleet.lane_head::<T>(self.node_id)
37 }
38
39 fn capacity(&self) -> usize {
40 self.fleet.ring_capacity::<T>()
41 }
42
43 fn read_at(
44 &self,
45 counter: u64,
46 ) -> Option<Frame> {
47 self.fleet.read_lane_at::<T>(self.node_id, counter)
48 }
49
50 fn read_state_at(
51 &self,
52 counter: u64,
53 ) -> RingRead {
54 self.fleet.read_lane_state_at::<T>(self.node_id, counter)
55 }
56}
57
58#[derive(Clone, Debug, PartialEq, Eq)]
60pub struct FleetLaneCursor {
61 lanes: Vec<RingCursor>,
62 initial_counter: u64,
63}
64
65impl FleetLaneCursor {
66 pub const fn from_counter(initial_counter: u64) -> Self {
67 Self { lanes: Vec::new(), initial_counter }
68 }
69
70 pub fn minimum_next_counter(&self) -> u64 {
71 self.lanes
72 .iter()
73 .map(|cursor| cursor.next_counter())
74 .min()
75 .unwrap_or(self.initial_counter)
76 }
77}
78
79#[derive(Clone, Debug, Default, PartialEq, Eq)]
81pub struct FleetLanePoll {
82 pub frames: Vec<Frame>,
83 pub loss: RingLoss,
84}
85
86impl<'a, T: OrbitTyped> FleetRingSource<'a, T> {
87 fn new(fleet: &'a Fleet) -> Self {
88 Self { fleet, _t: PhantomData }
89 }
90}
91
92impl<T: OrbitTyped> RingFrameSource for FleetRingSource<'_, T> {
93 fn kind(&self) -> u8 {
94 T::KIND
95 }
96
97 fn head(&self) -> u64 {
98 self.fleet.head::<T>()
99 }
100
101 fn capacity(&self) -> usize {
102 self.fleet.ring_capacity::<T>()
103 }
104
105 fn read_at(
106 &self,
107 counter: u64,
108 ) -> Option<Frame> {
109 self.fleet.read_at::<T>(counter)
110 }
111
112 fn read_state_at(
113 &self,
114 counter: u64,
115 ) -> RingRead {
116 self.fleet.read_state_at::<T>(counter)
117 }
118}
119
120impl Fleet {
121 pub fn cursor_at_head<T: OrbitTyped>(&self) -> RingCursor {
124 RingCursor::from_counter(self.head::<T>())
125 }
126
127 pub const fn cursor_from_start<T: OrbitTyped>(&self) -> RingCursor {
129 let _ = self;
130 let _ = PhantomData::<T>;
131 RingCursor::from_start()
132 }
133
134 pub fn poll_ring<T: OrbitTyped>(
138 &self,
139 cursor: &mut RingCursor,
140 ) -> RingPoll {
141 poll_ring(&FleetRingSource::<T>::new(self), cursor)
142 }
143
144 pub fn lane_cursor_at_head<T: OrbitTyped>(&self) -> FleetLaneCursor {
147 self.assert_per_node::<T>();
148 let lanes = (0..self.fleet_capacity())
149 .map(|node| {
150 RingCursor::from_counter(self.lane_head::<T>(NodeId::new(node)))
151 })
152 .collect();
153 FleetLaneCursor { lanes, initial_counter: 0 }
154 }
155
156 pub fn lane_cursor_from_start<T: OrbitTyped>(&self) -> FleetLaneCursor {
159 self.assert_per_node::<T>();
160 FleetLaneCursor {
161 lanes: vec![
162 RingCursor::from_start();
163 usize::from(self.fleet_capacity())
164 ],
165 initial_counter: 0,
166 }
167 }
168
169 pub fn poll_lanes<T: OrbitTyped>(
173 &self,
174 cursor: &mut FleetLaneCursor,
175 ) -> FleetLanePoll {
176 self.assert_per_node::<T>();
177 if cursor.lanes.is_empty() {
178 cursor.lanes = vec![
179 RingCursor::from_counter(cursor.initial_counter);
180 usize::from(self.fleet_capacity())
181 ];
182 }
183 assert_eq!(
184 cursor.lanes.len(),
185 usize::from(self.fleet_capacity()),
186 "lane cursor belongs to a different fleet capacity"
187 );
188
189 let mut combined = FleetLanePoll::default();
190 for (node, lane_cursor) in cursor.lanes.iter_mut().enumerate() {
191 let source =
192 FleetLaneSource::<T>::new(self, NodeId::new(node as u16));
193 let poll = poll_ring(&source, lane_cursor);
194 combined.frames.extend(poll.frames);
195 combined.loss.overwritten =
196 combined.loss.overwritten.saturating_add(poll.loss.overwritten);
197 combined.loss.unavailable =
198 combined.loss.unavailable.saturating_add(poll.loss.unavailable);
199 }
200 combined
201 }
202
203 fn assert_per_node<T: OrbitTyped>(&self) {
204 assert_eq!(
205 T::RING_SPEC.topology,
206 RingTopology::PerNode,
207 "lane cursor requires a per-node ring"
208 );
209 }
210}