1use std::fmt;
2use std::ops::{Deref, DerefMut};
3use std::str::FromStr;
4use std::sync::Arc;
5use std::time::Duration;
6
7use orbit_core::{Fleet, NodeId};
8
9use super::arena::Publication;
10use super::protocol::CONTROL_FRAME_BYTES;
11use super::{
12 ChunkDescriptor, ChunkGeometry, ChunkPlan, ControlEvent, ExchangeId, Flow,
13 PayloadArena, PayloadArenaSpec, PayloadChunk, ResetCode,
14};
15use crate::{
16 Error, Incarnation, ReadHalf, Result, Side, StreamSpec, Streams, Ticket,
17 WriteHalf,
18};
19
20#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
27pub enum ExchangePayloadSpec {
28 Shared(PayloadArenaSpec),
29 Directional { a_to_b: PayloadArenaSpec, b_to_a: PayloadArenaSpec },
30}
31
32impl ExchangePayloadSpec {
33 pub const fn for_flow(
35 self,
36 flow: Flow,
37 ) -> PayloadArenaSpec {
38 match (self, flow) {
39 (Self::Shared(payload), _) => payload,
40 (Self::Directional { a_to_b, .. }, Flow::AtoB) => a_to_b,
41 (Self::Directional { b_to_a, .. }, Flow::BtoA) => b_to_a,
42 }
43 }
44}
45
46#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
48pub struct ExchangeSpec {
49 pub control: StreamSpec,
52 pub payload: ExchangePayloadSpec,
55}
56
57impl ExchangeSpec {
58 pub const fn new(
59 control: StreamSpec,
60 payload: PayloadArenaSpec,
61 ) -> Self {
62 Self { control, payload: ExchangePayloadSpec::Shared(payload) }
63 }
64
65 pub const fn directional(
66 control: StreamSpec,
67 a_to_b: PayloadArenaSpec,
68 b_to_a: PayloadArenaSpec,
69 ) -> Self {
70 Self {
71 control,
72 payload: ExchangePayloadSpec::Directional { a_to_b, b_to_a },
73 }
74 }
75
76 pub const fn payload_for(
78 self,
79 flow: Flow,
80 ) -> PayloadArenaSpec {
81 self.payload.for_flow(flow)
82 }
83
84 pub const fn chunk_geometry(
86 self,
87 flow: Flow,
88 ) -> Option<ChunkGeometry> {
89 self.payload_for(flow).chunk_geometry()
90 }
91
92 fn validate(self) -> Result<()> {
93 if self.control.buffer_bytes < CONTROL_FRAME_BYTES {
94 return Err(Error::Malformed(format!(
95 "exchange control ring is {} bytes; one control frame is {CONTROL_FRAME_BYTES}",
96 self.control.buffer_bytes
97 )));
98 }
99 match self.payload {
100 ExchangePayloadSpec::Shared(payload)
101 if self.control.kind == payload.kind =>
102 {
103 return Err(Error::Malformed(
104 "exchange control and payload need distinct SHM kinds"
105 .to_owned(),
106 ));
107 }
108 ExchangePayloadSpec::Directional { a_to_b, b_to_a }
109 if self.control.kind == a_to_b.kind
110 || self.control.kind == b_to_a.kind
111 || a_to_b.kind == b_to_a.kind =>
112 {
113 return Err(Error::Malformed(
114 "exchange control and directional payloads need three distinct SHM kinds"
115 .to_owned()
116 ));
117 }
118 _ => {}
119 }
120 Ok(())
121 }
122}
123
124#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
127pub struct ExchangeTicket(Ticket);
128
129impl ExchangeTicket {
130 pub const fn from_stream_ticket(ticket: Ticket) -> Self {
131 Self(ticket)
132 }
133
134 pub const fn stream_ticket(self) -> Ticket {
135 self.0
136 }
137
138 pub const fn id(self) -> ExchangeId {
139 ExchangeId::from_stream_id(self.0.id)
140 }
141}
142
143impl fmt::Display for ExchangeTicket {
144 fn fmt(
145 &self,
146 f: &mut fmt::Formatter<'_>,
147 ) -> fmt::Result {
148 self.0.fmt(f)
149 }
150}
151
152impl FromStr for ExchangeTicket {
153 type Err = Error;
154
155 fn from_str(text: &str) -> Result<Self> {
156 text.parse().map(Self)
157 }
158}
159
160#[derive(Clone)]
161enum PayloadArenas {
162 Shared(PayloadArena),
163 Directional { a_to_b: PayloadArena, b_to_a: PayloadArena },
164}
165
166impl PayloadArenas {
167 fn for_flow(
168 &self,
169 flow: Flow,
170 ) -> PayloadArena {
171 match (self, flow) {
172 (Self::Shared(arena), _) => arena.clone(),
173 (Self::Directional { a_to_b, .. }, Flow::AtoB) => a_to_b.clone(),
174 (Self::Directional { b_to_a, .. }, Flow::BtoA) => b_to_a.clone(),
175 }
176 }
177
178 fn node_dead(
179 &self,
180 node: NodeId,
181 incarnation: Incarnation,
182 ) {
183 match self {
184 Self::Shared(arena) => arena.node_dead(node, incarnation),
185 Self::Directional { a_to_b, b_to_a } => {
186 a_to_b.node_dead(node, incarnation);
187 b_to_a.node_dead(node, incarnation);
188 }
189 }
190 }
191
192 fn reset_all(&self) {
193 match self {
194 Self::Shared(arena) => arena.reset_all(),
195 Self::Directional { a_to_b, b_to_a } => {
196 a_to_b.reset_all();
197 b_to_a.reset_all();
198 }
199 }
200 }
201
202 #[cfg(unix)]
203 fn unlink(&self) -> Result<()> {
204 match self {
205 Self::Shared(arena) => arena.unlink(),
206 Self::Directional { a_to_b, b_to_a } => {
207 a_to_b.unlink()?;
208 b_to_a.unlink()
209 }
210 }
211 }
212}
213
214#[derive(Clone)]
217pub struct Exchanges {
218 control: Streams,
219 payload: PayloadArenas,
220}
221
222impl Exchanges {
223 pub fn open(
224 fleet: Arc<Fleet>,
225 incarnation: Incarnation,
226 spec: ExchangeSpec,
227 ) -> Result<Self> {
228 spec.validate()?;
229 let control =
230 Streams::with_spec(Arc::clone(&fleet), incarnation, spec.control)?;
231 let payload = match spec.payload {
232 ExchangePayloadSpec::Shared(payload) => PayloadArenas::Shared(
233 PayloadArena::open(fleet, incarnation, payload)?,
234 ),
235 ExchangePayloadSpec::Directional { a_to_b, b_to_a } => {
236 PayloadArenas::Directional {
237 a_to_b: PayloadArena::open(
238 Arc::clone(&fleet),
239 incarnation,
240 a_to_b,
241 )?,
242 b_to_a: PayloadArena::open(fleet, incarnation, b_to_a)?,
243 }
244 }
245 };
246 Ok(Self { control, payload })
247 }
248
249 pub fn create(&self) -> Result<(ExchangeEndpoint, ExchangeTicket)> {
252 let (endpoint, ticket) = self.control.create()?;
253 Ok((self.endpoint(endpoint), ExchangeTicket(ticket)))
254 }
255
256 pub fn create_payload_available(
260 &self,
261 payload_len: usize,
262 ) -> Result<bool> {
263 self.payload.for_flow(Flow::AtoB).is_available(payload_len)
264 }
265
266 pub fn poll_create_payload_available(
268 &self,
269 payload_len: usize,
270 cx: &mut std::task::Context<'_>,
271 ) -> std::task::Poll<Result<()>> {
272 self.payload.for_flow(Flow::AtoB).poll_available(payload_len, cx)
273 }
274
275 pub fn open_peer(
278 &self,
279 ticket: ExchangeTicket,
280 ) -> Result<ExchangeEndpoint> {
281 let endpoint = self.control.open(ticket.0)?;
282 Ok(self.endpoint(endpoint))
283 }
284
285 fn endpoint(
286 &self,
287 endpoint: crate::Endpoint,
288 ) -> ExchangeEndpoint {
289 let id = ExchangeId::from_stream_id(endpoint.id());
290 let (send_flow, receive_flow) = match endpoint.side() {
291 Side::A => (Flow::AtoB, Flow::BtoA),
292 Side::B => (Flow::BtoA, Flow::AtoB),
293 };
294 let (read, write) = endpoint.split();
295 ExchangeEndpoint {
296 sender: Sender(Producer::new(
297 id,
298 send_flow,
299 self.payload.for_flow(send_flow),
300 write,
301 )),
302 receiver: Receiver(Consumer::new(
303 id,
304 receive_flow,
305 self.payload.for_flow(receive_flow),
306 read,
307 )),
308 }
309 }
310
311 pub fn offer(
312 &self,
313 ticket: ExchangeTicket,
314 to: NodeId,
315 ) -> Result<()> {
316 self.control.offer(ticket.0, to)
317 }
318
319 pub fn take_offer(&self) -> Option<ExchangeTicket> {
320 self.control.take_offer().map(ExchangeTicket)
321 }
322
323 pub fn blocking_take_offer(&self) -> Result<ExchangeTicket> {
325 self.control.blocking_take_offer().map(ExchangeTicket)
326 }
327
328 #[cfg(any(
330 target_os = "linux",
331 target_os = "freebsd",
332 target_os = "macos"
333 ))]
334 pub fn take_offer_timeout(
335 &self,
336 timeout: Duration,
337 ) -> Result<Option<ExchangeTicket>> {
338 self.control
339 .take_offer_timeout(timeout)
340 .map(|ticket| ticket.map(ExchangeTicket))
341 }
342
343 pub fn poll_take_offer(
345 &self,
346 cx: &mut std::task::Context<'_>,
347 ) -> std::task::Poll<Result<ExchangeTicket>> {
348 match self.control.poll_take_offer(cx) {
349 std::task::Poll::Ready(result) => {
350 std::task::Poll::Ready(result.map(ExchangeTicket))
351 }
352 std::task::Poll::Pending => std::task::Poll::Pending,
353 }
354 }
355
356 pub fn control(&self) -> &Streams {
357 &self.control
358 }
359
360 pub fn node_dead(
363 &self,
364 node: NodeId,
365 incarnation: Incarnation,
366 ) {
367 self.control.node_dead(node, incarnation);
368 self.payload.node_dead(node, incarnation);
369 }
370
371 pub fn reset_all(&self) {
374 self.control.reset_all();
375 self.payload.reset_all();
376 }
377
378 #[cfg(unix)]
381 pub fn unlink(&self) -> Result<()> {
382 self.control.unlink()?;
383 self.payload.unlink()
384 }
385}
386
387pub struct ExchangeEndpoint {
390 sender: Sender,
391 receiver: Receiver,
392}
393
394impl ExchangeEndpoint {
395 pub fn id(&self) -> ExchangeId {
396 self.sender.id()
397 }
398
399 pub fn sender(&mut self) -> &mut Sender {
400 &mut self.sender
401 }
402
403 pub fn receiver(&mut self) -> &mut Receiver {
404 &mut self.receiver
405 }
406
407 pub fn split(self) -> (Sender, Receiver) {
408 (self.sender, self.receiver)
409 }
410}
411
412#[derive(Clone, Copy, Debug, Eq, PartialEq)]
413enum ProducerState {
414 New,
415 Open,
416 Terminal,
417}
418
419struct Producer {
420 exchange: ExchangeId,
421 flow: Flow,
422 arena: PayloadArena,
423 control: WriteHalf,
424 next_chunk: u64,
425 state: ProducerState,
426}
427
428impl Producer {
429 fn new(
430 exchange: ExchangeId,
431 flow: Flow,
432 arena: PayloadArena,
433 control: WriteHalf,
434 ) -> Self {
435 Self {
436 exchange,
437 flow,
438 arena,
439 control,
440 next_chunk: 1,
441 state: ProducerState::New,
442 }
443 }
444
445 fn id(&self) -> ExchangeId {
446 self.exchange
447 }
448
449 fn start(
450 &mut self,
451 metadata: Option<&[u8]>,
452 ) -> Result<()> {
453 if self.state != ProducerState::New {
454 return Err(Error::Malformed(
455 "flow start was already sent".to_owned(),
456 ));
457 }
458 if let Some(bytes) = metadata.filter(|bytes| !bytes.is_empty()) {
459 let mut pending = self.reserve_start(bytes.len())?;
460 pending.copy_from_slice(bytes);
461 pending.commit()?;
462 } else {
463 self.send(ControlEvent::Start {
464 exchange: self.exchange,
465 flow: self.flow,
466 metadata: None,
467 })?;
468 self.state = ProducerState::Open;
469 }
470 Ok(())
471 }
472
473 fn data(
474 &mut self,
475 payload: &[u8],
476 ) -> Result<ChunkDescriptor> {
477 let mut pending = self.reserve_data(payload.len())?;
478 pending.copy_from_slice(payload);
479 pending.commit()
480 }
481
482 fn reserve_start(
483 &mut self,
484 payload_len: usize,
485 ) -> Result<PendingStart<'_>> {
486 if self.state != ProducerState::New {
487 return Err(Error::Malformed(
488 "flow start was already sent".to_owned(),
489 ));
490 }
491 let publication = self.arena.reserve(payload_len)?;
492 Ok(PendingStart { producer: self, publication })
493 }
494
495 fn reserve_data(
496 &mut self,
497 payload_len: usize,
498 ) -> Result<PendingData<'_>> {
499 if self.state != ProducerState::Open {
500 return Err(Error::Malformed(
501 "flow data requires an open flow".to_owned(),
502 ));
503 }
504 let publication = self.arena.reserve(payload_len)?;
505 Ok(PendingData { producer: self, publication })
506 }
507
508 fn commit_start(
509 &mut self,
510 publication: Publication,
511 ) -> Result<ChunkDescriptor> {
512 let descriptor = self.descriptor(&publication);
513 publication.make_live();
514 self.send(ControlEvent::Start {
515 exchange: self.exchange,
516 flow: self.flow,
517 metadata: Some(descriptor),
518 })?;
519 publication.mark_published();
520 self.next_chunk += 1;
521 self.state = ProducerState::Open;
522 Ok(descriptor)
523 }
524
525 fn commit_data(
526 &mut self,
527 publication: Publication,
528 ) -> Result<ChunkDescriptor> {
529 let descriptor = self.descriptor(&publication);
530 publication.make_live();
531 self.send(ControlEvent::Data(descriptor))?;
532 publication.mark_published();
533 self.next_chunk += 1;
534 Ok(descriptor)
535 }
536
537 fn finish(&mut self) -> Result<()> {
538 if self.state != ProducerState::Open {
539 return Err(Error::Malformed(
540 "flow FIN requires an open flow".to_owned(),
541 ));
542 }
543 self.send(ControlEvent::Fin {
544 exchange: self.exchange,
545 flow: self.flow,
546 })?;
547 self.control.finish()?;
548 self.state = ProducerState::Terminal;
549 Ok(())
550 }
551
552 fn reset(
553 &mut self,
554 code: ResetCode,
555 ) -> Result<()> {
556 if self.state == ProducerState::Terminal {
557 return Err(Error::Closed);
558 }
559 self.send(ControlEvent::Reset {
560 exchange: self.exchange,
561 flow: self.flow,
562 code,
563 })?;
564 self.control.finish()?;
565 self.state = ProducerState::Terminal;
566 Ok(())
567 }
568
569 fn send(
570 &self,
571 event: ControlEvent,
572 ) -> Result<()> {
573 self.control.try_write_exact(&event.encode())
574 }
575
576 fn descriptor(
577 &self,
578 publication: &Publication,
579 ) -> ChunkDescriptor {
580 let (
581 generation,
582 first_slot,
583 slot_count,
584 payload_len,
585 arena_kind,
586 owner_node,
587 ) = publication.coordinates();
588 ChunkDescriptor::new(
589 self.exchange,
590 self.flow,
591 self.next_chunk,
592 generation,
593 first_slot,
594 slot_count,
595 payload_len,
596 arena_kind,
597 owner_node,
598 )
599 }
600}
601
602pub struct PendingStart<'a> {
606 producer: &'a mut Producer,
607 publication: Publication,
608}
609
610impl PendingStart<'_> {
611 pub fn as_mut_slice(&mut self) -> &mut [u8] {
612 self.publication.as_mut_slice()
613 }
614
615 pub fn commit(self) -> Result<ChunkDescriptor> {
616 self.producer.commit_start(self.publication)
617 }
618
619 pub fn commit_len(
622 mut self,
623 payload_len: usize,
624 ) -> Result<ChunkDescriptor> {
625 self.publication.truncate(payload_len)?;
626 self.producer.commit_start(self.publication)
627 }
628}
629
630impl Deref for PendingStart<'_> {
631 type Target = [u8];
632
633 fn deref(&self) -> &Self::Target {
634 self.publication.as_slice()
635 }
636}
637
638impl DerefMut for PendingStart<'_> {
639 fn deref_mut(&mut self) -> &mut Self::Target {
640 self.as_mut_slice()
641 }
642}
643
644pub struct PendingData<'a> {
647 producer: &'a mut Producer,
648 publication: Publication,
649}
650
651impl PendingData<'_> {
652 pub fn as_mut_slice(&mut self) -> &mut [u8] {
653 self.publication.as_mut_slice()
654 }
655
656 pub fn commit(self) -> Result<ChunkDescriptor> {
657 self.producer.commit_data(self.publication)
658 }
659
660 pub fn commit_len(
663 mut self,
664 payload_len: usize,
665 ) -> Result<ChunkDescriptor> {
666 self.publication.truncate(payload_len)?;
667 self.producer.commit_data(self.publication)
668 }
669}
670
671impl Deref for PendingData<'_> {
672 type Target = [u8];
673
674 fn deref(&self) -> &Self::Target {
675 self.publication.as_slice()
676 }
677}
678
679impl DerefMut for PendingData<'_> {
680 fn deref_mut(&mut self) -> &mut Self::Target {
681 self.as_mut_slice()
682 }
683}
684
685#[derive(Clone, Copy, Debug, Eq, PartialEq)]
686enum ConsumerState {
687 New,
688 Open,
689 Terminal,
690}
691
692struct Consumer {
693 exchange: ExchangeId,
694 flow: Flow,
695 arena: PayloadArena,
696 control: ReadHalf,
697 next_chunk: u64,
698 state: ConsumerState,
699}
700
701impl Consumer {
702 fn new(
703 exchange: ExchangeId,
704 flow: Flow,
705 arena: PayloadArena,
706 control: ReadHalf,
707 ) -> Self {
708 Self {
709 exchange,
710 flow,
711 arena,
712 control,
713 next_chunk: 1,
714 state: ConsumerState::New,
715 }
716 }
717
718 fn id(&self) -> ExchangeId {
719 self.exchange
720 }
721
722 fn next(&mut self) -> Result<FlowEvent> {
723 if self.state == ConsumerState::Terminal {
724 return Err(Error::Closed);
725 }
726 let mut frame = [0_u8; CONTROL_FRAME_BYTES];
727 self.control.try_read_exact(&mut frame)?;
728 let event = ControlEvent::decode(&frame)
729 .map_err(|reason| Error::Malformed(reason.to_owned()))?;
730 if event.exchange() != self.exchange || event.flow() != self.flow {
731 return Err(Error::Malformed(
732 "control event belongs to another exchange flow".to_owned(),
733 ));
734 }
735 match event {
736 ControlEvent::Start { metadata, .. }
737 if self.state == ConsumerState::New =>
738 {
739 let metadata = metadata
740 .map(|descriptor| self.take_chunk(descriptor))
741 .transpose()?;
742 self.state = ConsumerState::Open;
743 Ok(FlowEvent::Start { metadata })
744 }
745 ControlEvent::Data(descriptor)
746 if self.state == ConsumerState::Open =>
747 {
748 let chunk = self.take_chunk(descriptor)?;
749 Ok(FlowEvent::Data(chunk))
750 }
751 ControlEvent::Fin { .. } if self.state == ConsumerState::Open => {
752 self.state = ConsumerState::Terminal;
753 Ok(FlowEvent::Fin)
754 }
755 ControlEvent::Reset { code, .. } => {
756 self.state = ConsumerState::Terminal;
757 Ok(FlowEvent::Reset(code))
758 }
759 _ => Err(Error::Malformed(
760 "control event violates the flow lifecycle".to_owned(),
761 )),
762 }
763 }
764
765 fn take_chunk(
766 &mut self,
767 descriptor: ChunkDescriptor,
768 ) -> Result<PayloadChunk> {
769 if descriptor.chunk_id() != self.next_chunk {
770 return Err(Error::Malformed(format!(
771 "flow expected chunk {}, received {}",
772 self.next_chunk,
773 descriptor.chunk_id()
774 )));
775 }
776 let chunk = self.arena.read(descriptor)?;
777 self.next_chunk += 1;
778 Ok(chunk)
779 }
780}
781
782pub enum FlowEvent {
784 Start { metadata: Option<PayloadChunk> },
785 Data(PayloadChunk),
786 Fin,
787 Reset(ResetCode),
788}
789
790pub trait FlowHandler {
793 type Error;
794
795 fn on_start(
796 &mut self,
797 metadata: Option<PayloadChunk>,
798 ) -> std::result::Result<(), Self::Error>;
799 fn on_data(
800 &mut self,
801 chunk: PayloadChunk,
802 ) -> std::result::Result<(), Self::Error>;
803 fn on_fin(&mut self) -> std::result::Result<(), Self::Error>;
804 fn on_reset(
805 &mut self,
806 code: ResetCode,
807 ) -> std::result::Result<(), Self::Error>;
808}
809
810#[derive(Debug)]
811pub enum DispatchError<E> {
812 Transport(Error),
813 Handler(E),
814}
815
816impl<E> From<Error> for DispatchError<E> {
817 fn from(value: Error) -> Self {
818 Self::Transport(value)
819 }
820}
821
822fn dispatch<H: FlowHandler>(
823 consumer: &mut Consumer,
824 handler: &mut H,
825) -> std::result::Result<(), DispatchError<H::Error>> {
826 match consumer.next()? {
827 FlowEvent::Start { metadata } => handler.on_start(metadata),
828 FlowEvent::Data(chunk) => handler.on_data(chunk),
829 FlowEvent::Fin => handler.on_fin(),
830 FlowEvent::Reset(code) => handler.on_reset(code),
831 }
832 .map_err(DispatchError::Handler)
833}
834
835pub struct Sender(Producer);
837
838impl Sender {
839 pub fn id(&self) -> ExchangeId {
840 self.0.id()
841 }
842
843 pub fn flow(&self) -> Flow {
844 self.0.flow
845 }
846
847 pub fn chunk_geometry(&self) -> ChunkGeometry {
849 self.0.arena.chunk_geometry()
850 }
851
852 pub fn plan_chunks(
854 &self,
855 data_bytes: usize,
856 ) -> Result<ChunkPlan> {
857 self.0.arena.plan_chunks(data_bytes)
858 }
859
860 pub fn plan_chunks_with(
862 &self,
863 data_bytes: usize,
864 slots_per_chunk: usize,
865 ) -> Result<ChunkPlan> {
866 self.0.arena.plan_chunks_with(data_bytes, slots_per_chunk)
867 }
868 pub fn start(
869 &mut self,
870 metadata: Option<&[u8]>,
871 ) -> Result<()> {
872 self.0.start(metadata)
873 }
874
875 pub fn reserve_start(
878 &mut self,
879 payload_len: usize,
880 ) -> Result<PendingStart<'_>> {
881 self.0.reserve_start(payload_len)
882 }
883
884 pub fn data(
885 &mut self,
886 payload: &[u8],
887 ) -> Result<ChunkDescriptor> {
888 self.0.data(payload)
889 }
890
891 pub fn reserve_data(
894 &mut self,
895 payload_len: usize,
896 ) -> Result<PendingData<'_>> {
897 self.0.reserve_data(payload_len)
898 }
899
900 pub fn finish(&mut self) -> Result<()> {
901 self.0.finish()
902 }
903
904 pub fn reset(
905 &mut self,
906 code: ResetCode,
907 ) -> Result<()> {
908 self.0.reset(code)
909 }
910
911 pub fn wait_writable(&self) -> Result<()> {
912 self.0.control.wait_writable_exact(CONTROL_FRAME_BYTES)
913 }
914
915 pub fn poll_writable(
916 &self,
917 cx: &mut std::task::Context<'_>,
918 ) -> std::task::Poll<Result<()>> {
919 self.0.control.poll_writable_exact(CONTROL_FRAME_BYTES, cx)
920 }
921
922 pub fn wait_ready(
925 &self,
926 payload_len: usize,
927 ) -> Result<()> {
928 self.0.control.wait_writable_exact(CONTROL_FRAME_BYTES)?;
929 if payload_len != 0 {
930 self.0.arena.wait_available(payload_len)?;
931 }
932 Ok(())
933 }
934
935 pub fn poll_ready(
938 &self,
939 payload_len: usize,
940 cx: &mut std::task::Context<'_>,
941 ) -> std::task::Poll<Result<()>> {
942 let control =
943 self.0.control.poll_writable_exact(CONTROL_FRAME_BYTES, cx);
944 let payload = if payload_len == 0 {
945 std::task::Poll::Ready(Ok(()))
946 } else {
947 self.0.arena.poll_available(payload_len, cx)
948 };
949 match (control, payload) {
950 (std::task::Poll::Ready(Err(error)), _)
951 | (_, std::task::Poll::Ready(Err(error))) => {
952 std::task::Poll::Ready(Err(error))
953 }
954 (
955 std::task::Poll::Ready(Ok(())),
956 std::task::Poll::Ready(Ok(())),
957 ) => std::task::Poll::Ready(Ok(())),
958 _ => std::task::Poll::Pending,
959 }
960 }
961}
962
963pub struct Receiver(Consumer);
965
966impl Receiver {
967 pub fn id(&self) -> ExchangeId {
968 self.0.id()
969 }
970
971 pub fn flow(&self) -> Flow {
972 self.0.flow
973 }
974
975 pub fn try_next(&mut self) -> Result<FlowEvent> {
976 self.0.next()
977 }
978
979 pub fn dispatch<H: FlowHandler>(
980 &mut self,
981 handler: &mut H,
982 ) -> std::result::Result<(), DispatchError<H::Error>> {
983 dispatch(&mut self.0, handler)
984 }
985
986 pub fn wait_readable(&self) -> Result<()> {
987 self.0.control.wait_readable()
988 }
989
990 pub fn poll_readable(
991 &self,
992 cx: &mut std::task::Context<'_>,
993 ) -> std::task::Poll<Result<()>> {
994 self.0.control.poll_readable(cx)
995 }
996}
997
998#[cfg(test)]
999mod tests {
1000 use super::*;
1001
1002 fn exchanges() -> Exchanges {
1003 Exchanges::open(
1004 Arc::new(Fleet::join("exchange-pair-test", 2).expect("fleet")),
1005 Incarnation::new(1),
1006 ExchangeSpec::new(
1007 StreamSpec::new(230, 8, 512),
1008 PayloadArenaSpec::new(231, 8, 64),
1009 ),
1010 )
1011 .expect("exchanges")
1012 }
1013
1014 #[test]
1015 fn peer_can_send_before_the_first_flow_finishes() {
1016 let exchanges = exchanges();
1017 let (server, ticket) = exchanges.create().expect("server");
1018 let client = exchanges.open_peer(ticket).expect("client");
1019 let (mut request_out, mut response_in) = server.split();
1020 let (mut response_out, mut request_in) = client.split();
1021
1022 request_out.start(Some(b"request-head")).expect("request start");
1023 let request_descriptor =
1024 request_out.data(&[7_u8; 192]).expect("request data");
1025 let request_metadata =
1026 match request_in.try_next().expect("request start event") {
1027 FlowEvent::Start { metadata: Some(metadata) } => metadata,
1028 _ => panic!("expected request start"),
1029 };
1030 assert_eq!(&*request_metadata, b"request-head");
1031 let request_chunk =
1032 match request_in.try_next().expect("request data event") {
1033 FlowEvent::Data(chunk) => chunk,
1034 _ => panic!("expected request data"),
1035 };
1036 assert_eq!(request_descriptor.arena_kind(), 231);
1037 assert_eq!(request_descriptor.slot_count(), 3);
1038
1039 response_out
1042 .start(Some(b"response-head"))
1043 .expect("early response start");
1044 let response_descriptor =
1045 response_out.data(b"response").expect("response data");
1046 assert_eq!(response_descriptor.arena_kind(), 231);
1047 assert!(matches!(response_in.try_next(), Ok(FlowEvent::Start { .. })));
1048 let response_chunk =
1049 match response_in.try_next().expect("response data event") {
1050 FlowEvent::Data(chunk) => chunk,
1051 _ => panic!("expected response data"),
1052 };
1053 assert_eq!(&*response_chunk, b"response");
1054
1055 drop(request_chunk);
1056 request_out.finish().expect("request fin");
1057 assert!(matches!(request_in.try_next(), Ok(FlowEvent::Fin)));
1058 response_out.finish().expect("response fin");
1059 assert!(matches!(response_in.try_next(), Ok(FlowEvent::Fin)));
1060 }
1061
1062 #[test]
1063 fn directional_payloads_keep_each_flows_credit_and_kind_separate() {
1064 let exchanges = Exchanges::open(
1065 Arc::new(
1066 Fleet::join("exchange-directional-test", 2).expect("fleet"),
1067 ),
1068 Incarnation::new(1),
1069 ExchangeSpec::directional(
1070 StreamSpec::new(220, 8, 512),
1071 PayloadArenaSpec::new(221, 1, 64),
1072 PayloadArenaSpec::new(222, 1, 128),
1073 ),
1074 )
1075 .expect("directional exchanges");
1076 let (mut side_a, ticket) = exchanges.create().expect("side A");
1077 let mut side_b = exchanges.open_peer(ticket).expect("side B");
1078
1079 let request_geometry = side_a.sender().chunk_geometry();
1080 let response_geometry = side_b.sender().chunk_geometry();
1081 assert_eq!(request_geometry.slot_payload_bytes(), 64);
1082 assert_eq!(response_geometry.slot_payload_bytes(), 128);
1083 assert_eq!(request_geometry.chunk_bytes(1), Some(64));
1084 assert_eq!(response_geometry.chunk_bytes(1), Some(128));
1085
1086 side_a.sender().start(None).expect("A-to-B start");
1087 assert!(matches!(
1088 side_b.receiver().try_next(),
1089 Ok(FlowEvent::Start { .. })
1090 ));
1091 side_b.sender().start(None).expect("B-to-A start");
1092 assert!(matches!(
1093 side_a.receiver().try_next(),
1094 Ok(FlowEvent::Start { .. })
1095 ));
1096
1097 let a = side_a.sender().data(&[1; 64]).expect("A-to-B payload");
1098 let b = side_b.sender().data(&[2; 128]).expect("B-to-A payload");
1099 assert_eq!(a.arena_kind(), 221);
1100 assert_eq!(b.arena_kind(), 222);
1101
1102 let a_payload = match side_b.receiver().try_next().expect("A-to-B data")
1103 {
1104 FlowEvent::Data(chunk) => chunk,
1105 _ => panic!("expected A-to-B data"),
1106 };
1107 let b_payload = match side_a.receiver().try_next().expect("B-to-A data")
1108 {
1109 FlowEvent::Data(chunk) => chunk,
1110 _ => panic!("expected B-to-A data"),
1111 };
1112 assert_eq!(&*a_payload, &[1; 64]);
1113 assert_eq!(&*b_payload, &[2; 128]);
1114 }
1115
1116 #[test]
1117 fn a_reserved_chunk_is_one_descriptor_over_many_slots() {
1118 let exchanges = Exchanges::open(
1119 Arc::new(
1120 Fleet::join("exchange-reservation-test", 2).expect("fleet"),
1121 ),
1122 Incarnation::new(1),
1123 ExchangeSpec::new(
1124 StreamSpec::new(233, 8, 512),
1125 PayloadArenaSpec::new(234, 8, 256),
1126 ),
1127 )
1128 .expect("exchanges");
1129 let (mut server, ticket) = exchanges.create().expect("server");
1130 let mut client = exchanges.open_peer(ticket).expect("client");
1131
1132 let expected: Vec<u8> =
1133 (0..777).map(|index| (index % 251) as u8).collect();
1134 let descriptor = {
1135 let mut pending =
1136 server.sender().reserve_start(expected.len()).expect("reserve");
1137 pending.copy_from_slice(&expected);
1138 pending.commit().expect("commit")
1139 };
1140 assert_eq!(descriptor.payload_len(), 777);
1141 assert_eq!(descriptor.slot_count(), 4);
1142 let received = match client.receiver().try_next().expect("start") {
1143 FlowEvent::Start { metadata: Some(metadata) } => metadata,
1144 _ => panic!("expected start metadata"),
1145 };
1146 assert_eq!(&*received, expected);
1147 }
1148
1149 #[test]
1150 fn dropping_an_uncommitted_chunk_returns_credit_without_an_event() {
1151 let exchanges = exchanges();
1152 let (mut server, ticket) = exchanges.create().expect("server");
1153 let mut client = exchanges.open_peer(ticket).expect("client");
1154 server.sender().start(None).expect("start");
1155 assert!(matches!(
1156 client.receiver().try_next(),
1157 Ok(FlowEvent::Start { metadata: None })
1158 ));
1159
1160 let pending =
1161 server.sender().reserve_data(256).expect("reserve all slots");
1162 drop(pending);
1163 assert!(matches!(client.receiver().try_next(), Err(Error::WouldBlock)));
1164 assert!(server.sender().reserve_data(256).is_ok());
1165 }
1166
1167 #[test]
1168 fn a_failed_control_commit_returns_its_payload_credit() {
1169 let exchanges = Exchanges::open(
1170 Arc::new(
1171 Fleet::join("exchange-failed-commit-test", 2).expect("fleet"),
1172 ),
1173 Incarnation::new(1),
1174 ExchangeSpec::new(
1175 StreamSpec::new(236, 8, CONTROL_FRAME_BYTES),
1176 PayloadArenaSpec::new(237, 1, 64),
1177 ),
1178 )
1179 .expect("exchanges");
1180 let (mut server, ticket) = exchanges.create().expect("server");
1181 let mut client = exchanges.open_peer(ticket).expect("client");
1182
1183 server.sender().start(None).expect("start fills control ring");
1184 let mut pending = server
1185 .sender()
1186 .reserve_data(64)
1187 .expect("reserve only payload slot");
1188 pending.fill(7);
1189 assert!(matches!(pending.commit(), Err(Error::WouldBlock)));
1190
1191 assert!(matches!(
1192 client.receiver().try_next(),
1193 Ok(FlowEvent::Start { metadata: None })
1194 ));
1195 let mut retry = server
1196 .sender()
1197 .reserve_data(64)
1198 .expect("failed commit returned credit");
1199 retry.fill(9);
1200 retry.commit().expect("retry commit");
1201 let received = match client.receiver().try_next().expect("retry data") {
1202 FlowEvent::Data(chunk) => chunk,
1203 _ => panic!("expected retry data"),
1204 };
1205 assert_eq!(&*received, &[9; 64]);
1206 }
1207
1208 #[test]
1209 fn a_short_io_commit_returns_unused_trailing_slots() {
1210 let exchanges = exchanges();
1211 let (mut server, ticket) = exchanges.create().expect("server");
1212 let mut client = exchanges.open_peer(ticket).expect("client");
1213 server.sender().start(None).expect("start");
1214 assert!(matches!(
1215 client.receiver().try_next(),
1216 Ok(FlowEvent::Start { metadata: None })
1217 ));
1218
1219 let descriptor = {
1220 let mut pending =
1221 server.sender().reserve_data(256).expect("reserve IO capacity");
1222 pending[..37].fill(5);
1223 pending.commit_len(37).expect("commit bytes read")
1224 };
1225 assert_eq!(descriptor.payload_len(), 37);
1226 assert_eq!(descriptor.slot_count(), 1);
1227
1228 let mut following =
1229 server.sender().reserve_data(192).expect("trailing slots returned");
1230 following.fill(9);
1231 following.commit().expect("commit following chunk");
1232 let first = match client.receiver().try_next().expect("short data") {
1233 FlowEvent::Data(chunk) => chunk,
1234 _ => panic!("expected short data"),
1235 };
1236 assert_eq!(&*first, &[5; 37]);
1237 let second = match client.receiver().try_next().expect("following data")
1238 {
1239 FlowEvent::Data(chunk) => chunk,
1240 _ => panic!("expected following data"),
1241 };
1242 assert_eq!(&*second, &[9; 192]);
1243 }
1244
1245 #[test]
1246 fn reset_is_terminal_for_only_its_own_flow() {
1247 let exchanges = exchanges();
1248 let (server, ticket) = exchanges.create().expect("server");
1249 let client = exchanges.open_peer(ticket).expect("client");
1250 let (mut request_out, mut response_in) = server.split();
1251 let (mut response_out, mut request_in) = client.split();
1252
1253 request_out.reset(ResetCode::new(41)).expect("request reset");
1254 assert!(matches!(
1255 request_in.try_next(),
1256 Ok(FlowEvent::Reset(code)) if code.get() == 41
1257 ));
1258
1259 response_out.start(None).expect("response remains independent");
1260 assert!(matches!(
1261 response_in.try_next(),
1262 Ok(FlowEvent::Start { metadata: None })
1263 ));
1264 }
1265}