1use core::fmt::Debug;
14use core::future::Future;
15use core::pin::Pin;
16use core::task::{Context, Poll};
17
18pub trait Pipe {
92 type In;
94 type Out;
96 type Err: Debug + 'static;
99
100 fn call(&self, input: Self::In) -> impl Future<Output = Result<Self::Out, Self::Err>>;
102}
103
104pub trait SendPipe: Send + Sync + 'static {
115 type In;
117 type Out;
119 type Err: Debug + Send + 'static;
121
122 fn call(&self, input: Self::In) -> impl Future<Output = Result<Self::Out, Self::Err>> + Send;
124}
125
126pub trait UnpinPipe {
143 type In;
145 type Out;
147 type Err: Debug + 'static;
149
150 fn call(&self, input: Self::In) -> impl Future<Output = Result<Self::Out, Self::Err>> + Unpin;
152}
153
154pub trait UnpinSendPipe: Send + Sync + 'static {
166 type In;
168 type Out;
170 type Err: Debug + Send + 'static;
172
173 fn call(
175 &self,
176 input: Self::In,
177 ) -> impl Future<Output = Result<Self::Out, Self::Err>> + Send + Unpin;
178}
179
180#[derive(Debug, Clone, Copy)]
190pub struct AndThen<First, Second> {
191 first: First,
192 second: Second,
193}
194
195impl<First, Second> AndThen<First, Second> {
196 #[must_use]
198 pub const fn new(first: First, second: Second) -> Self {
199 Self { first, second }
200 }
201}
202
203impl<First, Second> Pipe for AndThen<First, Second>
204where
205 First: Pipe,
206 Second: Pipe<In = First::Out>,
207 Second::Err: From<First::Err>,
208{
209 type In = First::In;
210 type Out = Second::Out;
211 type Err = Second::Err;
212
213 fn call(&self, input: Self::In) -> impl Future<Output = Result<Self::Out, Self::Err>> {
214 async move {
215 let intermediate = self.first.call(input).await?;
218 self.second.call(intermediate).await
219 }
220 }
221}
222
223impl<First, Second> SendPipe for AndThen<First, Second>
224where
225 First: SendPipe,
226 Second: SendPipe<In = First::Out>,
227 Second::Err: From<First::Err>,
228 First::In: Send,
229{
230 type In = First::In;
231 type Out = Second::Out;
232 type Err = Second::Err;
233
234 fn call(&self, input: Self::In) -> impl Future<Output = Result<Self::Out, Self::Err>> + Send {
235 async move {
236 let intermediate = self.first.call(input).await?;
237 self.second.call(intermediate).await
238 }
239 }
240}
241
242enum AndThenUnpinCall<FirstFut, Next, SecondFut> {
255 First {
256 future: FirstFut,
257 next: Option<Next>,
258 },
259 Second {
260 future: SecondFut,
261 },
262}
263
264fn start_and_then<FirstFut, Intermediate, FirstErr, Next, SecondFut>(
273 future: FirstFut,
274 next: Next,
275) -> AndThenUnpinCall<FirstFut, Next, SecondFut>
276where
277 FirstFut: Future<Output = Result<Intermediate, FirstErr>>,
278 Next: FnOnce(Intermediate) -> SecondFut,
279{
280 AndThenUnpinCall::First {
281 future,
282 next: Some(next),
283 }
284}
285
286impl<FirstFut, Intermediate, FirstErr, Next, SecondFut, SecondOut, SecondErr> Future
287 for AndThenUnpinCall<FirstFut, Next, SecondFut>
288where
289 FirstFut: Future<Output = Result<Intermediate, FirstErr>> + Unpin,
290 Next: FnOnce(Intermediate) -> SecondFut + Unpin,
291 SecondFut: Future<Output = Result<SecondOut, SecondErr>> + Unpin,
292 SecondErr: From<FirstErr>,
293{
294 type Output = Result<SecondOut, SecondErr>;
295
296 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
297 let this = self.get_mut();
300 loop {
301 match this {
302 AndThenUnpinCall::First { future, next } => {
303 match Pin::new(future).poll(cx) {
304 Poll::Ready(Ok(intermediate)) => {
305 let Some(next) = next.take() else {
310 return Poll::Pending;
311 };
312 *this = AndThenUnpinCall::Second {
313 future: next(intermediate),
314 };
315 }
317 Poll::Ready(Err(err)) => return Poll::Ready(Err(SecondErr::from(err))),
318 Poll::Pending => return Poll::Pending,
319 }
320 }
321 AndThenUnpinCall::Second { future } => return Pin::new(future).poll(cx),
322 }
323 }
324 }
325}
326
327impl<First, Second> UnpinPipe for AndThen<First, Second>
328where
329 First: UnpinPipe,
330 Second: UnpinPipe<In = First::Out>,
331 Second::Err: From<First::Err>,
332{
333 type In = First::In;
334 type Out = Second::Out;
335 type Err = Second::Err;
336
337 fn call(&self, input: Self::In) -> impl Future<Output = Result<Self::Out, Self::Err>> + Unpin {
338 let second = &self.second;
339 start_and_then(self.first.call(input), move |intermediate| {
340 second.call(intermediate)
341 })
342 }
343}
344
345impl<First, Second> UnpinSendPipe for AndThen<First, Second>
346where
347 First: UnpinSendPipe,
348 Second: UnpinSendPipe<In = First::Out>,
349 Second::Err: From<First::Err>,
350{
351 type In = First::In;
352 type Out = Second::Out;
353 type Err = Second::Err;
354
355 fn call(
356 &self,
357 input: Self::In,
358 ) -> impl Future<Output = Result<Self::Out, Self::Err>> + Send + Unpin {
359 let second = &self.second;
360 start_and_then(self.first.call(input), move |intermediate| {
361 second.call(intermediate)
362 })
363 }
364}
365
366mod marker_propagation {
373 use super::AndThen;
374 use proxima_core::markers::{
375 AllocFree, Commutative, Deterministic, DropSafe, IdempotentSideEffectFree, IsPure, NoStd,
376 Reproducible, WithoutFilesystem, WithoutNetwork, WithoutRandom, WithoutSpawn, WithoutTime,
377 };
378
379 impl<First: DropSafe, Second: DropSafe> DropSafe for AndThen<First, Second> {}
380 impl<First: NoStd, Second: NoStd> NoStd for AndThen<First, Second> {}
381 impl<First: AllocFree, Second: AllocFree> AllocFree for AndThen<First, Second> {}
382 impl<First: IsPure, Second: IsPure> IsPure for AndThen<First, Second> {}
383 impl<First: Deterministic, Second: Deterministic> Deterministic for AndThen<First, Second> {}
384 impl<First: Reproducible, Second: Reproducible> Reproducible for AndThen<First, Second> {}
385 impl<First: IdempotentSideEffectFree, Second: IdempotentSideEffectFree> IdempotentSideEffectFree
386 for AndThen<First, Second>
387 {
388 }
389 impl<First: Commutative, Second: Commutative> Commutative for AndThen<First, Second> {}
390
391 impl<First: WithoutFilesystem, Second: WithoutFilesystem> WithoutFilesystem
392 for AndThen<First, Second>
393 {
394 }
395 impl<First: WithoutNetwork, Second: WithoutNetwork> WithoutNetwork for AndThen<First, Second> {}
396 impl<First: WithoutSpawn, Second: WithoutSpawn> WithoutSpawn for AndThen<First, Second> {}
397 impl<First: WithoutTime, Second: WithoutTime> WithoutTime for AndThen<First, Second> {}
398 impl<First: WithoutRandom, Second: WithoutRandom> WithoutRandom for AndThen<First, Second> {}
399}
400
401#[cfg(test)]
402#[allow(clippy::unwrap_used, clippy::expect_used)]
403mod tests {
404 use super::{AndThen, Pipe, SendPipe};
405 use crate::block_on;
406 use crate::pipe::ext::PipeExt;
407 use core::convert::Infallible;
408 use core::future::Future;
409 use core::marker::PhantomData;
410 use proxima_core::markers::{
411 AllocFree, Commutative, Deterministic, DropSafe, IdempotentSideEffectFree, IsPure, NoStd,
412 Reproducible, WithoutFilesystem, WithoutNetwork, WithoutRandom, WithoutSpawn, WithoutTime,
413 };
414
415 struct Identity<Value>(PhantomData<fn() -> Value>);
419
420 impl<Value> Identity<Value> {
421 const fn new() -> Self {
422 Self(PhantomData)
423 }
424 }
425
426 impl<Value> Pipe for Identity<Value> {
427 type In = Value;
428 type Out = Value;
429 type Err = Infallible;
430
431 fn call(&self, input: Value) -> impl Future<Output = Result<Value, Infallible>> {
432 async move { Ok(input) }
433 }
434 }
435
436 impl<Value: Send + 'static> SendPipe for Identity<Value> {
437 type In = Value;
438 type Out = Value;
439 type Err = Infallible;
440
441 fn call(&self, input: Value) -> impl Future<Output = Result<Value, Infallible>> + Send {
442 async move { Ok(input) }
443 }
444 }
445
446 impl<Value> DropSafe for Identity<Value> {}
447 impl<Value> NoStd for Identity<Value> {}
448 impl<Value> AllocFree for Identity<Value> {}
449 impl<Value> IsPure for Identity<Value> {}
450 impl<Value> Deterministic for Identity<Value> {}
451 impl<Value> Reproducible for Identity<Value> {}
452 impl<Value> IdempotentSideEffectFree for Identity<Value> {}
453 impl<Value> Commutative for Identity<Value> {}
454 impl<Value> WithoutFilesystem for Identity<Value> {}
455 impl<Value> WithoutNetwork for Identity<Value> {}
456 impl<Value> WithoutSpawn for Identity<Value> {}
457 impl<Value> WithoutTime for Identity<Value> {}
458 impl<Value> WithoutRandom for Identity<Value> {}
459
460 #[derive(Debug, PartialEq, Eq)]
462 struct Overflow;
463
464 struct Increment;
465
466 impl Pipe for Increment {
467 type In = u64;
468 type Out = u64;
469 type Err = Overflow;
470
471 fn call(&self, input: u64) -> impl Future<Output = Result<u64, Overflow>> {
472 async move { input.checked_add(1).ok_or(Overflow) }
473 }
474 }
475
476 #[derive(Debug, PartialEq, Eq)]
480 enum HalveError {
481 Odd,
482 Upstream(Overflow),
483 }
484
485 impl From<Overflow> for HalveError {
486 fn from(value: Overflow) -> Self {
487 HalveError::Upstream(value)
488 }
489 }
490
491 struct Halve;
492
493 impl Pipe for Halve {
494 type In = u64;
495 type Out = u64;
496 type Err = HalveError;
497
498 fn call(&self, input: u64) -> impl Future<Output = Result<u64, HalveError>> {
499 async move {
500 if input.is_multiple_of(2) {
501 Ok(input / 2)
502 } else {
503 Err(HalveError::Odd)
504 }
505 }
506 }
507 }
508
509 #[derive(Debug, PartialEq, Eq)]
514 enum DoubleError {
515 TooBig,
516 Halve(HalveError),
517 }
518
519 impl From<HalveError> for DoubleError {
520 fn from(value: HalveError) -> Self {
521 DoubleError::Halve(value)
522 }
523 }
524
525 impl From<Overflow> for DoubleError {
526 fn from(value: Overflow) -> Self {
527 DoubleError::Halve(HalveError::from(value))
528 }
529 }
530
531 struct Double;
532
533 impl Pipe for Double {
534 type In = u64;
535 type Out = u64;
536 type Err = DoubleError;
537
538 fn call(&self, input: u64) -> impl Future<Output = Result<u64, DoubleError>> {
539 async move { input.checked_mul(2).ok_or(DoubleError::TooBig) }
540 }
541 }
542
543 struct AlwaysFail;
546
547 impl Pipe for AlwaysFail {
548 type In = u64;
549 type Out = u64;
550 type Err = Overflow;
551
552 fn call(&self, _input: u64) -> impl Future<Output = Result<u64, Overflow>> {
553 async move { Err(Overflow) }
554 }
555 }
556
557 struct SpyRef<'flag> {
561 ran: &'flag core::cell::Cell<bool>,
562 }
563
564 impl Pipe for SpyRef<'_> {
565 type In = u64;
566 type Out = u64;
567 type Err = HalveError;
568
569 fn call(&self, input: u64) -> impl Future<Output = Result<u64, HalveError>> {
570 self.ran.set(true);
571 async move { Ok(input) }
572 }
573 }
574
575 #[test]
576 fn series_pipes_identity_through_identity() {
577 let chain = AndThen::new(Identity::<u64>::new(), Identity::<u64>::new());
582 let out = block_on(Pipe::call(&chain, 41)).expect("infallible identity chain");
583 assert_eq!(out, 41);
584 }
585
586 #[test]
587 fn series_composes_distinct_error_types_via_from() {
588 let chain = Increment.and_then(Halve);
590 let out = block_on(Pipe::call(&chain, 5)).expect("even intermediate halves");
591 assert_eq!(out, 3);
592 }
593
594 #[test]
595 fn series_propagates_first_stage_error_converted_by_from() {
596 let chain = Increment.and_then(Halve);
598 let err = block_on(Pipe::call(&chain, u64::MAX)).expect_err("overflow propagates");
599 assert_eq!(err, HalveError::Upstream(Overflow));
600 }
601
602 #[test]
603 fn series_surfaces_second_stage_error_unchanged() {
604 let chain = Increment.and_then(Halve);
606 let err = block_on(Pipe::call(&chain, 6)).expect_err("odd intermediate rejected");
607 assert_eq!(err, HalveError::Odd);
608 }
609
610 fn assert_send<Type: Send>(_: &Type) {}
611
612 #[test]
613 fn series_is_a_send_pipe_with_a_send_future() {
614 let chain = AndThen::new(Identity::<u64>::new(), Identity::<u64>::new());
617 let future = SendPipe::call(&chain, 7);
618 assert_send(&future);
619 let out = block_on(future).expect("send chain");
620 assert_eq!(out, 7);
621 }
622
623 fn assert_all_markers<Type>()
627 where
628 Type: NoStd
629 + AllocFree
630 + IsPure
631 + Deterministic
632 + Reproducible
633 + IdempotentSideEffectFree
634 + Commutative
635 + WithoutFilesystem
636 + WithoutNetwork
637 + WithoutSpawn
638 + WithoutTime
639 + WithoutRandom
640 + DropSafe,
641 {
642 }
643
644 #[test]
645 fn series_propagates_all_markers_from_both_stages() {
646 assert_all_markers::<AndThen<Identity<u64>, Identity<u64>>>();
647 assert_all_markers::<AndThen<Identity<u64>, AndThen<Identity<u64>, Identity<u64>>>>();
649 }
650
651 #[test]
652 fn and_then_matches_series_new_for_a_two_stage_chain() {
653 let fluent = block_on(Pipe::call(&Increment.and_then(Halve), 5));
654 let manual = block_on(Pipe::call(&AndThen::new(Increment, Halve), 5));
655 assert_eq!(fluent, manual);
656 assert_eq!(fluent.expect("even intermediate halves"), 3);
657 }
658
659 #[test]
660 fn and_then_matches_series_new_on_the_error_path() {
661 let fluent = block_on(Pipe::call(&Increment.and_then(Halve), u64::MAX));
662 let manual = block_on(Pipe::call(&AndThen::new(Increment, Halve), u64::MAX));
663 assert_eq!(fluent, manual);
664 assert_eq!(
665 fluent.expect_err("overflow propagates"),
666 HalveError::Upstream(Overflow)
667 );
668 }
669
670 #[test]
671 fn and_then_chain_matches_nested_series_new_for_a_three_stage_chain() {
672 let left_leaning = Increment.and_then(Halve).and_then(Double);
676 let right_leaning = AndThen::new(Increment, AndThen::new(Halve, Double));
677
678 let left_output = block_on(Pipe::call(&left_leaning, 5)).expect("5 -> 6 -> 3 -> 6");
679 let right_output = block_on(Pipe::call(&right_leaning, 5)).expect("5 -> 6 -> 3 -> 6");
680 assert_eq!(left_output, right_output);
681 assert_eq!(left_output, 6);
682 }
683
684 #[test]
685 fn and_then_short_circuits_before_the_second_stage_on_first_stage_error() {
686 let ran = core::cell::Cell::new(false);
687 let chain = AlwaysFail.and_then(SpyRef { ran: &ran });
688
689 let err = block_on(Pipe::call(&chain, 1)).expect_err("first stage always fails");
690
691 assert_eq!(err, HalveError::Upstream(Overflow));
692 assert!(
693 !ran.get(),
694 "second stage must not run after first stage errors"
695 );
696 }
697}
698
699#[cfg(test)]
700#[allow(clippy::unwrap_used, clippy::expect_used)]
701mod unpin_tier_tests {
702 use super::{AndThen, UnpinPipe, UnpinSendPipe};
703 use core::convert::Infallible;
704 use core::future::Future;
705 use core::pin::Pin;
706 use core::task::{Context, Poll, Waker};
707
708 struct RingPop(u8);
711 impl Future for RingPop {
712 type Output = Result<u8, Infallible>;
713 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
714 Poll::Ready(Ok(self.0))
715 }
716 }
717
718 struct Ring(u8);
719 impl UnpinPipe for Ring {
720 type In = ();
721 type Out = u8;
722 type Err = Infallible;
723 fn call(&self, (): ()) -> impl Future<Output = Result<u8, Infallible>> + Unpin {
724 RingPop(self.0)
725 }
726 }
727 impl UnpinSendPipe for Ring {
728 type In = ();
729 type Out = u8;
730 type Err = Infallible;
731 fn call(&self, (): ()) -> impl Future<Output = Result<u8, Infallible>> + Send + Unpin {
732 RingPop(self.0)
733 }
734 }
735
736 fn merge_in_place<S: UnpinPipe<In = ()>, const N: usize>(
739 sources: &[S; N],
740 cx: &mut Context<'_>,
741 ) -> Poll<Result<S::Out, S::Err>> {
742 for source in sources {
743 let mut call = source.call(());
744 if let Poll::Ready(out) = Pin::new(&mut call).poll(cx) {
745 return Poll::Ready(out);
746 }
747 }
748 Poll::Pending
749 }
750
751 #[test]
752 fn unpin_future_polls_in_place_without_unsafe_or_alloc() {
753 let waker = Waker::noop();
754 let mut cx = Context::from_waker(waker);
755 let sources = [Ring(7), Ring(9)];
756 match merge_in_place(&sources, &mut cx) {
757 Poll::Ready(Ok(value)) => assert_eq!(value, 7, "first ready source wins"),
758 other => panic!("expected the first source to be ready, got {other:?}"),
759 }
760 }
761
762 #[test]
763 fn send_unpin_tier_is_the_cross_core_mergeable_form() {
764 fn assert_send_unpin<S: UnpinSendPipe<In = ()>>(source: &S) {
765 fn needs_send_unpin<F: Future + Send + Unpin>(_: &F) {}
766 let call = UnpinSendPipe::call(source, ());
767 needs_send_unpin(&call);
768 }
769 assert_send_unpin(&Ring(1));
770 }
771
772 struct Doubler;
776 impl UnpinPipe for Doubler {
777 type In = u8;
778 type Out = u16;
779 type Err = Infallible;
780 fn call(&self, input: u8) -> impl Future<Output = Result<u16, Infallible>> + Unpin {
781 core::future::ready(Ok(u16::from(input) * 2))
782 }
783 }
784 impl UnpinSendPipe for Doubler {
785 type In = u8;
786 type Out = u16;
787 type Err = Infallible;
788 fn call(&self, input: u8) -> impl Future<Output = Result<u16, Infallible>> + Send + Unpin {
789 core::future::ready(Ok(u16::from(input) * 2))
790 }
791 }
792
793 #[test]
794 fn and_then_unpin_chain_composes_two_pipes_without_a_box() {
795 let waker = Waker::noop();
796 let mut cx = Context::from_waker(waker);
797 let chain = AndThen::new(Ring(21), Doubler);
798 let mut call = UnpinPipe::call(&chain, ());
799 match Pin::new(&mut call).poll(&mut cx) {
800 Poll::Ready(Ok(value)) => assert_eq!(value, 42, "21 -> ring pop -> double -> 42"),
801 other => panic!("expected ready, got {other:?}"),
802 }
803 }
804
805 #[test]
806 fn and_then_unpin_send_chain_is_send_and_unpin() {
807 fn needs_send_unpin<F: Future + Send + Unpin>(_: &F) {}
808 let chain = AndThen::new(Ring(5), Doubler);
809 let call = UnpinSendPipe::call(&chain, ());
810 needs_send_unpin(&call);
811 }
812
813 struct PendOnceThenReady {
818 value: u8,
819 polled_once: core::cell::Cell<bool>,
820 }
821 impl Future for PendOnceThenReady {
822 type Output = Result<u8, Infallible>;
823 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
824 if self.polled_once.replace(true) {
825 Poll::Ready(Ok(self.value))
826 } else {
827 cx.waker().wake_by_ref();
828 Poll::Pending
829 }
830 }
831 }
832
833 struct SlowRing(u8);
834 impl UnpinPipe for SlowRing {
835 type In = ();
836 type Out = u8;
837 type Err = Infallible;
838 fn call(&self, (): ()) -> impl Future<Output = Result<u8, Infallible>> + Unpin {
839 PendOnceThenReady {
840 value: self.0,
841 polled_once: core::cell::Cell::new(false),
842 }
843 }
844 }
845
846 #[test]
847 fn and_then_unpin_chain_resumes_across_polls_without_rerunning_first_stage() {
848 let waker = Waker::noop();
849 let mut cx = Context::from_waker(waker);
850 let chain = AndThen::new(SlowRing(21), Doubler);
851 let mut call = UnpinPipe::call(&chain, ());
852 assert_eq!(
853 Pin::new(&mut call).poll(&mut cx),
854 Poll::Pending,
855 "first stage not ready yet"
856 );
857 match Pin::new(&mut call).poll(&mut cx) {
858 Poll::Ready(Ok(value)) => {
859 assert_eq!(value, 42, "second poll resumes at First, then runs Second");
860 }
861 other => panic!("expected ready on the second poll, got {other:?}"),
862 }
863 }
864
865 #[derive(Debug, PartialEq, Eq)]
869 struct RingError;
870
871 struct FailingRing;
872 impl UnpinPipe for FailingRing {
873 type In = ();
874 type Out = u8;
875 type Err = RingError;
876 fn call(&self, (): ()) -> impl Future<Output = Result<u8, RingError>> + Unpin {
877 core::future::ready(Err(RingError))
878 }
879 }
880
881 struct CountingDoubler {
882 calls: core::cell::Cell<u32>,
883 }
884 impl UnpinPipe for CountingDoubler {
885 type In = u8;
886 type Out = u16;
887 type Err = RingError;
888 fn call(&self, input: u8) -> impl Future<Output = Result<u16, RingError>> + Unpin {
889 self.calls.set(self.calls.get() + 1);
890 core::future::ready(Ok(u16::from(input) * 2))
891 }
892 }
893
894 #[test]
895 fn and_then_unpin_chain_short_circuits_before_the_second_stage() {
896 let waker = Waker::noop();
897 let mut cx = Context::from_waker(waker);
898 let second = CountingDoubler {
899 calls: core::cell::Cell::new(0),
900 };
901 let chain = AndThen::new(FailingRing, second);
902 let mut call = UnpinPipe::call(&chain, ());
903 match Pin::new(&mut call).poll(&mut cx) {
904 Poll::Ready(Err(RingError)) => {}
905 other => panic!("expected the first stage's error, got {other:?}"),
906 }
907 assert_eq!(
908 chain.second.calls.get(),
909 0,
910 "second stage must not run after first stage errors"
911 );
912 }
913}