From 3459be774791dfa082c6a17837e32dffe5b46e8e Mon Sep 17 00:00:00 2001 From: Charles thompson Date: Tue, 7 Oct 2025 08:21:41 -0400 Subject: [PATCH 1/3] Added SliceWrapper and SliceWrapperMut --- src/lib.rs | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index dc009a5..1452b94 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -235,3 +235,179 @@ mod tests { assert_eq!(size_local, SIZE); } } + +pub struct SliceWrapperPointer { + pointer: *const T, + length: usize, +} + +unsafe impl ReadBuffer for SliceWrapperPointer { + type Word = T; + unsafe fn read_buffer(&self) -> (*const Self::Word, usize) { + (self.pointer, self.length) + } +} + +#[derive(Debug)] +pub struct SliceWrapper<'a, T> { + inner: &'a [T], + pointer_alive: bool, +} + +impl<'a, T> SliceWrapper<'a, T> { + /// Wrap a slice to ensure the DMA transfer is complete by the time this + /// reference is dropped. + /// + /// # Safety + /// This type would cause undefined behavior and likely a system crash/worse + /// if `std::mem::forget()` is used on this type. Since `forget()` is not + /// an unsafe function, it is best this function is just to prevent accidental + /// memory corruption. + /// + /// 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 you do not use `forget()` and you know your HAL follows the above + /// rules, this should be perfectly safe to use. + /// + /// # Usage + /// + /// Here is an example using rp2040-hal: + /// + /// ```no_run + /// let mut buffer = [0u8; 256]; + /// let mut wrapper = SliceWrapper::new(&mut buffer); + /// let pointer = wrapper.get_pointer(); + /// let transfer = dma::single_buffer::Config::new(dma, pointer, uart_tx).start(); + /// let (dma, pointer, uart_tx) = transfer.wait(); + /// wrapper.feed_pointer(pointer); + /// ``` + + pub unsafe fn new(inner: &'a [T]) -> Self { + Self { + inner, + pointer_alive: false, + } + } + + pub fn get_pointer(&mut self) -> SliceWrapperPointer { + if self.pointer_alive { + panic!("SliceWrapperPointer already referenced in scope"); + } + self.pointer_alive = true; + + SliceWrapperPointer { + pointer: self.inner.as_ptr(), + length: self.inner.len(), + } + } + + pub fn feed_pointer(&mut self, pointer: SliceWrapperPointer) { + if pointer.pointer != self.inner.as_ptr() { + panic!("Attempted to feed SliceWrapper an invalid pointer"); + } + + self.pointer_alive = false; + } +} + +impl<'a, T> Drop for SliceWrapper<'a, T> { + fn drop(&mut self) { + if self.pointer_alive { + panic!("SliceWrapper has not been fed it's pointer"); + } + } +} + +pub struct SliceWrapperPointerMut { + pointer: *mut T, + length: usize, +} + +unsafe impl ReadBuffer for SliceWrapperPointerMut { + type Word = T; + unsafe fn read_buffer(&self) -> (*const Self::Word, usize) { + (self.pointer, self.length) + } +} + +unsafe impl WriteBuffer for SliceWrapperPointerMut { + type Word = T; + unsafe fn write_buffer(&mut self) -> (*mut Self::Word, usize) { + (self.pointer, self.length) + } +} + +#[derive(Debug)] +pub struct SliceWrapperMut<'a, T> { + inner: &'a mut [T], + pointer_alive: bool, +} + +impl<'a, T> SliceWrapperMut<'a, T> { + /// Wrap a slice to ensure the DMA transfer is complete by the time this + /// reference is dropped. + /// + /// # Safety + /// This type would cause undefined behavior and likely a system crash/worse + /// if `std::mem::forget()` is used on this type. Since `forget()` is not + /// an unsafe function, it is best this function is just to prevent accidental + /// memory corruption. + /// + /// 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 you do not use `forget()` and you know your HAL follows the above + /// rules, this should be perfectly safe to use. + /// + /// # Usage + /// + /// Here is an example using rp2040-hal: + /// + /// ```no_run + /// let mut buffer = [0u8; 256]; + /// let mut wrapper = SliceWrapperMut::new(&mut buffer); + /// let pointer = wrapper.get_pointer(); + /// let transfer = dma::single_buffer::Config::new(dma, pointer, uart_tx).start(); + /// let (dma, pointer, uart_tx) = transfer.wait(); + /// wrapper.feed_pointer(pointer); + /// ``` + pub fn new(inner: &'a mut [T]) -> Self { + Self { + inner, + pointer_alive: false, + } + } + + pub fn get_pointer(&mut self) -> SliceWrapperPointerMut { + if self.pointer_alive { + panic!("SliceWrapperPointer already referenced in scope"); + } + self.pointer_alive = true; + + SliceWrapperPointerMut { + pointer: self.inner.as_mut_ptr(), + length: self.inner.len(), + } + } + + pub fn feed_pointer(&mut self, pointer: SliceWrapperPointerMut) { + if pointer.pointer != self.inner.as_mut_ptr() { + panic!("Attempted to feed SliceWrapper an invalid pointer"); + } + + self.pointer_alive = false; + } +} + +impl<'a, T> Drop for SliceWrapperMut<'a, T> { + fn drop(&mut self) { + if self.pointer_alive { + panic!("SliceWrapper has not been fed it's pointer"); + } + } +} From 0a92fa18be554d18d87c2b08228f952cbfcc469e Mon Sep 17 00:00:00 2001 From: Charles thompson Date: Tue, 7 Oct 2025 08:23:58 -0400 Subject: [PATCH 2/3] Fixed some doc errors --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1452b94..3ad5e23 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -276,7 +276,7 @@ impl<'a, T> SliceWrapper<'a, T> { /// /// Here is an example using rp2040-hal: /// - /// ```no_run + /// ```ignore /// let mut buffer = [0u8; 256]; /// let mut wrapper = SliceWrapper::new(&mut buffer); /// let pointer = wrapper.get_pointer(); @@ -368,7 +368,7 @@ impl<'a, T> SliceWrapperMut<'a, T> { /// /// Here is an example using rp2040-hal: /// - /// ```no_run + /// ```ignore /// let mut buffer = [0u8; 256]; /// let mut wrapper = SliceWrapperMut::new(&mut buffer); /// let pointer = wrapper.get_pointer(); From fcaf1076f559b7442509b505a2a4f49e5586de78 Mon Sep 17 00:00:00 2001 From: Charles thompson Date: Tue, 7 Oct 2025 08:32:09 -0400 Subject: [PATCH 3/3] Fixed more doc errors --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3ad5e23..157e92d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -278,7 +278,7 @@ impl<'a, T> SliceWrapper<'a, T> { /// /// ```ignore /// let mut buffer = [0u8; 256]; - /// let mut wrapper = SliceWrapper::new(&mut buffer); + /// let mut wrapper = unsafe { SliceWrapper::new(&mut buffer) }; /// let pointer = wrapper.get_pointer(); /// let transfer = dma::single_buffer::Config::new(dma, pointer, uart_tx).start(); /// let (dma, pointer, uart_tx) = transfer.wait(); @@ -370,7 +370,7 @@ impl<'a, T> SliceWrapperMut<'a, T> { /// /// ```ignore /// let mut buffer = [0u8; 256]; - /// let mut wrapper = SliceWrapperMut::new(&mut buffer); + /// let mut wrapper = unsafe { SliceWrapperMut::new(&mut buffer) }; /// let pointer = wrapper.get_pointer(); /// let transfer = dma::single_buffer::Config::new(dma, pointer, uart_tx).start(); /// let (dma, pointer, uart_tx) = transfer.wait();