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