interchange/lib.rs
1#![cfg_attr(not(test), no_std)]
2//! Implement a somewhat convenient and somewhat efficient way to perform RPC
3//! in an embedded context.
4//!
5//! The approach is inspired by Go's channels, with the restriction that
6//! there is a clear separation into a requester and a responder.
7//!
8//! Requests may be canceled, which the responder should honour on a
9//! best-effort basis.
10//!
11//! ### Example use cases
12//! - USB device interrupt handler performs low-level protocol details, hands off
13//! commands from the host to higher-level logic running in the idle thread.
14//! This higher-level logic need only understand clearly typed commands, as
15//! moduled by variants of a given `Request` enum.
16//! - `trussed` crypto service, responding to crypto request from apps across
17//! TrustZone for Cortex-M secure/non-secure boundaries.
18//! - Request to blink a few lights and reply on button press
19//!
20//!
21//! ### Approach
22//! It is assumed that all requests fit in a single `Request` enum, and that
23//! all responses fit in single `Response` enum. The [`Channel`]() and [`Interchange`]() structs allocate a single buffer in which either Request or Response fit and handle synchronization
24//! Both structures have `const` constructors, allowing them to be statically allocated.
25//!
26//! An alternative approach would be to use two heapless Queues of length one
27//! each for response and requests. The advantage of our construction is to
28//! have only one static memory region in use.
29//!
30//! ```
31//! # #![cfg(not(loom))]
32//! # use interchange::{State, Interchange};
33//! #[derive(Clone, Debug, PartialEq)]
34//! pub enum Request {
35//! This(u8, u32),
36//! That(i64),
37//! }
38//!
39//! #[derive(Clone, Debug, PartialEq)]
40//! pub enum Response {
41//! Here(u8, u8, u8),
42//! There(i16),
43//! }
44//!
45//! static INTERCHANGE: Interchange<Request, Response, 1> = Interchange::new();
46//!
47//! let (mut rq, mut rp) = INTERCHANGE.claim().unwrap();
48//!
49//! assert!(rq.state() == State::Idle);
50//!
51//! // happy path: no cancelation
52//! let request = Request::This(1, 2);
53//! assert!(rq.request(request).is_ok());
54//!
55//! let request = rp.take_request().unwrap();
56//! println!("rp got request: {:?}", request);
57//!
58//! let response = Response::There(-1);
59//! assert!(!rp.is_canceled());
60//! assert!(rp.respond(response).is_ok());
61//!
62//! let response = rq.take_response().unwrap();
63//! println!("rq got response: {:?}", response);
64//!
65//! // early cancelation path
66//! assert!(rq.request(request).is_ok());
67//!
68//! let request = rq.cancel().unwrap().unwrap();
69//! println!("responder could cancel: {:?}", request);
70//!
71//! assert!(rp.take_request().is_none());
72//! assert!(State::Idle == rq.state());
73//!
74//! // late cancelation
75//! assert!(rq.request(request).is_ok());
76//! let request = rp.take_request().unwrap();
77//!
78//! println!("responder could cancel: {:?}", rq.cancel().unwrap().is_none());
79//! assert!(rp.is_canceled());
80//! assert!(rp.respond(response).is_err());
81//! assert!(rp.acknowledge_cancel().is_ok());
82//! assert!(State::Idle == rq.state());
83//!
84//! // building into request buffer
85//! impl Default for Request {
86//! fn default() -> Self {
87//! Request::That(0)
88//! }
89//! }
90//!
91//! rq.with_request_mut(|r| *r = Request::This(1,2)).unwrap() ;
92//! assert!(rq.send_request().is_ok());
93//! let request = rp.take_request().unwrap();
94//! assert_eq!(request, Request::This(1, 2));
95//! println!("rp got request: {:?}", request);
96//!
97//! // building into response buffer
98//! impl Default for Response {
99//! fn default() -> Self {
100//! Response::There(1)
101//! }
102//! }
103//!
104//! rp.with_response_mut(|r| *r = Response::Here(3,2,1)).unwrap();
105//! assert!(rp.send_response().is_ok());
106//! let response = rq.take_response().unwrap();
107//! assert_eq!(response, Response::Here(3,2,1));
108//!
109//! ```
110
111use core::fmt::{self, Debug};
112use core::sync::atomic::Ordering;
113
114#[cfg(loom)]
115use loom::{
116 cell::UnsafeCell,
117 sync::atomic::{AtomicBool, AtomicU8, AtomicUsize},
118};
119
120#[cfg(not(loom))]
121use core::{
122 cell::UnsafeCell,
123 sync::atomic::{AtomicBool, AtomicU8, AtomicUsize},
124};
125
126#[derive(Clone, Copy)]
127pub struct Error;
128
129impl Debug for Error {
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
131 f.write_str("The interchange is busy, this operation could not be performed")
132 }
133}
134
135#[repr(u8)]
136#[derive(Copy, Clone, Debug, Eq, PartialEq)]
137/// State of the RPC interchange
138pub enum State {
139 /// The requester may send a new request.
140 Idle = 0,
141 /// The requester is building a request, using the pre-allocated static data as &mut Request
142 BuildingRequest = 1,
143 /// The request is pending either processing by responder or cancelation by requester.
144 Requested = 2,
145 /// The responder is building a response, using the pre-allocated static data as &mut Response
146 /// It may opportunitstically be canceled by requester.
147 BuildingResponse = 3,
148 /// The responder sent a response.
149 Responded = 4,
150
151 Canceled = 12,
152}
153
154impl PartialEq<u8> for State {
155 #[inline]
156 fn eq(&self, other: &u8) -> bool {
157 *self as u8 == *other
158 }
159}
160
161impl From<u8> for State {
162 fn from(byte: u8) -> Self {
163 match byte {
164 1 => State::BuildingRequest,
165 2 => State::Requested,
166 3 => State::BuildingResponse,
167 4 => State::Responded,
168 12 => State::Canceled,
169 _ => State::Idle,
170 }
171 }
172}
173
174/// Callback that can be called
175pub type Callback = fn();
176
177// the repr(u8) is necessary so MaybeUninit::zeroized.assume_init() is valid and corresponds to
178// None
179#[repr(u8)]
180enum Message<Rq, Rp> {
181 None,
182 Request(Rq),
183 Response(Rp),
184}
185
186impl<Rq, Rp> Message<Rq, Rp> {
187 fn is_request_state(&self) -> bool {
188 matches!(self, Self::Request(_))
189 }
190
191 fn is_response_state(&self) -> bool {
192 matches!(self, Self::Response(_))
193 }
194
195 fn take_rq(&mut self) -> Rq {
196 let this = core::mem::replace(self, Message::None);
197 match this {
198 Message::Request(r) => r,
199 _ => unreachable!(),
200 }
201 }
202
203 fn rq_ref(&self) -> &Rq {
204 match *self {
205 Self::Request(ref request) => request,
206 _ => unreachable!(),
207 }
208 }
209
210 fn rq_mut(&mut self) -> &mut Rq {
211 match *self {
212 Self::Request(ref mut request) => request,
213 _ => unreachable!(),
214 }
215 }
216
217 fn take_rp(&mut self) -> Rp {
218 let this = core::mem::replace(self, Message::None);
219 match this {
220 Message::Response(r) => r,
221 _ => unreachable!(),
222 }
223 }
224
225 fn rp_ref(&self) -> &Rp {
226 match *self {
227 Self::Response(ref response) => response,
228 _ => unreachable!(),
229 }
230 }
231
232 fn rp_mut(&mut self) -> &mut Rp {
233 match *self {
234 Self::Response(ref mut response) => response,
235 _ => unreachable!(),
236 }
237 }
238
239 fn from_rq(rq: Rq) -> Self {
240 Self::Request(rq)
241 }
242
243 fn from_rp(rp: Rp) -> Self {
244 Self::Response(rp)
245 }
246}
247
248/// Channel used for Request/Response mechanism.
249/// ```
250/// # #![cfg(not(loom))]
251/// # use interchange::{State, Channel};
252/// #[derive(Clone, Debug, PartialEq)]
253/// pub enum Request {
254/// This(u8, u32),
255/// That(i64),
256/// }
257///
258/// #[derive(Clone, Debug, PartialEq)]
259/// pub enum Response {
260/// Here(u8, u8, u8),
261/// There(i16),
262/// }
263///
264/// static CHANNEL: Channel<Request,Response> = Channel::new();
265///
266/// let (mut rq, mut rp) = CHANNEL.split().unwrap();
267///
268/// assert!(rq.state() == State::Idle);
269///
270/// // happy path: no cancelation
271/// let request = Request::This(1, 2);
272/// assert!(rq.request(request).is_ok());
273///
274/// let request = rp.take_request().unwrap();
275/// println!("rp got request: {:?}", request);
276///
277/// let response = Response::There(-1);
278/// assert!(!rp.is_canceled());
279/// assert!(rp.respond(response).is_ok());
280///
281/// let response = rq.take_response().unwrap();
282/// println!("rq got response: {:?}", response);
283///
284/// // early cancelation path
285/// assert!(rq.request(request).is_ok());
286///
287/// let request = rq.cancel().unwrap().unwrap();
288/// println!("responder could cancel: {:?}", request);
289///
290/// assert!(rp.take_request().is_none());
291/// assert!(State::Idle == rq.state());
292///
293/// // late cancelation
294/// assert!(rq.request(request).is_ok());
295/// let request = rp.take_request().unwrap();
296///
297/// println!("responder could cancel: {:?}", rq.cancel().unwrap().is_none());
298/// assert!(rp.is_canceled());
299/// assert!(rp.respond(response).is_err());
300/// assert!(rp.acknowledge_cancel().is_ok());
301/// assert!(State::Idle == rq.state());
302///
303/// // building into request buffer
304/// impl Default for Request {
305/// fn default() -> Self {
306/// Request::That(0)
307/// }
308/// }
309///
310/// rq.with_request_mut(|r| *r = Request::This(1,2)).unwrap() ;
311/// assert!(rq.send_request().is_ok());
312/// let request = rp.take_request().unwrap();
313/// assert_eq!(request, Request::This(1, 2));
314/// println!("rp got request: {:?}", request);
315///
316/// // building into response buffer
317/// impl Default for Response {
318/// fn default() -> Self {
319/// Response::There(1)
320/// }
321/// }
322///
323/// rp.with_response_mut(|r| *r = Response::Here(3,2,1)).unwrap();
324/// assert!(rp.send_response().is_ok());
325/// let response = rq.take_response().unwrap();
326/// assert_eq!(response, Response::Here(3,2,1));
327///
328/// ```
329pub struct Channel<Rq, Rp> {
330 data: UnsafeCell<Message<Rq, Rp>>,
331 state: AtomicU8,
332 requester_claimed: AtomicBool,
333 responder_claimed: AtomicBool,
334}
335
336impl<Rq, Rp> Channel<Rq, Rp> {
337 // Loom's atomics are not const :/
338 #[cfg(not(loom))]
339 pub const fn new() -> Self {
340 Self {
341 data: UnsafeCell::new(Message::None),
342 state: AtomicU8::new(0),
343 requester_claimed: AtomicBool::new(false),
344 responder_claimed: AtomicBool::new(false),
345 }
346 }
347
348 #[cfg(loom)]
349 pub fn new() -> Self {
350 Self {
351 data: UnsafeCell::new(Message::None),
352 state: AtomicU8::new(0),
353 requester_claimed: AtomicBool::new(false),
354 responder_claimed: AtomicBool::new(false),
355 }
356 }
357
358 /// Obtain the requester end of the channel if it hasn't been taken yet.
359 ///
360 /// Can be called again if the previously obtained [`Requester`]() has been dropped
361 pub fn requester(&self) -> Option<Requester<'_, Rq, Rp>> {
362 if self
363 .requester_claimed
364 .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
365 .is_ok()
366 {
367 Some(Requester {
368 channel: self,
369 callback: || {},
370 })
371 } else {
372 None
373 }
374 }
375
376 /// Obtain the responder end of the channel if it hasn't been taken yet.
377 ///
378 /// Can be called again if the previously obtained [`Responder`]() has been dropped
379 pub fn responder(&self) -> Option<Responder<'_, Rq, Rp>> {
380 if self
381 .responder_claimed
382 .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
383 .is_ok()
384 {
385 Some(Responder {
386 channel: self,
387 callback: || {},
388 })
389 } else {
390 None
391 }
392 }
393
394 /// Obtain both the requester and responder ends of the channel.
395 ///
396 /// Can be called again if the previously obtained [`Responder`]() and [`Requester`]() have been dropped
397 pub fn split(&self) -> Option<(Requester<'_, Rq, Rp>, Responder<'_, Rq, Rp>)> {
398 Some((self.requester()?, self.responder()?))
399 }
400
401 fn transition(&self, from: State, to: State) -> bool {
402 self.state
403 .compare_exchange(from as u8, to as u8, Ordering::AcqRel, Ordering::Relaxed)
404 .is_ok()
405 }
406}
407
408impl<Rq, Rp> Default for Channel<Rq, Rp> {
409 fn default() -> Self {
410 Self::new()
411 }
412}
413
414/// Requester end of a channel
415///
416/// For a `static` [`Channel`]() or [`Interchange`](),
417/// the requester uses a `'static` lifetime parameter
418pub struct Requester<'i, Rq, Rp> {
419 channel: &'i Channel<Rq, Rp>,
420 callback: Callback,
421}
422
423impl<Rq, Rp> Drop for Requester<'_, Rq, Rp> {
424 fn drop(&mut self) {
425 self.channel
426 .requester_claimed
427 .store(false, Ordering::Release);
428 }
429}
430
431impl<'i, Rq, Rp> Requester<'i, Rq, Rp> {
432 /// Allows to set a callback that is called when a request has been sent and when a request
433 /// has been cancelled before it was taken by the responder.
434 ///
435 /// The callback is called by [`Requester::request`][], [`Requester::send_request`][] and
436 /// [`Requester::cancel`][].
437 pub fn callback_mut(&mut self) -> &mut Callback {
438 &mut self.callback
439 }
440
441 pub fn channel(&self) -> &'i Channel<Rq, Rp> {
442 self.channel
443 }
444
445 #[cfg(not(loom))]
446 unsafe fn data(&self) -> &Message<Rq, Rp> {
447 &mut *self.channel.data.get()
448 }
449
450 #[cfg(not(loom))]
451 unsafe fn data_mut(&mut self) -> &mut Message<Rq, Rp> {
452 &mut *self.channel.data.get()
453 }
454
455 #[cfg(not(loom))]
456 unsafe fn with_data<R>(&self, f: impl FnOnce(&Message<Rq, Rp>) -> R) -> R {
457 f(&*self.channel.data.get())
458 }
459
460 #[cfg(not(loom))]
461 unsafe fn with_data_mut<R>(&mut self, f: impl FnOnce(&mut Message<Rq, Rp>) -> R) -> R {
462 f(&mut *self.channel.data.get())
463 }
464
465 #[cfg(loom)]
466 unsafe fn with_data<R>(&self, f: impl FnOnce(&Message<Rq, Rp>) -> R) -> R {
467 self.channel.data.with(|i| f(&*i))
468 }
469
470 #[cfg(loom)]
471 unsafe fn with_data_mut<R>(&mut self, f: impl FnOnce(&mut Message<Rq, Rp>) -> R) -> R {
472 self.channel.data.with_mut(|i| f(&mut *i))
473 }
474
475 #[inline]
476 /// Current state of the channel.
477 ///
478 /// Informational only!
479 ///
480 /// The responder may change this state between calls,
481 /// internally atomics ensure correctness.
482 pub fn state(&self) -> State {
483 State::from(self.channel.state.load(Ordering::Acquire))
484 }
485
486 /// Send a request to the responder.
487 ///
488 /// If efficiency is a concern, or requests need multiple steps to
489 /// construct, use `request_mut` and `send_request`.
490 ///
491 /// If the RPC state is `Idle`, this always succeeds, else calling
492 /// is a logic error and the request is returned.
493 ///
494 /// If the request has been sent succesfully, this functions calls the callback set with
495 /// [`Requester::callback_mut`][].
496 pub fn request(&mut self, request: Rq) -> Result<(), Error> {
497 if State::Idle == self.channel.state.load(Ordering::Acquire) {
498 unsafe {
499 self.with_data_mut(|i| *i = Message::from_rq(request));
500 }
501 self.channel
502 .state
503 .store(State::Requested as u8, Ordering::Release);
504 (self.callback)();
505 Ok(())
506 } else {
507 Err(Error)
508 }
509 }
510
511 /// Attempt to cancel a request.
512 ///
513 /// If the responder has not taken the request yet, this succeeds and returns
514 /// the request.
515 ///
516 /// If the responder has taken the request (is processing), we succeed and return None.
517 ///
518 /// In other cases (`Idle` or `Reponsed`) there is nothing to cancel and we fail.
519 ///
520 /// If the responder has not taken the request yet, this functions calls the callback set
521 /// with [`Requester::callback_mut`][].
522 pub fn cancel(&mut self) -> Result<Option<Rq>, Error> {
523 if self
524 .channel
525 .transition(State::BuildingResponse, State::Canceled)
526 {
527 // we canceled after the responder took the request, but before they answered.
528 return Ok(None);
529 }
530
531 if self.channel.transition(State::Requested, State::Idle) {
532 (self.callback)();
533 // we canceled before the responder was even aware of the request.
534 return Ok(Some(unsafe { self.with_data_mut(|i| i.take_rq()) }));
535 }
536
537 Err(Error)
538 }
539
540 /// If there is a response waiting, obtain a reference to it
541 ///
542 /// This may be called multiple times.
543 // Safety: We cannot test this with loom efficiently, but given that `with_response` is tested,
544 // this is likely correct
545 #[cfg(not(loom))]
546 pub fn response(&self) -> Result<&Rp, Error> {
547 if self.channel.transition(State::Responded, State::Responded) {
548 Ok(unsafe { self.data().rp_ref() })
549 } else {
550 Err(Error)
551 }
552 }
553
554 /// If there is a request waiting, perform an operation with a reference to it
555 ///
556 /// This may be called multiple times.
557 pub fn with_response<R>(&self, f: impl FnOnce(&Rp) -> R) -> Result<R, Error> {
558 if self.channel.transition(State::Responded, State::Responded) {
559 Ok(unsafe { self.with_data(|i| f(i.rp_ref())) })
560 } else {
561 Err(Error)
562 }
563 }
564
565 /// Look for a response.
566 /// If the responder has sent a response, we return it.
567 ///
568 /// This may be called only once as it move the state to Idle.
569 /// If you need copies, clone the request.
570 // It is a logic error to call this method if we're Idle or Canceled, but
571 // it seems unnecessary to model this.
572 pub fn take_response(&mut self) -> Option<Rp> {
573 if self.channel.transition(State::Responded, State::Idle) {
574 Some(unsafe { self.with_data_mut(|i| i.take_rp()) })
575 } else {
576 None
577 }
578 }
579}
580
581impl<Rq, Rp> Requester<'_, Rq, Rp>
582where
583 Rq: Default,
584{
585 /// Initialize a request with its default values and mutates it with `f`
586 ///
587 /// This is usefull to build large structures in-place
588 pub fn with_request_mut<R>(&mut self, f: impl FnOnce(&mut Rq) -> R) -> Result<R, Error> {
589 if self.channel.transition(State::Idle, State::BuildingRequest)
590 || self
591 .channel
592 .transition(State::BuildingRequest, State::BuildingRequest)
593 {
594 let res = unsafe {
595 self.with_data_mut(|i| {
596 if !i.is_request_state() {
597 *i = Message::from_rq(Rq::default());
598 }
599 f(i.rq_mut())
600 })
601 };
602 Ok(res)
603 } else {
604 Err(Error)
605 }
606 }
607
608 /// Initialize a request with its default values and and return a mutable reference to it
609 ///
610 /// This is usefull to build large structures in-place
611 // Safety: We cannot test this with loom efficiently, but given that `with_request_mut` is tested,
612 // this is likely correct
613 #[cfg(not(loom))]
614 pub fn request_mut(&mut self) -> Result<&mut Rq, Error> {
615 if self.channel.transition(State::Idle, State::BuildingRequest)
616 || self
617 .channel
618 .transition(State::BuildingRequest, State::BuildingRequest)
619 {
620 unsafe {
621 self.with_data_mut(|i| {
622 if !i.is_request_state() {
623 *i = Message::from_rq(Rq::default());
624 }
625 })
626 }
627 Ok(unsafe { self.data_mut().rq_mut() })
628 } else {
629 Err(Error)
630 }
631 }
632
633 /// Send a request that was already placed in the channel using `request_mut` or
634 /// `with_request_mut`.
635 ///
636 /// If the request has been sent succesfully, this functions calls the callback set with
637 /// [`Requester::callback_mut`][].
638 pub fn send_request(&mut self) -> Result<(), Error> {
639 if State::BuildingRequest == self.channel.state.load(Ordering::Acquire)
640 && self
641 .channel
642 .transition(State::BuildingRequest, State::Requested)
643 {
644 (self.callback)();
645 Ok(())
646 } else {
647 // logic error
648 Err(Error)
649 }
650 }
651}
652
653/// Responder end of a channel
654///
655/// For a `static` [`Channel`]() or [`Interchange`](),
656/// the responder uses a `'static` lifetime parameter
657pub struct Responder<'i, Rq, Rp> {
658 channel: &'i Channel<Rq, Rp>,
659 callback: Callback,
660}
661
662impl<Rq, Rp> Drop for Responder<'_, Rq, Rp> {
663 fn drop(&mut self) {
664 self.channel
665 .responder_claimed
666 .store(false, Ordering::Release);
667 }
668}
669
670impl<'i, Rq, Rp> Responder<'i, Rq, Rp> {
671 /// Allows to set a callback that is called when a response has been sent.
672 ///
673 /// The callback is called by [`Responder::respond`][] and [`Responder::send_response`][].
674 pub fn callback_mut(&mut self) -> &mut Callback {
675 &mut self.callback
676 }
677
678 pub fn channel(&self) -> &'i Channel<Rq, Rp> {
679 self.channel
680 }
681
682 #[cfg(not(loom))]
683 unsafe fn data(&self) -> &Message<Rq, Rp> {
684 &mut *self.channel.data.get()
685 }
686
687 #[cfg(not(loom))]
688 unsafe fn data_mut(&mut self) -> &mut Message<Rq, Rp> {
689 &mut *self.channel.data.get()
690 }
691
692 #[cfg(not(loom))]
693 unsafe fn with_data<R>(&self, f: impl FnOnce(&Message<Rq, Rp>) -> R) -> R {
694 f(&*self.channel.data.get())
695 }
696
697 #[cfg(not(loom))]
698 unsafe fn with_data_mut<R>(&mut self, f: impl FnOnce(&mut Message<Rq, Rp>) -> R) -> R {
699 f(&mut *self.channel.data.get())
700 }
701
702 #[cfg(loom)]
703 unsafe fn with_data<R>(&self, f: impl FnOnce(&Message<Rq, Rp>) -> R) -> R {
704 self.channel.data.with(|i| f(&*i))
705 }
706
707 #[cfg(loom)]
708 unsafe fn with_data_mut<R>(&mut self, f: impl FnOnce(&mut Message<Rq, Rp>) -> R) -> R {
709 self.channel.data.with_mut(|i| f(&mut *i))
710 }
711
712 #[inline]
713 /// Current state of the channel.
714 ///
715 /// Informational only!
716 ///
717 /// The responder may change this state between calls,
718 /// internally atomics ensure correctness.
719 pub fn state(&self) -> State {
720 State::from(self.channel.state.load(Ordering::Acquire))
721 }
722
723 /// If there is a request waiting, perform an operation with a reference to it
724 ///
725 /// This may be called only once as it move the state to BuildingResponse.
726 /// If you need copies, use `take_request`
727 pub fn with_request<R>(&self, f: impl FnOnce(&Rq) -> R) -> Result<R, Error> {
728 if self
729 .channel
730 .transition(State::Requested, State::BuildingResponse)
731 {
732 Ok(unsafe { self.with_data(|i| f(i.rq_ref())) })
733 } else {
734 Err(Error)
735 }
736 }
737
738 /// If there is a request waiting, obtain a reference to it
739 ///
740 /// This may be called multiple times.
741 // Safety: We cannot test this with loom efficiently, but given that `with_request` is tested,
742 // this is likely correct
743 #[cfg(not(loom))]
744 pub fn request(&self) -> Result<&Rq, Error> {
745 if self
746 .channel
747 .transition(State::Requested, State::BuildingResponse)
748 {
749 Ok(unsafe { self.data().rq_ref() })
750 } else {
751 Err(Error)
752 }
753 }
754
755 /// If there is a request waiting, take a reference to it out
756 ///
757 /// This may be called only once as it move the state to BuildingResponse.
758 /// If you need copies, clone the request.
759 pub fn take_request(&mut self) -> Option<Rq> {
760 if self
761 .channel
762 .transition(State::Requested, State::BuildingResponse)
763 {
764 Some(unsafe { self.with_data_mut(|i| i.take_rq()) })
765 } else {
766 None
767 }
768 }
769
770 // Check if requester attempted to cancel
771 pub fn is_canceled(&self) -> bool {
772 self.channel.state.load(Ordering::SeqCst) == State::Canceled as u8
773 }
774
775 // Acknowledge a cancel, thereby setting Channel to Idle state again.
776 //
777 // It is a logic error to call this method if there is no pending cancellation.
778 pub fn acknowledge_cancel(&self) -> Result<(), Error> {
779 if self.channel.transition(State::Canceled, State::Idle) {
780 Ok(())
781 } else {
782 Err(Error)
783 }
784 }
785
786 /// Respond to a request.
787 ///
788 /// If efficiency is a concern, or responses need multiple steps to
789 /// construct, use `with_response_mut` or `response_mut` and `send_response`.
790 ///
791 /// If the response has been sent succesfully, this functions calls the callback set with
792 /// [`Responder::callback_mut`][].
793 pub fn respond(&mut self, response: Rp) -> Result<(), Error> {
794 if State::BuildingResponse == self.channel.state.load(Ordering::Acquire) {
795 unsafe {
796 self.with_data_mut(|i| *i = Message::from_rp(response));
797 }
798 if self
799 .channel
800 .transition(State::BuildingResponse, State::Responded)
801 {
802 (self.callback)();
803 Ok(())
804 } else {
805 Err(Error)
806 }
807 } else {
808 Err(Error)
809 }
810 }
811}
812
813impl<Rq, Rp> Responder<'_, Rq, Rp>
814where
815 Rp: Default,
816{
817 /// Initialize a response with its default values and mutates it with `f`
818 ///
819 /// This is usefull to build large structures in-place
820 pub fn with_response_mut<R>(&mut self, f: impl FnOnce(&mut Rp) -> R) -> Result<R, Error> {
821 if self
822 .channel
823 .transition(State::Requested, State::BuildingResponse)
824 || self
825 .channel
826 .transition(State::BuildingResponse, State::BuildingResponse)
827 {
828 let res = unsafe {
829 self.with_data_mut(|i| {
830 if !i.is_response_state() {
831 *i = Message::from_rp(Rp::default());
832 }
833 f(i.rp_mut())
834 })
835 };
836 Ok(res)
837 } else {
838 Err(Error)
839 }
840 }
841
842 /// Initialize a response with its default values and and return a mutable reference to it
843 ///
844 /// This is usefull to build large structures in-place
845 // Safety: We cannot test this with loom efficiently, but given that `with_response_mut` is tested,
846 // this is likely correct
847 #[cfg(not(loom))]
848 pub fn response_mut(&mut self) -> Result<&mut Rp, Error> {
849 if self
850 .channel
851 .transition(State::Requested, State::BuildingResponse)
852 || self
853 .channel
854 .transition(State::BuildingResponse, State::BuildingResponse)
855 {
856 unsafe {
857 self.with_data_mut(|i| {
858 if !i.is_response_state() {
859 *i = Message::from_rp(Rp::default());
860 }
861 })
862 }
863 Ok(unsafe { self.data_mut().rp_mut() })
864 } else {
865 Err(Error)
866 }
867 }
868
869 /// Send a response that was already placed in the channel using `response_mut` or
870 /// `with_response_mut`.
871 ///
872 /// If the response has been sent succesfully, this functions calls the callback set with
873 /// [`Responder::callback_mut`][].
874 pub fn send_response(&mut self) -> Result<(), Error> {
875 if State::BuildingResponse == self.channel.state.load(Ordering::Acquire)
876 && self
877 .channel
878 .transition(State::BuildingResponse, State::Responded)
879 {
880 (self.callback)();
881 Ok(())
882 } else {
883 // logic error
884 Err(Error)
885 }
886 }
887}
888
889// Safety: The channel can be split, which then allows getting sending the Rq and Rp types across threads
890// TODO: is the Sync bound really necessary?
891unsafe impl<Rq, Rp> Sync for Channel<Rq, Rp>
892where
893 Rq: Send + Sync,
894 Rp: Send + Sync,
895{
896}
897
898/// Set of `N` channels
899///
900/// Channels can be claimed with [`claim()`](Self::claim)
901///
902/// ```
903/// # #![cfg(not(loom))]
904/// # use interchange::*;
905/// # #[derive(Clone, Debug, PartialEq)]
906/// # pub enum Request {
907/// # This(u8, u32),
908/// # That(i64),
909/// # }
910/// #
911/// # #[derive(Clone, Debug, PartialEq)]
912/// # pub enum Response {
913/// # Here(u8, u8, u8),
914/// # There(i16),
915/// # }
916/// #
917/// static interchange: Interchange<Request, Response,10> = Interchange::new();
918///
919/// for i in 0..10 {
920/// let rq: Requester<'_, Request, Response>;
921/// let rp: Responder<'_, Request, Response>;
922/// (rq, rp) = interchange.claim().unwrap() ;
923/// }
924/// ```
925pub struct Interchange<Rq, Rp, const N: usize> {
926 channels: [Channel<Rq, Rp>; N],
927 last_claimed: AtomicUsize,
928}
929
930impl<Rq, Rp, const N: usize> Interchange<Rq, Rp, N> {
931 /// Create a new Interchange
932 #[cfg(not(loom))]
933 pub const fn new() -> Self {
934 Self {
935 channels: [const { Channel::new() }; N],
936 last_claimed: AtomicUsize::new(0),
937 }
938 }
939
940 /// Create a new Interchange
941 #[cfg(loom)]
942 pub fn new() -> Self {
943 Self {
944 channels: core::array::from_fn(|_| Channel::new()),
945 last_claimed: AtomicUsize::new(0),
946 }
947 }
948
949 /// Claim one of the channels of the interchange. Returns None if called more than `N` times.
950 pub fn claim(&'_ self) -> Option<(Requester<'_, Rq, Rp>, Responder<'_, Rq, Rp>)> {
951 self.as_interchange_ref().claim()
952 }
953
954 /// Returns a reference to the interchange with the `N` const-generic removed.
955 /// This can avoid the requirement to have `const N: usize` everywhere
956 /// ```
957 /// # #![cfg(not(loom))]
958 /// # use interchange::{State, Interchange, InterchangeRef};
959 /// # #[derive(Clone, Debug, PartialEq)]
960 /// # pub enum Request {
961 /// # This(u8, u32),
962 /// # That(i64),
963 /// # }
964 /// # #[derive(Clone, Debug, PartialEq)]
965 /// # pub enum Response {
966 /// # Here(u8, u8, u8),
967 /// # There(i16),
968 /// # }
969 /// static INTERCHANGE_INNER: Interchange<Request, Response, 1> = Interchange::new();
970 ///
971 /// // The size of the interchange is absent from the type
972 /// static INTERCHANGE: InterchangeRef<'static, Request, Response> = INTERCHANGE_INNER.as_interchange_ref();
973 ///
974 /// let (mut rq, mut rp) = INTERCHANGE.claim().unwrap();
975 /// ```
976 pub const fn as_interchange_ref(&self) -> InterchangeRef<'_, Rq, Rp> {
977 InterchangeRef {
978 channels: &self.channels,
979 last_claimed: &self.last_claimed,
980 }
981 }
982}
983
984/// Interchange witout the `const N: usize` generic parameter
985/// Obtained using [`Interchange::as_interchange_ref`](Interchange::as_interchange_ref)
986pub struct InterchangeRef<'alloc, Rq, Rp> {
987 channels: &'alloc [Channel<Rq, Rp>],
988 last_claimed: &'alloc AtomicUsize,
989}
990
991impl<'alloc, Rq, Rp> InterchangeRef<'alloc, Rq, Rp> {
992 /// Claim one of the channels of the interchange. Returns None if called more than `N` times.
993 pub fn claim(&self) -> Option<(Requester<'alloc, Rq, Rp>, Responder<'alloc, Rq, Rp>)> {
994 let index = self.last_claimed.fetch_add(1, Ordering::Relaxed);
995 let n = self.channels.len();
996
997 for i in (index % n)..n {
998 let tmp = self.channels[i].split();
999 if tmp.is_some() {
1000 return tmp;
1001 }
1002 }
1003
1004 for i in 0..(index % n) {
1005 let tmp = self.channels[i].split();
1006 if tmp.is_some() {
1007 return tmp;
1008 }
1009 }
1010 None
1011 }
1012}
1013
1014impl<Rq, Rp> Clone for InterchangeRef<'_, Rq, Rp> {
1015 fn clone(&self) -> Self {
1016 *self
1017 }
1018}
1019
1020impl<Rq, Rp> Copy for InterchangeRef<'_, Rq, Rp> {}
1021
1022impl<Rq, Rp, const N: usize> Default for Interchange<Rq, Rp, N> {
1023 fn default() -> Self {
1024 Self::new()
1025 }
1026}
1027
1028/// ```compile_fail
1029/// use std::rc::Rc;
1030/// use interchange::*;
1031/// #[allow(unconditional_recursion, unused)]
1032/// fn assert_send<T: Send>() {
1033/// assert_send::<Channel<Rc<String>, u32>>();
1034/// }
1035/// ```
1036/// ```compile_fail
1037/// use std::rc::Rc;
1038/// use interchange::*;
1039/// #[allow(unconditional_recursion, unused)]
1040/// fn assert_send<T: Send>() {
1041/// assert_send::<Requester<Rc<String>, u32>>();
1042/// }
1043/// ```
1044/// ```compile_fail
1045/// use std::rc::Rc;
1046/// use interchange::*;
1047/// #[allow(unconditional_recursion, unused)]
1048/// fn assert_send<T: Send>() {
1049/// assert_send::<Responder<Rc<String>, u32>>();
1050/// }
1051/// ```
1052/// ```compile_fail
1053/// use std::rc::Rc;
1054/// use interchange::*;
1055/// #[allow(unconditional_recursion, unused)]
1056/// fn assert_sync<T: Sync>() {
1057/// assert_sync::<Channel<Rc<String>, u32>>();
1058/// }
1059/// ```
1060/// ```compile_fail
1061/// use std::rc::Rc;
1062/// use interchange::*;
1063/// #[allow(unconditional_recursion, unused)]
1064/// fn assert_sync<T: Sync>() {
1065/// assert_sync::<Requester<Rc<String>, u32>>();
1066/// }
1067/// ```
1068/// ```compile_fail
1069/// use std::rc::Rc;
1070/// use interchange::*;
1071/// #[allow(unconditional_recursion, unused)]
1072/// fn assert_sync<T: Sync>() {
1073/// assert_sync::<Responder<Rc<String>, u32>>();
1074/// }
1075/// ```
1076const _ASSERT_COMPILE_FAILS: () = {};
1077
1078#[cfg(all(not(loom), test))]
1079mod tests {
1080 use super::*;
1081 #[derive(Clone, Debug, PartialEq)]
1082 pub enum Request {
1083 This(u8, u32),
1084 }
1085 #[derive(Clone, Debug, PartialEq)]
1086 pub enum Response {
1087 Here(u8, u8, u8),
1088 There(i16),
1089 }
1090 impl Default for Response {
1091 fn default() -> Self {
1092 Response::There(1)
1093 }
1094 }
1095 impl Default for Request {
1096 fn default() -> Self {
1097 Request::This(0, 0)
1098 }
1099 }
1100
1101 #[test]
1102 fn interchange() {
1103 static INTERCHANGE: Interchange<Request, Response, 1> = Interchange::new();
1104 let (mut rq, mut rp) = INTERCHANGE.claim().unwrap();
1105 assert_eq!(rq.state(), State::Idle);
1106 // happy path: no cancelation
1107 let request = Request::This(1, 2);
1108 assert!(rq.request(request).is_ok());
1109 let request = rp.take_request().unwrap();
1110 println!("rp got request: {request:?}");
1111 let response = Response::There(-1);
1112 assert!(!rp.is_canceled());
1113 assert!(rp.respond(response).is_ok());
1114 let response = rq.take_response().unwrap();
1115 println!("rq got response: {response:?}");
1116 // early cancelation path
1117 assert!(rq.request(request).is_ok());
1118 let request = rq.cancel().unwrap().unwrap();
1119 println!("responder could cancel: {request:?}");
1120 assert!(rp.take_request().is_none());
1121 assert_eq!(State::Idle, rq.state());
1122 // late cancelation
1123 assert!(rq.request(request).is_ok());
1124 let request = rp.take_request().unwrap();
1125 println!(
1126 "responder could cancel: {:?}",
1127 rq.cancel().unwrap().is_none()
1128 );
1129 assert_eq!(request, Request::This(1, 2));
1130 assert!(rp.is_canceled());
1131 assert!(rp.respond(response).is_err());
1132 assert!(rp.acknowledge_cancel().is_ok());
1133 assert_eq!(State::Idle, rq.state());
1134 // building into request buffer
1135 rq.with_request_mut(|r| *r = Request::This(1, 2)).unwrap();
1136 assert!(rq.send_request().is_ok());
1137 let request = rp.take_request().unwrap();
1138 assert_eq!(request, Request::This(1, 2));
1139 println!("rp got request: {request:?}");
1140 // building into response buffer
1141 rp.with_response_mut(|r| *r = Response::Here(3, 2, 1))
1142 .unwrap();
1143 assert!(rp.send_response().is_ok());
1144 let response = rq.take_response().unwrap();
1145 assert_eq!(response, Response::Here(3, 2, 1));
1146 }
1147
1148 #[test]
1149 fn interchange_ref() {
1150 static INTERCHANGE_INNER: Interchange<Request, Response, 1> = Interchange::new();
1151 static INTERCHANGE: InterchangeRef<'static, Request, Response> =
1152 INTERCHANGE_INNER.as_interchange_ref();
1153 let (mut rq, mut rp) = INTERCHANGE.claim().unwrap();
1154 assert_eq!(rq.state(), State::Idle);
1155 // happy path: no cancelation
1156 let request = Request::This(1, 2);
1157 assert!(rq.request(request).is_ok());
1158 let request = rp.take_request().unwrap();
1159 println!("rp got request: {request:?}");
1160 let response = Response::There(-1);
1161 assert!(!rp.is_canceled());
1162 assert!(rp.respond(response).is_ok());
1163 let response = rq.take_response().unwrap();
1164 println!("rq got response: {response:?}");
1165 // early cancelation path
1166 assert!(rq.request(request).is_ok());
1167 let request = rq.cancel().unwrap().unwrap();
1168 println!("responder could cancel: {request:?}");
1169 assert!(rp.take_request().is_none());
1170 assert_eq!(State::Idle, rq.state());
1171 // late cancelation
1172 assert!(rq.request(request).is_ok());
1173 let request = rp.take_request().unwrap();
1174 println!(
1175 "responder could cancel: {:?}",
1176 rq.cancel().unwrap().is_none()
1177 );
1178 assert_eq!(request, Request::This(1, 2));
1179 assert!(rp.is_canceled());
1180 assert!(rp.respond(response).is_err());
1181 assert!(rp.acknowledge_cancel().is_ok());
1182 assert_eq!(State::Idle, rq.state());
1183 // building into request buffer
1184 rq.with_request_mut(|r| *r = Request::This(1, 2)).unwrap();
1185 assert!(rq.send_request().is_ok());
1186 let request = rp.take_request().unwrap();
1187 assert_eq!(request, Request::This(1, 2));
1188 println!("rp got request: {request:?}");
1189 // building into response buffer
1190 rp.with_response_mut(|r| *r = Response::Here(3, 2, 1))
1191 .unwrap();
1192 assert!(rp.send_response().is_ok());
1193 let response = rq.take_response().unwrap();
1194 assert_eq!(response, Response::Here(3, 2, 1));
1195 }
1196
1197 #[allow(unconditional_recursion, clippy::extra_unused_type_parameters, unused)]
1198 fn assert_send<T: Send>() {
1199 assert_send::<Channel<String, u32>>();
1200 assert_send::<Responder<'static, String, u32>>();
1201 assert_send::<Requester<'static, String, u32>>();
1202 assert_send::<Channel<&'static mut String, u32>>();
1203 assert_send::<Responder<'static, &'static mut String, u32>>();
1204 assert_send::<Requester<'static, &'static mut String, u32>>();
1205 }
1206 #[allow(unconditional_recursion, clippy::extra_unused_type_parameters, unused)]
1207 fn assert_sync<T: Sync>() {
1208 assert_sync::<Channel<String, u32>>();
1209 assert_sync::<Channel<String, u32>>();
1210 assert_sync::<Responder<'static, String, u32>>();
1211 assert_sync::<Requester<'static, String, u32>>();
1212
1213 assert_sync::<Channel<&'static mut String, u32>>();
1214 assert_sync::<Responder<'static, &'static mut String, u32>>();
1215 assert_sync::<Requester<'static, &'static mut String, u32>>();
1216 }
1217}