@@ -4,95 +4,77 @@ use std::task::{Context, Poll};
44
55use diesel:: QueryResult ;
66use futures_core:: { ready, TryFuture , TryStream } ;
7- use futures_util:: TryStreamExt ;
8- use pin_project_lite:: pin_project;
7+ use futures_util:: { TryFutureExt , TryStreamExt } ;
98
10- pin_project ! {
11- /// Reimplementation of [`futures_util::future::Map`] without the generic closure argument
12- #[ project = MapProj ]
13- #[ project_replace = MapProjReplace ]
14- pub enum Map <Fut : Future , T > {
15- Incomplete {
16- #[ pin]
17- future: Fut ,
18- f: fn ( Fut :: Output ) -> QueryResult <T >,
19- } ,
20- Complete ,
21- }
9+ // We use a custom future implementation here to erase some lifetimes
10+ // that otherwise need to be specified explicitly
11+ //
12+ // Specifying these lifetimes results in the compiler not beeing
13+ // able to look through the generic code and emit
14+ // lifetime erros for pipelined queries. See
15+ // https://github.com/weiznich/diesel_async/issues/249 for more context
16+ #[ repr( transparent) ]
17+ pub struct MapOk < F : TryFutureExt , T > {
18+ future : futures_util:: future:: MapOk < F , fn ( F :: Ok ) -> T > ,
2219}
2320
24- impl < Fut : Future , T > Map < Fut , T > {
25- pub ( crate ) fn new ( future : Fut , f : fn ( Fut :: Output ) -> QueryResult < T > ) -> Self {
26- Self :: Incomplete { future, f }
21+ impl < F , T > Future for MapOk < F , T >
22+ where
23+ F : TryFuture ,
24+ futures_util:: future:: MapOk < F , fn ( F :: Ok ) -> T > : Future < Output = Result < T , F :: Error > > ,
25+ {
26+ type Output = Result < T , F :: Error > ;
27+
28+ fn poll ( self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Self :: Output > {
29+ unsafe {
30+ // SAFETY: This projects pinning to the only inner field, so it
31+ // should be safe
32+ self . map_unchecked_mut ( |s| & mut s. future )
33+ }
34+ . poll ( cx)
2735 }
2836}
2937
30- impl < Fut : Future , T > Future for Map < Fut , T > {
31- type Output = QueryResult < T > ;
32-
33- fn poll ( mut self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < QueryResult < T > > {
34- match self . as_mut ( ) . project ( ) {
35- MapProj :: Incomplete { future, .. } => {
36- let output = ready ! ( future. poll( cx) ) ;
37- match self . as_mut ( ) . project_replace ( Map :: Complete ) {
38- MapProjReplace :: Incomplete { f, .. } => Poll :: Ready ( f ( output) ) ,
39- MapProjReplace :: Complete => unreachable ! ( ) ,
40- }
41- }
42- MapProj :: Complete => panic ! ( "Map polled after completion" ) ,
38+ impl < Fut : TryFutureExt , T > MapOk < Fut , T > {
39+ pub ( crate ) fn new ( future : Fut , f : fn ( Fut :: Ok ) -> T ) -> Self {
40+ Self {
41+ future : future. map_ok ( f) ,
4342 }
4443 }
4544}
4645
47- pin_project ! {
48- /// Reimplementation of [`futures_util::future::AndThen`] without the generic closure argument
49- #[ project = AndThenProj ]
50- pub enum AndThen <Fut1 : Future , Fut2 > {
51- First {
52- #[ pin]
53- future1: Map <Fut1 , Fut2 >,
54- } ,
55- Second {
56- #[ pin]
57- future2: Fut2 ,
58- } ,
59- Empty ,
60- }
46+ // similar to `MapOk` above this mainly exists to hide the lifetime
47+ #[ repr( transparent) ]
48+ pub struct AndThen < F1 : TryFuture , F2 > {
49+ future : futures_util:: future:: AndThen < F1 , F2 , fn ( F1 :: Ok ) -> F2 > ,
6150}
6251
63- impl < Fut1 : Future , Fut2 > AndThen < Fut1 , Fut2 > {
64- pub ( crate ) fn new ( fut1 : Fut1 , f : fn ( Fut1 :: Output ) -> QueryResult < Fut2 > ) -> AndThen < Fut1 , Fut2 > {
65- Self :: First {
66- future1 : Map :: new ( fut1, f) ,
52+ impl < Fut1 , Fut2 > AndThen < Fut1 , Fut2 >
53+ where
54+ Fut1 : TryFuture ,
55+ Fut2 : TryFuture < Error = Fut1 :: Error > ,
56+ {
57+ pub ( crate ) fn new ( fut1 : Fut1 , f : fn ( Fut1 :: Ok ) -> Fut2 ) -> AndThen < Fut1 , Fut2 > {
58+ Self {
59+ future : fut1. and_then ( f) ,
6760 }
6861 }
6962}
7063
71- impl < Fut1 , Fut2 > Future for AndThen < Fut1 , Fut2 >
64+ impl < F1 , F2 > Future for AndThen < F1 , F2 >
7265where
73- Fut1 : TryFuture < Error = diesel :: result :: Error > ,
74- Fut2 : TryFuture < Error = diesel :: result :: Error > ,
66+ F1 : TryFuture ,
67+ F2 : TryFuture < Error = F1 :: Error > ,
7568{
76- type Output = QueryResult < Fut2 :: Ok > ;
69+ type Output = Result < F2 :: Ok , F2 :: Error > ;
7770
78- fn poll ( mut self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
79- loop {
80- match self . as_mut ( ) . project ( ) {
81- AndThenProj :: First { future1 } => match ready ! ( future1. try_poll( cx) ) {
82- Ok ( future2) => self . set ( Self :: Second { future2 } ) ,
83- Err ( error) => {
84- self . set ( Self :: Empty ) ;
85- break Poll :: Ready ( Err ( error) ) ;
86- }
87- } ,
88- AndThenProj :: Second { future2 } => {
89- let output = ready ! ( future2. try_poll( cx) ) ;
90- self . set ( Self :: Empty ) ;
91- break Poll :: Ready ( output) ;
92- }
93- AndThenProj :: Empty => panic ! ( "AndThen polled after completion" ) ,
94- }
71+ fn poll ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
72+ unsafe {
73+ // SAFETY: This projects pinning to the only inner field, so it
74+ // should be safe
75+ self . map_unchecked_mut ( |s| & mut s. future )
9576 }
77+ . poll ( cx)
9678 }
9779}
9880
0 commit comments