@@ -4,95 +4,77 @@ use std::task::{Context, Poll};
4
4
5
5
use diesel:: QueryResult ;
6
6
use futures_core:: { ready, TryFuture , TryStream } ;
7
- use futures_util:: TryStreamExt ;
8
- use pin_project_lite:: pin_project;
7
+ use futures_util:: { TryFutureExt , TryStreamExt } ;
9
8
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 > ,
22
19
}
23
20
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)
27
35
}
28
36
}
29
37
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) ,
43
42
}
44
43
}
45
44
}
46
45
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 > ,
61
50
}
62
51
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) ,
67
60
}
68
61
}
69
62
}
70
63
71
- impl < Fut1 , Fut2 > Future for AndThen < Fut1 , Fut2 >
64
+ impl < F1 , F2 > Future for AndThen < F1 , F2 >
72
65
where
73
- Fut1 : TryFuture < Error = diesel :: result :: Error > ,
74
- Fut2 : TryFuture < Error = diesel :: result :: Error > ,
66
+ F1 : TryFuture ,
67
+ F2 : TryFuture < Error = F1 :: Error > ,
75
68
{
76
- type Output = QueryResult < Fut2 :: Ok > ;
69
+ type Output = Result < F2 :: Ok , F2 :: Error > ;
77
70
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 )
95
76
}
77
+ . poll ( cx)
96
78
}
97
79
}
98
80
0 commit comments