diff --git a/CHANGELOG.md b/CHANGELOG.md index 81916ef..268d4e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # [unreleased] +# [v0.1.2] 2026-06-08 + +- Released with new name `raw-buffer`. +- Added more safety notes. + # [v0.1.1] Badge fix, points to wrong crate. @@ -16,5 +21,11 @@ Badge fix, points to wrong crate. Initial release +# Release with new name + +[v0.1.2]: https://egit.irs.uni-stuttgart.de/rust/raw-buffer/releases/tag/v0.1.2 + +# Release with old name `raw-slicee` + [v0.1.1]: https://egit.irs.uni-stuttgart.de/rust/raw-slice/compare/v0.1.0...v0.1.1 [v0.1.0]: https://egit.irs.uni-stuttgart.de/rust/raw-slice/releases/tag/v0.1.0 diff --git a/Cargo.toml b/Cargo.toml index b0500a5..dac01c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,19 +1,15 @@ [package] -name = "raw-slicee" -version = "0.1.1" +name = "raw-buffer" +version = "0.1.2" edition = "2024" rust-version = "1.85.1" authors = ["Robin Mueller "] description = "Generic low-level raw slice types" -homepage = "https://egit.irs.uni-stuttgart.de/rust/raw-slice" -repository = "https://egit.irs.uni-stuttgart.de/rust/raw-slice" +homepage = "https://egit.irs.uni-stuttgart.de/rust/raw-buffer" +repository = "https://egit.irs.uni-stuttgart.de/rust/raw-buffer" license = "Apache-2.0 OR MIT" keywords = ["no-std", "slice", "embedded", "dma", "pointer"] categories = ["no-std", "no-std::no-alloc", "hardware-support", "embedded", "data-structures"] -# Name was hogged. -[lib] -name = "raw_slice" - [dependencies] embedded-dma = "0.2" diff --git a/src/lib.rs b/src/lib.rs index 2b74f8d..701ffa3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ //! This data structure is particularly useful in embedded systems, where data may be //! passed to asynchronous peripherals such as serial TX drivers using interrupts or DMA. //! The data may be static, but it could also reside on the stack. By using a shared [RawBufSlice], -//! you can pass borrowed data to a driver **without** needing to explicitly manage lifetimes. +//! you can pass borrowed data to a driver without needing to explicitly manage lifetimes. //! //! ## Safety Considerations //! @@ -22,6 +22,12 @@ //! (e.g., an ISR and a task) requires proper synchronization. //! - **Immutability:** [RawSlice] provides a **read-only view** of the data. If you need //! mutability, [RawSliceMut] can be used. +//! - If the raw slice wrapper is used with stack allocated slices: Higher-level APIs +//! oftentimes rely on `Drop` implementations to allow cancelling +//! transfers on non-blocking APIs. Using `core::mem::forget` on such implementations +//! can leak the underlying memory. HAL and firmware authors *MUST* either use this +//! abstraction combined with `'static` slices or ensure that the `Drop` +//! implementations always runs properly. //! //! ## Usage Example //! @@ -30,7 +36,9 @@ //! //! static DATA: &[u8] = &[1, 2, 3, 4]; //! -//! let raw_buf = unsafe { RawBufSlice::new(DATA) }; +//! // Safety: Your safety note here. We are using static data, your DMA might have other +//! // requirements to the buffer used, e.g. buffer in correct RAM, with certain alignment etc. +//! let raw_buf = unsafe { RawSlice::new(DATA) }; //! //! // Later, in an ISR or different context //! unsafe { @@ -68,9 +76,9 @@ impl RawSlice { /// /// # Safety /// - /// - The caller **must** ensure that the slice outlives this `RawSlice`. + /// - The caller **must** ensure that the slice outlives this `RawSlice`. This is especially + /// important if the original slice is stack allocated. /// - The original slice **must not** be mutated while this `RawSlice` is used. - #[allow(dead_code)] pub const unsafe fn new(data: &[T]) -> Self { Self { data: data.as_ptr(), @@ -90,7 +98,8 @@ impl RawSlice { /// /// # Safety /// - /// - The caller **must** ensure that the slice outlives this `RawSlice`. + /// - The caller **must** ensure that the slice outlives this `RawSlice`. This is especially + /// important if the original slice is stack allocated. /// - The original slice **must not** be mutated while this `RawSlice` is used. pub const unsafe fn set(&mut self, data: &[T]) { self.data = data.as_ptr(); @@ -153,11 +162,25 @@ pub type RawU32Slice = RawSlice; macro_rules! impl_dma_read_buf { ($slice_type:ident, $ty:ident) => { - /// This allows using [Self] in DMA APIs which expect a [embedded_dma::ReadBuffer]. + /// This allows using [Self] in DMA based APIs which expect a [embedded_dma::ReadBuffer]. /// /// However, the user still must ensure that any alignment rules for DMA buffers required by /// the hardware are met and than any MPU/MMU configuration necessary is also performed for this /// to work properly. + /// + /// # Safety + /// + /// - The raw slice type erases the lifetime of slice. The caller *MUST* ensure that the + /// lifetime of the slice is valid as long as the buffer is in-use by the DMA. + /// - It is also imperitive that the DMA system you're using returns the pointer + /// *only after a DMA transfer is complete*. If you're unsure check the docs and if nothing + /// is mentioned in the docs please clarify it with a project maintainer. + /// - If the raw slice wrapper is used on a stack allocated slice: Higher-level APIs + /// oftentimes rely on `Drop` implementations to allow cancelling + /// transfers on non-blocking APIs. Using `core::mem::forget` on such implementations + /// can leak the underlying memory. HAL and firmware authors *MUST* either use this + /// abstraction combined with `'static` slices or ensure that the `Drop` + /// implementations always runs properly. unsafe impl embedded_dma::ReadBuffer for $slice_type { type Word = $ty; @@ -186,9 +209,9 @@ impl RawSliceMut { /// /// # Safety /// - /// - The caller **must** ensure that the slice outlives this `RawSlice`. + /// - The caller **must** ensure that the slice outlives this `RawSlice`. This is especially + /// important if the original slice is stack allocated. /// - The original slice **must not** be mutated while this `RawSlice` is used. - #[allow(dead_code)] pub const unsafe fn new(data: &mut [T]) -> Self { Self { data: data.as_mut_ptr(), @@ -208,7 +231,8 @@ impl RawSliceMut { /// /// # Safety /// - /// - The caller **must** ensure that the slice outlives this `RawSlice`. + /// - The caller **must** ensure that the slice outlives this `RawSlice`. This is especially + /// important if the original slice is stack allocated. /// - The original slice **must not** be mutated while this `RawSlice` is used. pub const unsafe fn set(&mut self, data: &mut [T]) { self.data = data.as_mut_ptr(); @@ -288,6 +312,20 @@ macro_rules! impl_dma_write_buf { /// /// However, the user still must ensure that any alignment rules for DMA buffers required by /// the hardware are met and than any MPU/MMU configuration necessary was also performed. + /// + /// # Safety + /// + /// - The raw slice type erases the lifetime of slice. The caller *MUST* ensure that the + /// lifetime of the slice is valid as long as the buffer is in-use by the DMA. + /// - It is also imperitive that the DMA system you're using returns the pointer + /// *only after a DMA transfer is complete*. If you're unsure check the docs and if nothing + /// is mentioned in the docs please clarify it with a project maintainer. + /// - If the raw slice wrapper is used on a stack allocated slice: Higher-level APIs + /// oftentimes rely on `Drop` implementations to allow cancelling + /// transfers on non-blocking APIs. Using `core::mem::forget` on such implementations + /// can leak the underlying memory, allowing hardware to write to invalid memory + /// locations. HAL and firmware authors *MUST* either use this abstraction combined with + /// `'static` slices or ensure that the `Drop` implementations always runs properly. unsafe impl embedded_dma::WriteBuffer for $slice_type { type Word = $ty;