35
35
Word : Copy + ' static ,
36
36
= impl Future < Output = Result < ( ) , T :: Error > > ;
37
37
38
+ #[ macro_export]
39
+ /// This macro is a workaround for the workaround in [`SpiDevice::transaction`]
40
+ ///
41
+ /// # Examples
42
+ ///
43
+ /// ```
44
+ /// use embedded_hal_async::spi::{transaction_helper, SpiBus, SpiBusRead, SpiBusWrite, SpiDevice};
45
+ ///
46
+ /// pub async fn transaction_example<SPI>(mut device: SPI) -> Result<u32, SPI::Error>
47
+ /// where
48
+ /// SPI: SpiDevice,
49
+ /// SPI::Bus: SpiBus,
50
+ /// {
51
+ /// transaction_helper!(&mut device, move |bus| async move {
52
+ /// // Unlike `SpiDevice::transaction`, we don't need to
53
+ /// // manually dereference a pointer in order to use the bus.
54
+ /// bus.write(&[42]).await?;
55
+ /// let mut data = [0; 4];
56
+ /// bus.read(&mut data).await?;
57
+ /// Ok(u32::from_be_bytes(data))
58
+ /// })
59
+ /// .await
60
+ /// }
61
+ /// ```
62
+ macro_rules! spi_transaction_helper {
63
+ ( $device: expr, move |$bus: ident| async move $closure_body: expr) => {
64
+ $crate:: spi:: SpiDevice :: transaction( $device, move |$bus| async move {
65
+ // Safety: Implementers of the `SpiDevice` trait guarantee that the pointer is
66
+ // valid and dereferencable for the entire duration of the closure.
67
+ let $bus = unsafe { & mut * $bus } ;
68
+ let result = $closure_body;
69
+ :: core:: mem:: drop( $bus) ; // Ensure that the bus reference was not moved out of the closure
70
+ result
71
+ } )
72
+ } ;
73
+ }
74
+
75
+ #[ doc( inline) ]
76
+ pub use spi_transaction_helper as transaction_helper;
77
+
38
78
/// SPI device trait
39
79
///
40
80
/// `SpiDevice` represents ownership over a single SPI device on a (possibly shared) bus, selected
@@ -95,11 +135,7 @@ pub unsafe trait SpiDevice: ErrorType {
95
135
Self :: Bus : SpiBusRead < Word > ,
96
136
Word : Copy + ' static ,
97
137
{
98
- self . transaction ( move |bus| async move {
99
- // safety: `bus` is a valid pointer we're allowed to use for the duration of the closure.
100
- let bus = unsafe { & mut * bus } ;
101
- bus. read ( buf) . await
102
- } )
138
+ transaction_helper ! ( self , move |bus| async move { bus. read( buf) . await } )
103
139
}
104
140
105
141
/// Do a write within a transaction.
@@ -112,11 +148,7 @@ pub unsafe trait SpiDevice: ErrorType {
112
148
Self :: Bus : SpiBusWrite < Word > ,
113
149
Word : Copy + ' static ,
114
150
{
115
- self . transaction ( move |bus| async move {
116
- // safety: `bus` is a valid pointer we're allowed to use for the duration of the closure.
117
- let bus = unsafe { & mut * bus } ;
118
- bus. write ( buf) . await
119
- } )
151
+ transaction_helper ! ( self , move |bus| async move { bus. write( buf) . await } )
120
152
}
121
153
122
154
/// Do a transfer within a transaction.
@@ -133,11 +165,10 @@ pub unsafe trait SpiDevice: ErrorType {
133
165
Self :: Bus : SpiBus < Word > ,
134
166
Word : Copy + ' static ,
135
167
{
136
- self . transaction ( move |bus| async move {
137
- // safety: `bus` is a valid pointer we're allowed to use for the duration of the closure.
138
- let bus = unsafe { & mut * bus } ;
139
- bus. transfer ( read, write) . await
140
- } )
168
+ transaction_helper ! (
169
+ self ,
170
+ move |bus| async move { bus. transfer( read, write) . await }
171
+ )
141
172
}
142
173
143
174
/// Do an in-place transfer within a transaction.
@@ -153,11 +184,10 @@ pub unsafe trait SpiDevice: ErrorType {
153
184
Self :: Bus : SpiBus < Word > ,
154
185
Word : Copy + ' static ,
155
186
{
156
- self . transaction ( move |bus| async move {
157
- // safety: `bus` is a valid pointer we're allowed to use for the duration of the closure.
158
- let bus = unsafe { & mut * bus } ;
159
- bus. transfer_in_place ( buf) . await
160
- } )
187
+ transaction_helper ! (
188
+ self ,
189
+ move |bus| async move { bus. transfer_in_place( buf) . await }
190
+ )
161
191
}
162
192
}
163
193
0 commit comments