@@ -22,13 +22,8 @@ pub trait SpiDevice: ErrorType {
22
22
where
23
23
Self : ' a ,
24
24
R : ' a ,
25
- F : FnOnce ( & ' a mut Self :: Bus ) -> Fut + ' a ,
26
- Fut : Future <
27
- Output = (
28
- & ' a mut Self :: Bus ,
29
- Result < R , <Self :: Bus as ErrorType >:: Error > ,
30
- ) ,
31
- > + ' a ;
25
+ F : FnOnce ( * mut Self :: Bus ) -> Fut + ' a ,
26
+ Fut : Future < Output = Result < R , <Self :: Bus as ErrorType >:: Error > > + ' a ;
32
27
33
28
/// Perform a transaction against the device.
34
29
///
@@ -42,15 +37,14 @@ pub trait SpiDevice: ErrorType {
42
37
/// The locking mechanism is implementation-defined. The only requirement is it must prevent two
43
38
/// transactions from executing concurrently against the same bus. Examples of implementations are:
44
39
/// critical sections, blocking mutexes, async mutexes, returning an error or panicking if the bus is already busy.
40
+ ///
41
+ /// The current state of the Rust typechecker doesn't allow expressing the necessary lifetime constraints, so
42
+ /// the `f` closure receives a lifetime-less `*mut Bus` raw pointer instead. The pointer is guaranteed
43
+ /// to be valid for the entire duration the closure is running, so dereferencing it is safe.
45
44
fn transaction < ' a , R , F , Fut > ( & ' a mut self , f : F ) -> Self :: TransactionFuture < ' a , R , F , Fut >
46
45
where
47
- F : FnOnce ( & ' a mut Self :: Bus ) -> Fut + ' a ,
48
- Fut : Future <
49
- Output = (
50
- & ' a mut Self :: Bus ,
51
- Result < R , <Self :: Bus as ErrorType >:: Error > ,
52
- ) ,
53
- > + ' a ;
46
+ F : FnOnce ( * mut Self :: Bus ) -> Fut + ' a ,
47
+ Fut : Future < Output = Result < R , <Self :: Bus as ErrorType >:: Error > > + ' a ;
54
48
}
55
49
56
50
/// Helper methods for SpiDevice.
@@ -147,8 +141,9 @@ impl<T: SpiDevice> SpiDeviceExt for T {
147
141
Word : Copy + ' static ,
148
142
{
149
143
self . transaction ( move |bus| async move {
150
- let res = bus. read ( buf) . await ;
151
- ( bus, res)
144
+ // safety: `bus` is a valid pointer we're allowed to use for the duration of the closure.
145
+ let bus = unsafe { & mut * bus } ;
146
+ bus. read ( buf) . await
152
147
} )
153
148
}
154
149
@@ -164,8 +159,9 @@ impl<T: SpiDevice> SpiDeviceExt for T {
164
159
Word : Copy + ' static ,
165
160
{
166
161
self . transaction ( move |bus| async move {
167
- let res = bus. write ( buf) . await ;
168
- ( bus, res)
162
+ // safety: `bus` is a valid pointer we're allowed to use for the duration of the closure.
163
+ let bus = unsafe { & mut * bus } ;
164
+ bus. write ( buf) . await
169
165
} )
170
166
}
171
167
@@ -185,8 +181,9 @@ impl<T: SpiDevice> SpiDeviceExt for T {
185
181
Word : Copy + ' static ,
186
182
{
187
183
self . transaction ( move |bus| async move {
188
- let res = bus. transfer ( read, write) . await ;
189
- ( bus, res)
184
+ // safety: `bus` is a valid pointer we're allowed to use for the duration of the closure.
185
+ let bus = unsafe { & mut * bus } ;
186
+ bus. transfer ( read, write) . await
190
187
} )
191
188
}
192
189
@@ -205,8 +202,9 @@ impl<T: SpiDevice> SpiDeviceExt for T {
205
202
Word : Copy + ' static ,
206
203
{
207
204
self . transaction ( move |bus| async move {
208
- let res = bus. transfer_in_place ( buf) . await ;
209
- ( bus, res)
205
+ // safety: `bus` is a valid pointer we're allowed to use for the duration of the closure.
206
+ let bus = unsafe { & mut * bus } ;
207
+ bus. transfer_in_place ( buf) . await
210
208
} )
211
209
}
212
210
}
@@ -216,18 +214,13 @@ impl<T: SpiDevice> SpiDevice for &mut T {
216
214
217
215
type TransactionFuture < ' a , R , F , Fut > = T :: TransactionFuture < ' a , R , F , Fut >
218
216
where
219
- Self : ' a , R : ' a , F : FnOnce ( & ' a mut Self :: Bus ) -> Fut + ' a ,
220
- Fut : Future < Output = ( & ' a mut Self :: Bus , Result < R , <Self :: Bus as ErrorType >:: Error > ) > + ' a ;
217
+ Self : ' a , R : ' a , F : FnOnce ( * mut Self :: Bus ) -> Fut + ' a ,
218
+ Fut : Future < Output = Result < R , <Self :: Bus as ErrorType >:: Error > > + ' a ;
221
219
222
220
fn transaction < ' a , R , F , Fut > ( & ' a mut self , f : F ) -> Self :: TransactionFuture < ' a , R , F , Fut >
223
221
where
224
- F : FnOnce ( & ' a mut Self :: Bus ) -> Fut + ' a ,
225
- Fut : Future <
226
- Output = (
227
- & ' a mut Self :: Bus ,
228
- Result < R , <Self :: Bus as ErrorType >:: Error > ,
229
- ) ,
230
- > + ' a ,
222
+ F : FnOnce ( * mut Self :: Bus ) -> Fut + ' a ,
223
+ Fut : Future < Output = Result < R , <Self :: Bus as ErrorType >:: Error > > + ' a ,
231
224
{
232
225
T :: transaction ( self , f)
233
226
}
@@ -449,27 +442,22 @@ where
449
442
450
443
type TransactionFuture < ' a , R , F , Fut > = impl Future < Output = Result < R , Self :: Error > > + ' a
451
444
where
452
- Self : ' a , R : ' a , F : FnOnce ( & ' a mut Self :: Bus ) -> Fut + ' a ,
453
- Fut : Future < Output = ( & ' a mut Self :: Bus , Result < R , <Self :: Bus as ErrorType >:: Error > ) > + ' a ;
445
+ Self : ' a , R : ' a , F : FnOnce ( * mut Self :: Bus ) -> Fut + ' a ,
446
+ Fut : Future < Output = Result < R , <Self :: Bus as ErrorType >:: Error > > + ' a ;
454
447
455
448
fn transaction < ' a , R , F , Fut > ( & ' a mut self , f : F ) -> Self :: TransactionFuture < ' a , R , F , Fut >
456
449
where
457
450
R : ' a ,
458
- F : FnOnce ( & ' a mut Self :: Bus ) -> Fut + ' a ,
459
- Fut : Future <
460
- Output = (
461
- & ' a mut Self :: Bus ,
462
- Result < R , <Self :: Bus as ErrorType >:: Error > ,
463
- ) ,
464
- > + ' a ,
451
+ F : FnOnce ( * mut Self :: Bus ) -> Fut + ' a ,
452
+ Fut : Future < Output = Result < R , <Self :: Bus as ErrorType >:: Error > > + ' a ,
465
453
{
466
454
async move {
467
455
self . cs . set_low ( ) . map_err ( ExclusiveDeviceError :: Cs ) ?;
468
456
469
- let ( bus , f_res) = f ( & mut self . bus ) . await ;
457
+ let f_res = f ( & mut self . bus ) . await ;
470
458
471
459
// On failure, it's important to still flush and deassert CS.
472
- let flush_res = bus. flush ( ) . await ;
460
+ let flush_res = self . bus . flush ( ) . await ;
473
461
let cs_res = self . cs . set_high ( ) ;
474
462
475
463
let f_res = f_res. map_err ( ExclusiveDeviceError :: Spi ) ?;
0 commit comments