1
1
//! Traits to aid the correct use of buffers in DMA abstractions.
2
2
//!
3
- //! This library provides the `ReadBuffer` and `WriteBuffer` unsafe traits to be used as bounds to
3
+ //! This library provides the [ `ReadBuffer`] and [ `WriteBuffer`] unsafe traits to be used as bounds to
4
4
//! buffers types used in DMA operations.
5
5
//!
6
6
//! There are some subtleties to the extent of the guarantees provided by these traits, all of these
11
11
//! `Self` (with the exception of [`write_buffer`](trait.WriteBuffer.html#tymethod.write_buffer) in
12
12
//! our case). This is to allow types like `Vec`, this restriction doesn't apply to `Self::Target`.
13
13
//!
14
- //! * The location is only guaranteed to be stable for the duration of `Self`, that means that
15
- //! `Self` doesn't need to be `'static`, i.e. `&'a [u8]` is valid. This can be a bit subtle for
16
- //! most DMA abstractions, because they almost always require `'static`, given the intrinsics of
17
- //! `mem::forget` and the Rust language itself. Those APIs must also bound to `'static` and not only
18
- //! `WriteBuffer`/`ReadBuffer`. The reason we don't require `'static` in the traits themselves is
19
- //! because it would block implementations that can deal with stack allocated buffers, like APIs
20
- //! that use closures to prevent memory corruption.
21
- //!
22
- //! If your API also needs a `'static` bound, prefer the use of [StaticReadBuffer] and
23
- //! [StaticWriteBuffer]. They are a stricter version that requires a `'static` lifetime invariant,
24
- //! while also allowing end users to __unsafely__ bypass it.
25
- //!
26
- //! If you are not sure which version of the traits you should be bounding to in your DMA
27
- //! implementations, prefer the "Static" versions, they are sound for a bigger number of techniques
28
- //! that deal with DMA.
14
+ //! * [`ReadBuffer`] and [`WriteBuffer`] guarantee a stable location for as long as the DMA transfer
15
+ //! occurs. Given the intrinsics of `mem::forget` and the Rust language itself, a
16
+ //! 'static lifetime is usually required.
29
17
//!
30
18
//! The above list is not exhaustive, for a complete set of requirements and guarantees, the
31
19
//! documentation of each trait and method should be analyzed.
32
- //!
33
- //! [StaticReadBuffer]: trait.StaticReadBuffer.html
34
- //! [StaticWriteBuffer]: trait.StaticWriteBuffer.html
35
20
#![ no_std]
36
21
37
22
use core:: {
@@ -51,7 +36,7 @@ use stable_deref_trait::StableDeref;
51
36
/// - `read_buffer` must always return the same value, if called multiple
52
37
/// times.
53
38
/// - The memory specified by the pointer and size returned by `read_buffer`
54
- /// must not be freed as long as `self` is not dropped.
39
+ /// must not be freed during the transfer it is used in as long as `self` is not dropped.
55
40
pub unsafe trait ReadBuffer {
56
41
type Word ;
57
42
@@ -82,7 +67,7 @@ pub unsafe trait ReadBuffer {
82
67
/// - `write_buffer` must always return the same value, if called multiple
83
68
/// times.
84
69
/// - The memory specified by the pointer and size returned by `write_buffer`
85
- /// must not be freed as long as `self` is not dropped.
70
+ /// must not be freed during the transfer as long as `self` is not dropped.
86
71
pub unsafe trait WriteBuffer {
87
72
type Word ;
88
73
@@ -105,7 +90,7 @@ pub unsafe trait WriteBuffer {
105
90
106
91
unsafe impl < B , T > ReadBuffer for B
107
92
where
108
- B : Deref < Target = T > + StableDeref ,
93
+ B : Deref < Target = T > + StableDeref + ' static ,
109
94
T : ReadTarget + ?Sized ,
110
95
{
111
96
type Word = T :: Word ;
@@ -117,7 +102,7 @@ where
117
102
118
103
unsafe impl < B , T > WriteBuffer for B
119
104
where
120
- B : DerefMut < Target = T > + StableDeref ,
105
+ B : DerefMut < Target = T > + StableDeref + ' static ,
121
106
T : WriteTarget + ?Sized ,
122
107
{
123
108
type Word = T :: Word ;
@@ -153,7 +138,7 @@ unsafe impl Word for i64 {}
153
138
/// # Safety
154
139
///
155
140
/// - `as_read_buffer` must adhere to the safety requirements
156
- /// documented for `DmaReadBuffer::dma_read_buffer` .
141
+ /// documented for [`ReadBuffer::read_buffer`] .
157
142
pub unsafe trait ReadTarget {
158
143
type Word : Word ;
159
144
@@ -172,7 +157,7 @@ pub unsafe trait ReadTarget {
172
157
/// # Safety
173
158
///
174
159
/// - `as_write_buffer` must adhere to the safety requirements
175
- /// documented for `DmaWriteBuffer::dma_write_buffer` .
160
+ /// documented for [`WriteBuffer::write_buffer`] .
176
161
pub unsafe trait WriteTarget {
177
162
type Word : Word ;
178
163
@@ -256,75 +241,6 @@ unsafe impl<T: WriteTarget> WriteTarget for MaybeUninit<T> {
256
241
type Word = T :: Word ;
257
242
}
258
243
259
- /// Trait for buffers that can be given to DMA for reading. This is a more strict version of
260
- /// [ReadBuffer](trait.ReadBuffer.html), if you are not sure about which one to use on your safe
261
- /// API, prefer this one. This trait also allows end users to __unsafely__ bypass the `'static`
262
- /// invariant.
263
- ///
264
- /// # Safety
265
- ///
266
- /// This has the same invariants as [ReadBuffer](trait.ReadBuffer.html) with the additional
267
- /// requirement that the buffer should have a `'static` lifetime.
268
- pub unsafe trait StaticReadBuffer : ReadBuffer {
269
- type Word ;
270
-
271
- /// Provide a buffer usable for DMA reads.
272
- ///
273
- /// The return value is:
274
- ///
275
- /// - pointer to the start of the buffer
276
- /// - buffer size in words
277
- ///
278
- /// # Safety
279
- ///
280
- /// Once this method has been called, it is unsafe to call any `&mut self`
281
- /// methods on this object as long as the returned value is in use (by DMA).
282
- unsafe fn static_read_buffer ( & self ) -> ( * const <Self as StaticReadBuffer >:: Word , usize ) ;
283
- }
284
-
285
- /// Trait for buffers that can be given to DMA for writing. This is a more strict version of
286
- /// [WriteBuffer](trait.WriteBuffer.html), if you are not sure about which one to use on your safe
287
- /// API, prefer this one. This trait also allows end users to __unsafely__ bypass the `'static`
288
- /// invariant.
289
- ///
290
- /// # Safety
291
- ///
292
- /// This has the same invariants as [WriteBuffer](trait.WriteBuffer.html) with the additional
293
- /// requirement that the buffer should have a `'static` lifetime.
294
- pub unsafe trait StaticWriteBuffer : WriteBuffer {
295
- type Word ;
296
-
297
- /// Provide a buffer usable for DMA writes.
298
- ///
299
- /// The return value is:
300
- ///
301
- /// - pointer to the start of the buffer
302
- /// - buffer size in words
303
- ///
304
- /// # Safety
305
- ///
306
- /// Once this method has been called, it is unsafe to call any `&mut self`
307
- /// methods, except for `write_buffer`, on this object as long as the
308
- /// returned value is in use (by DMA).
309
- unsafe fn static_write_buffer ( & mut self ) -> ( * mut <Self as StaticWriteBuffer >:: Word , usize ) ;
310
- }
311
-
312
- unsafe impl < B : ReadBuffer + ' static > StaticReadBuffer for B {
313
- type Word = <Self as ReadBuffer >:: Word ;
314
-
315
- unsafe fn static_read_buffer ( & self ) -> ( * const <Self as StaticReadBuffer >:: Word , usize ) {
316
- self . read_buffer ( )
317
- }
318
- }
319
-
320
- unsafe impl < B : WriteBuffer + ' static > StaticWriteBuffer for B {
321
- type Word = <Self as WriteBuffer >:: Word ;
322
-
323
- unsafe fn static_write_buffer ( & mut self ) -> ( * mut <Self as StaticWriteBuffer >:: Word , usize ) {
324
- self . write_buffer ( )
325
- }
326
- }
327
-
328
244
#[ cfg( test) ]
329
245
mod tests {
330
246
use super :: * ;
@@ -337,54 +253,30 @@ mod tests {
337
253
unsafe { buffer. read_buffer ( ) }
338
254
}
339
255
340
- fn static_api_read < W , B > ( buffer : B ) -> ( * const W , usize )
341
- where
342
- B : StaticReadBuffer < Word = W > ,
343
- {
344
- unsafe { buffer. static_read_buffer ( ) }
345
- }
346
-
347
256
fn api_write < W , B > ( mut buffer : B ) -> ( * mut W , usize )
348
257
where
349
258
B : WriteBuffer < Word = W > ,
350
259
{
351
260
unsafe { buffer. write_buffer ( ) }
352
261
}
353
262
354
- fn static_api_write < W , B > ( mut buffer : B ) -> ( * mut W , usize )
355
- where
356
- B : StaticWriteBuffer < Word = W > ,
357
- {
358
- unsafe { buffer. static_write_buffer ( ) }
359
- }
360
-
361
263
#[ test]
362
264
fn read_api ( ) {
363
265
const SIZE : usize = 128 ;
364
266
static BUF : [ u8 ; SIZE ] = [ 0u8 ; SIZE ] ;
365
- let local_buf = [ 0u8 ; SIZE ] ;
366
267
367
- let ( ptr, size_local) = api_read ( & local_buf ) ;
268
+ let ( ptr, size_local) = api_read ( & BUF ) ;
368
269
assert ! ( unsafe { ( & * ptr as & dyn Any ) . is:: <u8 >( ) } ) ;
369
- assert ! ( size_local == SIZE ) ;
370
-
371
- let ( ptr, size_static) = static_api_read ( & BUF ) ;
372
- assert ! ( unsafe { ( & * ptr as & dyn Any ) . is:: <u8 >( ) } ) ;
373
- assert ! ( size_static == SIZE ) ;
270
+ assert_eq ! ( size_local, SIZE ) ;
374
271
}
375
272
376
273
#[ test]
377
274
fn write_api ( ) {
378
275
const SIZE : usize = 128 ;
379
276
static mut BUF : [ u8 ; SIZE ] = [ 0u8 ; SIZE ] ;
380
- let mut local_buf = [ 0u8 ; SIZE ] ;
381
-
382
- let ( ptr, size_local) = api_write ( & mut local_buf) ;
383
- assert ! ( unsafe { ( & * ptr as & dyn Any ) . is:: <u8 >( ) } ) ;
384
- assert ! ( size_local == SIZE ) ;
385
277
386
- let ( ptr, size_static ) = static_api_write ( unsafe { & mut BUF } ) ;
278
+ let ( ptr, size_local ) = api_write ( unsafe { & mut BUF } ) ;
387
279
assert ! ( unsafe { ( & * ptr as & dyn Any ) . is:: <u8 >( ) } ) ;
388
- assert ! ( size_static == SIZE ) ;
280
+ assert_eq ! ( size_local , SIZE ) ;
389
281
}
390
282
}
0 commit comments