Skip to content

Commit b2fd84b

Browse files
bors[bot]Dirbaioandrewgazelka
authored
Merge #19
19: Remove static {read,write} buffers r=eldruin a=andrewgazelka - Fixes #17 - Fixes #10 - This is essentially a copy of #13 but with the documentation change requirements that were never made. Since the mentioned PR has been stale since March, I found it fair to make another PR. I am potentially concerned regarding a use case for non-static buffers in the previous docs in the embedded-dma: > The reason we don't require `'static` in the traits themselves is because it would block implementations that can deal with stack allocated buffers, like APIs that use closures to prevent memory corruption. Can someone provide an example of an API that use closures to prevent memory corruption? If closures have a valid use case, #18 might be a better option. Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net> Co-authored-by: Andrew Gazelka <andrew.gazelka@gmail.com>
2 parents be053d3 + 03ac551 commit b2fd84b

File tree

2 files changed

+22
-122
lines changed

2 files changed

+22
-122
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Changed
11+
- [breaking change] `StaticReadBuffer` and `StaticWriteBuffer` no longer exist. Instead use `ReadBuffer`, `WriteBuffer`.
12+
13+
### Added
14+
- Replace less strict `ReadBuffer` and `WriteBuffer` definitions with
15+
those of `StaticReadBuffer` and `StaticWriteBuffer`. This removes the separate static
16+
traits.
17+
1018
## [v0.1.2] - 2020-09-30
1119

1220
### Added

src/lib.rs

Lines changed: 14 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Traits to aid the correct use of buffers in DMA abstractions.
22
//!
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
44
//! buffers types used in DMA operations.
55
//!
66
//! There are some subtleties to the extent of the guarantees provided by these traits, all of these
@@ -11,27 +11,12 @@
1111
//! `Self` (with the exception of [`write_buffer`](trait.WriteBuffer.html#tymethod.write_buffer) in
1212
//! our case). This is to allow types like `Vec`, this restriction doesn't apply to `Self::Target`.
1313
//!
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.
2917
//!
3018
//! The above list is not exhaustive, for a complete set of requirements and guarantees, the
3119
//! documentation of each trait and method should be analyzed.
32-
//!
33-
//! [StaticReadBuffer]: trait.StaticReadBuffer.html
34-
//! [StaticWriteBuffer]: trait.StaticWriteBuffer.html
3520
#![no_std]
3621

3722
use core::{
@@ -51,7 +36,7 @@ use stable_deref_trait::StableDeref;
5136
/// - `read_buffer` must always return the same value, if called multiple
5237
/// times.
5338
/// - 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.
5540
pub unsafe trait ReadBuffer {
5641
type Word;
5742

@@ -82,7 +67,7 @@ pub unsafe trait ReadBuffer {
8267
/// - `write_buffer` must always return the same value, if called multiple
8368
/// times.
8469
/// - 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.
8671
pub unsafe trait WriteBuffer {
8772
type Word;
8873

@@ -105,7 +90,7 @@ pub unsafe trait WriteBuffer {
10590

10691
unsafe impl<B, T> ReadBuffer for B
10792
where
108-
B: Deref<Target = T> + StableDeref,
93+
B: Deref<Target = T> + StableDeref + 'static,
10994
T: ReadTarget + ?Sized,
11095
{
11196
type Word = T::Word;
@@ -117,7 +102,7 @@ where
117102

118103
unsafe impl<B, T> WriteBuffer for B
119104
where
120-
B: DerefMut<Target = T> + StableDeref,
105+
B: DerefMut<Target = T> + StableDeref + 'static,
121106
T: WriteTarget + ?Sized,
122107
{
123108
type Word = T::Word;
@@ -153,7 +138,7 @@ unsafe impl Word for i64 {}
153138
/// # Safety
154139
///
155140
/// - `as_read_buffer` must adhere to the safety requirements
156-
/// documented for `DmaReadBuffer::dma_read_buffer`.
141+
/// documented for [`ReadBuffer::read_buffer`].
157142
pub unsafe trait ReadTarget {
158143
type Word: Word;
159144

@@ -172,7 +157,7 @@ pub unsafe trait ReadTarget {
172157
/// # Safety
173158
///
174159
/// - `as_write_buffer` must adhere to the safety requirements
175-
/// documented for `DmaWriteBuffer::dma_write_buffer`.
160+
/// documented for [`WriteBuffer::write_buffer`].
176161
pub unsafe trait WriteTarget {
177162
type Word: Word;
178163

@@ -256,75 +241,6 @@ unsafe impl<T: WriteTarget> WriteTarget for MaybeUninit<T> {
256241
type Word = T::Word;
257242
}
258243

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-
328244
#[cfg(test)]
329245
mod tests {
330246
use super::*;
@@ -337,54 +253,30 @@ mod tests {
337253
unsafe { buffer.read_buffer() }
338254
}
339255

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-
347256
fn api_write<W, B>(mut buffer: B) -> (*mut W, usize)
348257
where
349258
B: WriteBuffer<Word = W>,
350259
{
351260
unsafe { buffer.write_buffer() }
352261
}
353262

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-
361263
#[test]
362264
fn read_api() {
363265
const SIZE: usize = 128;
364266
static BUF: [u8; SIZE] = [0u8; SIZE];
365-
let local_buf = [0u8; SIZE];
366267

367-
let (ptr, size_local) = api_read(&local_buf);
268+
let (ptr, size_local) = api_read(&BUF);
368269
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);
374271
}
375272

376273
#[test]
377274
fn write_api() {
378275
const SIZE: usize = 128;
379276
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);
385277

386-
let (ptr, size_static) = static_api_write(unsafe { &mut BUF });
278+
let (ptr, size_local) = api_write(unsafe { &mut BUF });
387279
assert!(unsafe { (&*ptr as &dyn Any).is::<u8>() });
388-
assert!(size_static == SIZE);
280+
assert_eq!(size_local, SIZE);
389281
}
390282
}

0 commit comments

Comments
 (0)