diff --git a/bbqtest/src/benches.rs b/bbqtest/src/benches.rs index 689607b..c6b51e6 100644 --- a/bbqtest/src/benches.rs +++ b/bbqtest/src/benches.rs @@ -1,4 +1,4 @@ -use bbqueue::{consts::*, BBBuffer}; +use bbqueue::{consts::*, GenericBBBuffer}; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use std::cmp::min; @@ -17,7 +17,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { c.bench_function("bbq 2048/4096", |bench| bench.iter(|| chunky(&data, 2048))); - let buffy: BBBuffer = BBBuffer::new(); + let buffy: GenericBBBuffer = GenericBBBuffer::new(); let (mut prod, mut cons) = buffy.try_split().unwrap(); c.bench_function("bbq 8192/65536", |bench| { @@ -196,7 +196,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { use crossbeam_utils::thread; fn chunky(data: &[u8], chunksz: usize) { - let buffy: BBBuffer = BBBuffer::new(); + let buffy: GenericBBBuffer = GenericBBBuffer::new(); let (mut prod, mut cons) = buffy.try_split().unwrap(); thread::scope(|sc| { diff --git a/bbqtest/src/lib.rs b/bbqtest/src/lib.rs index ec9d3b4..103e92b 100644 --- a/bbqtest/src/lib.rs +++ b/bbqtest/src/lib.rs @@ -7,7 +7,7 @@ mod single_thread; #[cfg(test)] mod tests { - use bbqueue::{consts::*, BBBuffer, ConstBBBuffer, Error as BBQError}; + use bbqueue::{consts::*, BBBuffer, ConstBBBuffer, Error as BBQError, GenericBBBuffer}; #[test] fn deref_deref_mut() { @@ -34,8 +34,8 @@ mod tests { #[test] fn static_allocator() { // Check we can make multiple static items... - static BBQ1: BBBuffer = BBBuffer(ConstBBBuffer::new()); - static BBQ2: BBBuffer = BBBuffer(ConstBBBuffer::new()); + static BBQ1: BBBuffer = GenericBBBuffer(ConstBBBuffer::new()); + static BBQ2: BBBuffer = GenericBBBuffer(ConstBBBuffer::new()); let (mut prod1, mut cons1) = BBQ1.try_split().unwrap(); let (mut _prod2, mut cons2) = BBQ2.try_split().unwrap(); @@ -55,8 +55,8 @@ mod tests { #[test] fn release() { // Check we can make multiple static items... - static BBQ1: BBBuffer = BBBuffer(ConstBBBuffer::new()); - static BBQ2: BBBuffer = BBBuffer(ConstBBBuffer::new()); + static BBQ1: GenericBBBuffer = GenericBBBuffer(ConstBBBuffer::new()); + static BBQ2: GenericBBBuffer = GenericBBBuffer(ConstBBBuffer::new()); let (prod1, cons1) = BBQ1.try_split().unwrap(); let (prod2, cons2) = BBQ2.try_split().unwrap(); @@ -93,7 +93,7 @@ mod tests { #[test] fn direct_usage_sanity() { // Initialize - let bb: BBBuffer = BBBuffer::new(); + let bb: BBBuffer = GenericBBBuffer::new(); let (mut prod, mut cons) = bb.try_split().unwrap(); assert_eq!(cons.read(), Err(BBQError::InsufficientSize)); @@ -178,7 +178,7 @@ mod tests { #[test] fn zero_sized_grant() { - let bb: BBBuffer = BBBuffer::new(); + let bb: GenericBBBuffer = GenericBBBuffer::new(); let (mut prod, mut _cons) = bb.try_split().unwrap(); let size = 1000; @@ -191,7 +191,7 @@ mod tests { #[test] fn frame_sanity() { - let bb: BBBuffer = BBBuffer::new(); + let bb: GenericBBBuffer = GenericBBBuffer::new(); let (mut prod, mut cons) = bb.try_split_framed().unwrap(); // One frame in, one frame out @@ -238,7 +238,7 @@ mod tests { #[test] fn frame_wrap() { - let bb: BBBuffer = BBBuffer::new(); + let bb: GenericBBBuffer = GenericBBBuffer::new(); let (mut prod, mut cons) = bb.try_split_framed().unwrap(); // 10 + 1 used @@ -304,7 +304,7 @@ mod tests { #[test] fn frame_big_little() { - let bb: BBBuffer = BBBuffer::new(); + let bb: GenericBBBuffer = GenericBBBuffer::new(); let (mut prod, mut cons) = bb.try_split_framed().unwrap(); // Create a frame that should take 3 bytes for the header diff --git a/bbqtest/src/multi_thread.rs b/bbqtest/src/multi_thread.rs index a9aff77..3b964b4 100644 --- a/bbqtest/src/multi_thread.rs +++ b/bbqtest/src/multi_thread.rs @@ -1,7 +1,7 @@ #[cfg_attr(not(feature = "verbose"), allow(unused_variables))] #[cfg(test)] mod tests { - use bbqueue::{consts::*, BBBuffer, ConstBBBuffer, Error}; + use bbqueue::{consts::*, ConstBBBuffer, Error, GenericBBBuffer}; use rand::prelude::*; use std::thread::spawn; use std::time::{Duration, Instant}; @@ -13,6 +13,8 @@ mod tests { const RPT_IVAL: usize = ITERS / 100; + // Data type + type DataTy = u8; // These two should be the same type QueueSizeTy = U1024; const QUEUE_SIZE: usize = 1024; @@ -29,7 +31,7 @@ mod tests { println!("RTX: Generating Test Data..."); let gen_start = Instant::now(); let mut data = Vec::with_capacity(ITERS); - (0..ITERS).for_each(|_| data.push(rand::random::())); + (0..ITERS).for_each(|_| data.push(rand::random::())); let mut data_rx = data.clone(); let mut trng = thread_rng(); @@ -50,7 +52,7 @@ mod tests { #[cfg(feature = "verbose")] println!("RTX: Running test..."); - static BB: BBBuffer = BBBuffer(ConstBBBuffer::new()); + static BB: GenericBBBuffer = GenericBBBuffer(ConstBBBuffer::new()); let (mut tx, mut rx) = BB.try_split().unwrap(); let mut last_tx = Instant::now(); @@ -142,7 +144,7 @@ mod tests { #[test] fn sanity_check() { - static BB: BBBuffer = BBBuffer(ConstBBBuffer::new()); + static BB: GenericBBBuffer = GenericBBBuffer(ConstBBBuffer::new()); let (mut tx, mut rx) = BB.try_split().unwrap(); let mut last_tx = Instant::now(); @@ -236,7 +238,7 @@ mod tests { #[test] fn sanity_check_grant_max() { - static BB: BBBuffer = BBBuffer(ConstBBBuffer::new()); + static BB: GenericBBBuffer = GenericBBBuffer(ConstBBBuffer::new()); let (mut tx, mut rx) = BB.try_split().unwrap(); #[cfg(feature = "verbose")] diff --git a/bbqtest/src/ring_around_the_senders.rs b/bbqtest/src/ring_around_the_senders.rs index c689a2d..b025893 100644 --- a/bbqtest/src/ring_around_the_senders.rs +++ b/bbqtest/src/ring_around_the_senders.rs @@ -1,18 +1,22 @@ #[cfg(test)] mod tests { + use core::convert::TryFrom; + use core::fmt::Debug; + use bbqueue::{ - consts::*, ArrayLength, BBBuffer, ConstBBBuffer, Consumer, GrantR, GrantW, Producer, + consts::*, ArrayLength, ConstBBBuffer, Consumer, GenericBBBuffer, GrantR, GrantW, Producer, }; - enum Potato<'a, N> + enum Potato<'a, T, N> where - N: ArrayLength, + T: Sized + TryFrom, + N: ArrayLength, { - Tx((Producer<'a, N>, u8)), - Rx((Consumer<'a, N>, u8)), - TxG(GrantW<'a, N>), - RxG(GrantR<'a, N>), + Tx((Producer<'a, T, N>, u8)), + Rx((Consumer<'a, T, N>, u8)), + TxG(GrantW<'a, T, N>), + RxG(GrantR<'a, T, N>), Idle, Done, } @@ -28,9 +32,10 @@ mod tests { const BYTES_PER_GRANT: usize = 129; type BufferSize = U4096; - impl<'a, N> Potato<'a, N> + impl<'a, T, N> Potato<'a, T, N> where - N: ArrayLength, + T: Sized + TryFrom + Debug + PartialEq, + N: ArrayLength, { fn work(self) -> (Self, Self) { match self { @@ -66,7 +71,9 @@ mod tests { gr_w.iter_mut() .take(BYTES_PER_GRANT) .enumerate() - .for_each(|(i, by)| *by = i as u8); + .for_each(|(i, by)| { + *by = T::try_from(i).ok().expect("can construct from usize") + }); gr_w.commit(BYTES_PER_GRANT); (Self::Idle, Self::Idle) } @@ -74,7 +81,9 @@ mod tests { gr_r.iter() .take(BYTES_PER_GRANT) .enumerate() - .for_each(|(i, by)| assert_eq!(*by, i as u8)); + .for_each(|(i, by)| { + assert_eq!(*by, T::try_from(i).ok().expect("can construct from usize")) + }); gr_r.release(BYTES_PER_GRANT); (Self::Idle, Self::Idle) } @@ -84,31 +93,40 @@ mod tests { } } - static BB: BBBuffer = BBBuffer(ConstBBBuffer::new()); + // Data type + type DataTy = u8; + static BB: GenericBBBuffer = GenericBBBuffer(ConstBBBuffer::new()); use std::sync::mpsc::{channel, Receiver, Sender}; use std::thread::spawn; #[test] fn hello() { - let (prod, cons) = BB.try_split().unwrap(); + generic_hello::(&BB); + } + + fn generic_hello(bb: &'static GenericBBBuffer) + where + T: Sized + TryFrom + Debug + PartialEq, + { + let (prod, cons) = bb.try_split().unwrap(); // create the channels let (tx_1_2, rx_1_2): ( - Sender>, - Receiver>, + Sender>, + Receiver>, ) = channel(); let (tx_2_3, rx_2_3): ( - Sender>, - Receiver>, + Sender>, + Receiver>, ) = channel(); let (tx_3_4, rx_3_4): ( - Sender>, - Receiver>, + Sender>, + Receiver>, ) = channel(); let (tx_4_1, rx_4_1): ( - Sender>, - Receiver>, + Sender>, + Receiver>, ) = channel(); tx_1_2.send(Potato::Tx((prod, 3))).unwrap(); @@ -116,7 +134,7 @@ mod tests { let thread_1 = spawn(move || { let mut count = TOTAL_RINGS; - let mut me: Potato<'static, BufferSize> = Potato::Idle; + let mut me: Potato<'static, T, BufferSize> = Potato::Idle; loop { if let Potato::Idle = me { @@ -168,9 +186,9 @@ mod tests { }); let closure_2_3_4 = - move |rx: Receiver>, - tx: Sender>| { - let mut me: Potato<'static, BufferSize> = Potato::Idle; + move |rx: Receiver>, + tx: Sender>| { + let mut me: Potato<'static, T, BufferSize> = Potato::Idle; let mut count = 0; loop { diff --git a/bbqtest/src/single_thread.rs b/bbqtest/src/single_thread.rs index 9f8ee52..7b16497 100644 --- a/bbqtest/src/single_thread.rs +++ b/bbqtest/src/single_thread.rs @@ -1,16 +1,102 @@ #[cfg(test)] mod tests { - use bbqueue::{consts::*, BBBuffer}; + use core::convert::TryFrom; + use std::fmt::Debug; + + use bbqueue::{consts::*, GenericBBBuffer}; + + #[test] + fn sanity_check_u8() { + generic_sanity_check::(); + } #[test] - fn sanity_check() { - let bb: BBBuffer = BBBuffer::new(); + fn sanity_check_pod() { + generic_sanity_check::(); + generic_sanity_check::(); + } + + #[derive(Debug, Clone, Copy, PartialEq)] + struct U8Sized(u8); + + impl From for U8Sized { + fn from(v: u8) -> Self { + U8Sized(v) + } + } + + // TODO: tailor this to address specific error cases if any + #[derive(Debug, Clone, Copy, PartialEq)] + struct PodStruct { + array: [u8; 32], + variants: PodEnum, + } + + impl From for PodStruct { + fn from(v: u8) -> Self { + PodStruct { + array: [v; 32], + variants: PodEnum::from(v), + } + } + } + + #[derive(Debug, Clone, Copy, PartialEq)] + enum PodEnum { + Empty, + Tuple((u64, i64, usize)), + Array([i16; 16]), + } + + impl From for PodEnum { + fn from(v: u8) -> Self { + if v == 0 { + Self::Empty + } else if v < 128 { + Self::Tuple((v as u64, (v + 1) as i64, (v + 2) as usize)) + } else { + Self::Array([v as i16; 16]) + } + } + } + + #[test] + fn sanity_check_ptr() { + generic_sanity_check::(); + } + + #[derive(Debug, Clone, PartialEq)] + struct RefStruct { + vec: Vec, + maybe_boxed: Option>, + } + + impl From for RefStruct { + fn from(v: u8) -> Self { + let mut vec = Vec::with_capacity(v as usize); + vec.iter_mut().for_each(|e| *e = v); + + let maybe_boxed = Some(Box::new(RefStruct { + vec: vec.clone(), + maybe_boxed: None, + })); + RefStruct { vec, maybe_boxed } + } + } + + fn generic_sanity_check() + where + T: Sized + TryFrom + Debug + PartialEq + Clone, + { + let bb: GenericBBBuffer = GenericBBBuffer::new(); let (mut prod, mut cons) = bb.try_split().unwrap(); const ITERS: usize = 100000; for i in 0..ITERS { - let j = (i & 255) as u8; + let j = T::try_from((i & 255) as u8) + .ok() + .expect("can construct type from u8"); #[cfg(feature = "extra-verbose")] println!("==========================="); @@ -27,7 +113,7 @@ mod tests { #[cfg(feature = "extra-verbose")] println!("GRANT: {:?}", bb); - wgr[0] = j; + wgr[0] = j.clone(); #[cfg(feature = "extra-verbose")] println!("WRITE: {:?}", bb); diff --git a/core/src/bbbuffer.rs b/core/src/bbbuffer.rs index ef04f28..a93426a 100644 --- a/core/src/bbbuffer.rs +++ b/core/src/bbbuffer.rs @@ -21,18 +21,25 @@ use generic_array::{ArrayLength, GenericArray}; /// A backing structure for a BBQueue. Can be used to create either /// a BBQueue or a split Producer/Consumer pair -pub struct BBBuffer>( +#[derive(Debug)] +pub struct GenericBBBuffer>( // Underlying data storage - #[doc(hidden)] pub ConstBBBuffer>, + #[doc(hidden)] pub ConstBBBuffer>, ); +/// An alias of `GenericBBBuffer` parametrized with `u8` for operations on byte-based buffers, +/// including `try_split_framed` method, `FrameProducer` and `FrameConsumer`. +/// Added for compatibility with code depending on `BBBuffer` type name +pub type BBBuffer = GenericBBBuffer; + unsafe impl Sync for ConstBBBuffer {} -impl<'a, N> BBBuffer +impl<'a, T, N> GenericBBBuffer where - N: ArrayLength, + T: Sized, + N: ArrayLength, { - /// Attempt to split the `BBBuffer` into `Consumer` and `Producer` halves to gain access to the + /// Attempt to split the `GenericBBBuffer` into `Consumer` and `Producer` halves to gain access to the /// buffer. If buffer has already been split, an error will be returned. /// /// NOTE: When splitting, the underlying buffer will be explicitly initialized @@ -47,10 +54,10 @@ where /// ```rust /// # // bbqueue test shim! /// # fn bbqtest() { - /// use bbqueue::{BBBuffer, consts::*}; + /// use bbqueue::{GenericBBBuffer, consts::*}; /// /// // Create and split a new buffer - /// let buffer: BBBuffer = BBBuffer::new(); + /// let buffer: GenericBBBuffer = GenericBBBuffer::new(); /// let (prod, cons) = buffer.try_split().unwrap(); /// /// // Not possible to split twice @@ -63,7 +70,7 @@ where /// # bbqtest(); /// # } /// ``` - pub fn try_split(&'a self) -> Result<(Producer<'a, N>, Consumer<'a, N>)> { + pub fn try_split(&'a self) -> Result<(Producer<'a, T, N>, Consumer<'a, T, N>)> { if atomic::swap(&self.0.already_split, true, AcqRel) { return Err(Error::AlreadySplit); } @@ -91,38 +98,21 @@ where } } - /// Attempt to split the `BBBuffer` into `FrameConsumer` and `FrameProducer` halves - /// to gain access to the buffer. If buffer has already been split, an error - /// will be returned. - /// - /// NOTE: When splitting, the underlying buffer will be explicitly initialized - /// to zero. This may take a measurable amount of time, depending on the size - /// of the buffer. This is necessary to prevent undefined behavior. If the buffer - /// is placed at `static` scope within the `.bss` region, the explicit initialization - /// will be elided (as it is already performed as part of memory initialization) - /// - /// NOTE: If the `thumbv6` feature is selected, this function takes a short critical - /// section while splitting. - pub fn try_split_framed(&'a self) -> Result<(FrameProducer<'a, N>, FrameConsumer<'a, N>)> { - let (producer, consumer) = self.try_split()?; - Ok((FrameProducer { producer }, FrameConsumer { consumer })) - } - /// Attempt to release the Producer and Consumer /// /// This re-initializes the buffer so it may be split in a different mode at a later /// time. There must be no read or write grants active, or an error will be returned. /// - /// The `Producer` and `Consumer` must be from THIS `BBBuffer`, or an error will + /// The `Producer` and `Consumer` must be from THIS `GenericBBBuffer`, or an error will /// be returned. /// /// ```rust /// # // bbqueue test shim! /// # fn bbqtest() { - /// use bbqueue::{BBBuffer, consts::*}; + /// use bbqueue::{GenericBBBuffer, consts::*}; /// /// // Create and split a new buffer - /// let buffer: BBBuffer = BBBuffer::new(); + /// let buffer: GenericBBBuffer = GenericBBBuffer::new(); /// let (prod, cons) = buffer.try_split().unwrap(); /// /// // Not possible to split twice @@ -143,9 +133,9 @@ where /// ``` pub fn try_release( &'a self, - prod: Producer<'a, N>, - cons: Consumer<'a, N>, - ) -> CoreResult<(), (Producer<'a, N>, Consumer<'a, N>)> { + prod: Producer<'a, T, N>, + cons: Consumer<'a, T, N>, + ) -> CoreResult<(), (Producer<'a, T, N>, Consumer<'a, T, N>)> { // Note: Re-entrancy is not possible because we require ownership // of the producer and consumer, which are not cloneable. We also // can assume the buffer has been split, because @@ -182,13 +172,35 @@ where Ok(()) } +} + +impl<'a, N> GenericBBBuffer +where + N: ArrayLength, +{ + /// Attempt to split the `GenericBBBuffer` into `FrameConsumer` and `FrameProducer` halves + /// to gain access to the buffer. If buffer has already been split, an error + /// will be returned. + /// + /// NOTE: When splitting, the underlying buffer will be explicitly initialized + /// to zero. This may take a measurable amount of time, depending on the size + /// of the buffer. This is necessary to prevent undefined behavior. If the buffer + /// is placed at `static` scope within the `.bss` region, the explicit initialization + /// will be elided (as it is already performed as part of memory initialization) + /// + /// NOTE: If the `thumbv6` feature is selected, this function takes a short critical + /// section while splitting. + pub fn try_split_framed(&'a self) -> Result<(FrameProducer<'a, N>, FrameConsumer<'a, N>)> { + let (producer, consumer) = self.try_split()?; + Ok((FrameProducer { producer }, FrameConsumer { consumer })) + } /// Attempt to release the Producer and Consumer in Framed mode /// /// This re-initializes the buffer so it may be split in a different mode at a later /// time. There must be no read or write grants active, or an error will be returned. /// - /// The `FrameProducer` and `FrameConsumer` must be from THIS `BBBuffer`, or an error + /// The `FrameProducer` and `FrameConsumer` must be from THIS `GenericBBBuffer`, or an error /// will be returned. pub fn try_release_framed( &'a self, @@ -203,12 +215,13 @@ where } } -/// `const-fn` version BBBuffer +/// `const-fn` version GenericBBBuffer /// -/// NOTE: This is only necessary to use when creating a `BBBuffer` at static +/// NOTE: This is only necessary to use when creating a `GenericBBBuffer` at static /// scope, and is generally never used directly. This process is necessary to /// work around current limitations in `const fn`, and will be replaced in /// the future. +#[derive(Debug)] pub struct ConstBBBuffer { buf: UnsafeCell>, @@ -226,7 +239,7 @@ pub struct ConstBBBuffer { /// when exiting the inverted condition last: AtomicUsize, - /// Used by the Writer to remember what bytes are currently + /// Used by the Writer to remember what elements are currently /// allowed to be written to, but are not yet ready to be /// read from reserve: AtomicUsize, @@ -242,17 +255,17 @@ pub struct ConstBBBuffer { } impl ConstBBBuffer { - /// Create a new constant inner portion of a `BBBuffer`. + /// Create a new constant inner portion of a `GenericBBBuffer`. /// - /// NOTE: This is only necessary to use when creating a `BBBuffer` at static + /// NOTE: This is only necessary to use when creating a `GenericBBBuffer` at static /// scope, and is generally never used directly. This process is necessary to /// work around current limitations in `const fn`, and will be replaced in /// the future. /// /// ```rust,no_run - /// use bbqueue::{BBBuffer, ConstBBBuffer, consts::*}; + /// use bbqueue::{GenericBBBuffer, ConstBBBuffer, consts::*}; /// - /// static BUF: BBBuffer = BBBuffer( ConstBBBuffer::new() ); + /// static BUF: GenericBBBuffer = GenericBBBuffer( ConstBBBuffer::new() ); /// /// fn main() { /// let (prod, cons) = BUF.try_split().unwrap(); @@ -276,9 +289,9 @@ impl ConstBBBuffer { /// and can cause the .data section to be much larger than necessary. By /// forcing the `last` pointer to be zero initially, we place the structure /// in an "inverted" condition, which will be resolved on the first commited - /// bytes that are written to the structure. + /// elements (i.e. bytes) that are written to the structure. /// - /// When read == last == write, no bytes will be allowed to be read (good), but + /// When read == last == write, no elements will be allowed to be read (good), but /// write grants can be given out (also good). last: AtomicUsize::new(0), @@ -297,7 +310,7 @@ impl ConstBBBuffer { } } -/// `Producer` is the primary interface for pushing data into a `BBBuffer`. +/// `Producer` is the primary interface for pushing data into a `GenericBBBuffer`. /// There are various methods for obtaining a grant to write to the buffer, with /// different potential tradeoffs. As all grants are required to be a contiguous /// range of data, different strategies are sometimes useful when making the decision @@ -309,34 +322,41 @@ impl ConstBBBuffer { /// * User will receive a grant `sz == N` (or receive an error) /// * This may cause a wraparound if a grant of size N is not available /// at the end of the ring. -/// * If this grant caused a wraparound, the bytes that were "skipped" at the +/// * If this grant caused a wraparound, the elements that were "skipped" at the /// end of the ring will not be available until the reader reaches them, /// regardless of whether the grant commited any data or not. -/// * Maximum possible waste due to skipping: `N - 1` bytes +/// * Maximum possible waste due to skipping: `N - 1` elements /// * `grant_max_remaining(N)` /// * User will receive a grant `0 < sz <= N` (or receive an error) /// * This will only cause a wrap to the beginning of the ring if exactly -/// zero bytes are available at the end of the ring. -/// * Maximum possible waste due to skipping: 0 bytes +/// zero element slots are available at the end of the ring. +/// * Maximum possible waste due to skipping: 0 elements /// /// See [this github issue](https://github.com/jamesmunns/bbqueue/issues/38) for a /// discussion of grant methods that could be added in the future. -pub struct Producer<'a, N> +pub struct Producer<'a, T, N> where - N: ArrayLength, + T: Sized, + N: ArrayLength, { - bbq: NonNull>, + bbq: NonNull>, pd: PhantomData<&'a ()>, } -unsafe impl<'a, N> Send for Producer<'a, N> where N: ArrayLength {} +unsafe impl<'a, T, N> Send for Producer<'a, T, N> +where + T: Sized, + N: ArrayLength, +{ +} -impl<'a, N> Producer<'a, N> +impl<'a, T, N> Producer<'a, T, N> where - N: ArrayLength, + T: Sized, + N: ArrayLength, { /// Request a writable, contiguous section of memory of exactly - /// `sz` bytes. If the buffer size requested is not available, + /// `sz` element slots. If the buffer size requested is not available, /// an error will be returned. /// /// This method may cause the buffer to wrap around early if the @@ -346,18 +366,18 @@ where /// ```rust /// # // bbqueue test shim! /// # fn bbqtest() { - /// use bbqueue::{BBBuffer, consts::*}; + /// use bbqueue::{GenericBBBuffer, consts::*}; /// /// // Create and split a new buffer of 6 elements - /// let buffer: BBBuffer = BBBuffer::new(); + /// let buffer: GenericBBBuffer = GenericBBBuffer::new(); /// let (mut prod, cons) = buffer.try_split().unwrap(); /// - /// // Successfully obtain and commit a grant of four bytes + /// // Successfully obtain and commit a grant of four elements /// let mut grant = prod.grant_exact(4).unwrap(); /// assert_eq!(grant.buf().len(), 4); /// grant.commit(4); /// - /// // Try to obtain a grant of three bytes + /// // Try to obtain a grant of three elements /// assert!(prod.grant_exact(3).is_err()); /// # // bbqueue test shim! /// # } @@ -367,7 +387,7 @@ where /// # bbqtest(); /// # } /// ``` - pub fn grant_exact(&mut self, sz: usize) -> Result> { + pub fn grant_exact(&mut self, sz: usize) -> Result> { let inner = unsafe { &self.bbq.as_ref().0 }; if atomic::swap(&inner.write_in_progress, true, AcqRel) { @@ -416,7 +436,7 @@ where // This is sound, as UnsafeCell, MaybeUninit, and GenericArray // are all `#[repr(Transparent)] - let start_of_buf_ptr = inner.buf.get().cast::(); + let start_of_buf_ptr = inner.buf.get().cast::(); let grant_slice = unsafe { from_raw_parts_mut(start_of_buf_ptr.offset(start as isize), sz) }; @@ -427,7 +447,7 @@ where } /// Request a writable, contiguous section of memory of up to - /// `sz` bytes. If a buffer of size `sz` is not available without + /// `sz` elements. If a buffer of size `sz` is not available without /// wrapping, but some space (0 < available < sz) is available without /// wrapping, then a grant will be given for the remaining size at the /// end of the buffer. If no space is available for writing, an error @@ -436,23 +456,23 @@ where /// ``` /// # // bbqueue test shim! /// # fn bbqtest() { - /// use bbqueue::{BBBuffer, consts::*}; + /// use bbqueue::{GenericBBBuffer, consts::*}; /// /// // Create and split a new buffer of 6 elements - /// let buffer: BBBuffer = BBBuffer::new(); + /// let buffer: GenericBBBuffer = GenericBBBuffer::new(); /// let (mut prod, mut cons) = buffer.try_split().unwrap(); /// - /// // Successfully obtain and commit a grant of four bytes + /// // Successfully obtain and commit a grant of four elements /// let mut grant = prod.grant_max_remaining(4).unwrap(); /// assert_eq!(grant.buf().len(), 4); /// grant.commit(4); /// - /// // Release the four initial commited bytes + /// // Release the four initial commited elements /// let mut grant = cons.read().unwrap(); /// assert_eq!(grant.buf().len(), 4); /// grant.release(4); /// - /// // Try to obtain a grant of three bytes, get two bytes + /// // Try to obtain a grant of three elements, get two elements /// let mut grant = prod.grant_max_remaining(3).unwrap(); /// assert_eq!(grant.buf().len(), 2); /// grant.commit(2); @@ -464,7 +484,7 @@ where /// # bbqtest(); /// # } /// ``` - pub fn grant_max_remaining(&mut self, mut sz: usize) -> Result> { + pub fn grant_max_remaining(&mut self, mut sz: usize) -> Result> { let inner = unsafe { &self.bbq.as_ref().0 }; if atomic::swap(&inner.write_in_progress, true, AcqRel) { @@ -518,7 +538,7 @@ where // This is sound, as UnsafeCell, MaybeUninit, and GenericArray // are all `#[repr(Transparent)] - let start_of_buf_ptr = inner.buf.get().cast::(); + let start_of_buf_ptr = inner.buf.get().cast::(); let grant_slice = unsafe { from_raw_parts_mut(start_of_buf_ptr.offset(start as isize), sz) }; @@ -529,36 +549,43 @@ where } } -/// `Consumer` is the primary interface for reading data from a `BBBuffer`. -pub struct Consumer<'a, N> +/// `Consumer` is the primary interface for reading data from a `GenericBBBuffer`. +pub struct Consumer<'a, T, N> where - N: ArrayLength, + T: Sized, + N: ArrayLength, { - bbq: NonNull>, + bbq: NonNull>, pd: PhantomData<&'a ()>, } -unsafe impl<'a, N> Send for Consumer<'a, N> where N: ArrayLength {} +unsafe impl<'a, T, N> Send for Consumer<'a, T, N> +where + T: Sized, + N: ArrayLength, +{ +} -impl<'a, N> Consumer<'a, N> +impl<'a, T, N> Consumer<'a, T, N> where - N: ArrayLength, + T: Sized, + N: ArrayLength, { - /// Obtains a contiguous slice of committed bytes. This slice may not - /// contain ALL available bytes, if the writer has wrapped around. The - /// remaining bytes will be available after all readable bytes are + /// Obtains a contiguous slice of committed elements. This slice may not + /// contain ALL available elements, if the writer has wrapped around. The + /// remaining elements will be available after all readable elements are /// released /// /// ```rust /// # // bbqueue test shim! /// # fn bbqtest() { - /// use bbqueue::{BBBuffer, consts::*}; + /// use bbqueue::{GenericBBBuffer, consts::*}; /// /// // Create and split a new buffer of 6 elements - /// let buffer: BBBuffer = BBBuffer::new(); + /// let buffer: GenericBBBuffer = GenericBBBuffer::new(); /// let (mut prod, mut cons) = buffer.try_split().unwrap(); /// - /// // Successfully obtain and commit a grant of four bytes + /// // Successfully obtain and commit a grant of four elements /// let mut grant = prod.grant_max_remaining(4).unwrap(); /// assert_eq!(grant.buf().len(), 4); /// grant.commit(4); @@ -574,7 +601,7 @@ where /// # bbqtest(); /// # } /// ``` - pub fn read(&mut self) -> Result> { + pub fn read(&mut self) -> Result> { let inner = unsafe { &self.bbq.as_ref().0 }; if atomic::swap(&inner.read_in_progress, true, AcqRel) { @@ -614,7 +641,7 @@ where // This is sound, as UnsafeCell, MaybeUninit, and GenericArray // are all `#[repr(Transparent)] - let start_of_buf_ptr = inner.buf.get().cast::(); + let start_of_buf_ptr = inner.buf.get().cast::(); let grant_slice = unsafe { from_raw_parts_mut(start_of_buf_ptr.offset(read as isize), sz) }; Ok(GrantR { @@ -624,21 +651,22 @@ where } } -impl BBBuffer +impl GenericBBBuffer where - N: ArrayLength, + T: Sized, + N: ArrayLength, { /// Returns the size of the backing storage. /// - /// This is the maximum number of bytes that can be stored in this queue. + /// This is the maximum number of elements that can be stored in this queue. /// /// ```rust /// # // bbqueue test shim! /// # fn bbqtest() { - /// use bbqueue::{BBBuffer, consts::*}; + /// use bbqueue::{GenericBBBuffer, consts::*}; /// /// // Create a new buffer of 6 elements - /// let buffer: BBBuffer = BBBuffer::new(); + /// let buffer: GenericBBBuffer = GenericBBBuffer::new(); /// assert_eq!(buffer.capacity(), 6); /// # // bbqueue test shim! /// # } @@ -653,9 +681,10 @@ where } } -impl BBBuffer +impl GenericBBBuffer where - N: ArrayLength, + T: Sized, + N: ArrayLength, { /// Create a new bbqueue /// @@ -664,10 +693,10 @@ where /// ```rust /// # // bbqueue test shim! /// # fn bbqtest() { - /// use bbqueue::{BBBuffer, consts::*}; + /// use bbqueue::{GenericBBBuffer, consts::*}; /// /// // Create a new buffer of 6 elements - /// let buffer: BBBuffer = BBBuffer::new(); + /// let buffer: GenericBBBuffer = GenericBBBuffer::new(); /// # // bbqueue test shim! /// # } /// # @@ -685,42 +714,55 @@ where /// may be written to, and potentially "committed" to the queue. /// /// NOTE: If the grant is dropped without explicitly commiting -/// the contents, then no bytes will be comitted for writing. +/// the contents, then no elements will be comitted for writing. /// If the `thumbv6` feature is selected, dropping the grant /// without committing it takes a short critical section, #[derive(Debug, PartialEq)] -pub struct GrantW<'a, N> +pub struct GrantW<'a, T, N> where - N: ArrayLength, + T: Sized, + N: ArrayLength, { - pub(crate) buf: &'a mut [u8], - bbq: NonNull>, + pub(crate) buf: &'a mut [T], + bbq: NonNull>, } -unsafe impl<'a, N> Send for GrantW<'a, N> where N: ArrayLength {} +unsafe impl<'a, T, N> Send for GrantW<'a, T, N> +where + T: Sized, + N: ArrayLength, +{ +} /// A structure representing a contiguous region of memory that /// may be read from, and potentially "released" (or cleared) /// from the queue /// /// NOTE: If the grant is dropped without explicitly releasing -/// the contents, then no bytes will be released as read. +/// the contents, then no elements will be released as read. /// If the `thumbv6` feature is selected, dropping the grant /// without releasing it takes a short critical section, #[derive(Debug, PartialEq)] -pub struct GrantR<'a, N> +pub struct GrantR<'a, T, N> where - N: ArrayLength, + T: Sized, + N: ArrayLength, { - pub(crate) buf: &'a mut [u8], - bbq: NonNull>, + pub(crate) buf: &'a mut [T], + bbq: NonNull>, } -unsafe impl<'a, N> Send for GrantR<'a, N> where N: ArrayLength {} +unsafe impl<'a, T, N> Send for GrantR<'a, T, N> +where + T: Sized, + N: ArrayLength, +{ +} -impl<'a, N> GrantW<'a, N> +impl<'a, T, N> GrantW<'a, T, N> where - N: ArrayLength, + T: Sized, + N: ArrayLength, { /// Finalizes a writable grant given by `grant()` or `grant_max()`. /// This makes the data available to be read via `read()`. This consumes @@ -741,13 +783,13 @@ where /// ```rust /// # // bbqueue test shim! /// # fn bbqtest() { - /// use bbqueue::{BBBuffer, consts::*}; + /// use bbqueue::{GenericBBBuffer, consts::*}; /// /// // Create and split a new buffer of 6 elements - /// let buffer: BBBuffer = BBBuffer::new(); + /// let buffer: GenericBBBuffer = GenericBBBuffer::new(); /// let (mut prod, mut cons) = buffer.try_split().unwrap(); /// - /// // Successfully obtain and commit a grant of four bytes + /// // Successfully obtain and commit a grant of four elements /// let mut grant = prod.grant_max_remaining(4).unwrap(); /// grant.buf().copy_from_slice(&[1, 2, 3, 4]); /// grant.commit(4); @@ -759,7 +801,7 @@ where /// # bbqtest(); /// # } /// ``` - pub fn buf(&mut self) -> &mut [u8] { + pub fn buf(&mut self) -> &mut [T] { self.buf } @@ -774,8 +816,8 @@ where /// /// Additionally, you must ensure that a separate reference to this data is not created /// to this data, e.g. using `DerefMut` or the `buf()` method of this grant. - pub unsafe fn as_static_mut_buf(&mut self) -> &'static mut [u8] { - transmute::<&mut [u8], &'static mut [u8]>(self.buf) + pub unsafe fn as_static_mut_buf(&mut self) -> &'static mut [T] { + transmute::<&mut [T], &'static mut [T]>(self.buf) } #[inline(always)] @@ -797,7 +839,7 @@ where let new_write = inner.reserve.load(Acquire); if (new_write < write) && (write != max) { - // We have already wrapped, but we are skipping some bytes at the end of the ring. + // We have already wrapped, but we are skipping some elements at the end of the ring. // Mark `last` where the write pointer used to be to hold the line here inner.last.store(write, Release); } else if new_write > last { @@ -825,11 +867,12 @@ where } } -impl<'a, N> GrantR<'a, N> +impl<'a, T, N> GrantR<'a, T, N> where - N: ArrayLength, + T: Sized, + N: ArrayLength, { - /// Release a sequence of bytes from the buffer, allowing the space + /// Release a sequence of elements from the buffer, allowing the space /// to be used by later writes. This consumes the grant. /// /// If `used` is larger than the given grant, the full grant will @@ -845,8 +888,9 @@ where forget(self); } + #[allow(dead_code)] pub(crate) fn shrink(&mut self, len: usize) { - let mut new_buf: &mut [u8] = &mut []; + let mut new_buf: &mut [T] = &mut []; core::mem::swap(&mut self.buf, &mut new_buf); let (new, _) = new_buf.split_at_mut(len); self.buf = new; @@ -857,13 +901,13 @@ where /// ``` /// # // bbqueue test shim! /// # fn bbqtest() { - /// use bbqueue::{BBBuffer, consts::*}; + /// use bbqueue::{GenericBBBuffer, consts::*}; /// /// // Create and split a new buffer of 6 elements - /// let buffer: BBBuffer = BBBuffer::new(); + /// let buffer: GenericBBBuffer = GenericBBBuffer::new(); /// let (mut prod, mut cons) = buffer.try_split().unwrap(); /// - /// // Successfully obtain and commit a grant of four bytes + /// // Successfully obtain and commit a grant of four elements /// let mut grant = prod.grant_max_remaining(4).unwrap(); /// grant.buf().copy_from_slice(&[1, 2, 3, 4]); /// grant.commit(4); @@ -881,7 +925,7 @@ where /// # bbqtest(); /// # } /// ``` - pub fn buf(&self) -> &[u8] { + pub fn buf(&self) -> &[T] { self.buf } @@ -889,7 +933,7 @@ where /// /// This is useful if you are performing in-place operations /// on an incoming packet, such as decryption - pub fn buf_mut(&mut self) -> &mut [u8] { + pub fn buf_mut(&mut self) -> &mut [T] { self.buf } @@ -904,8 +948,8 @@ where /// /// Additionally, you must ensure that a separate reference to this data is not created /// to this data, e.g. using `Deref` or the `buf()` method of this grant. - pub unsafe fn as_static_buf(&self) -> &'static [u8] { - transmute::<&[u8], &'static [u8]>(self.buf) + pub unsafe fn as_static_buf(&self) -> &'static [T] { + transmute::<&[T], &'static [T]>(self.buf) } #[inline(always)] @@ -922,60 +966,66 @@ where } } -impl<'a, N> Drop for GrantW<'a, N> +impl<'a, T, N> Drop for GrantW<'a, T, N> where - N: ArrayLength, + T: Sized, + N: ArrayLength, { fn drop(&mut self) { self.commit_inner(0) } } -impl<'a, N> Drop for GrantR<'a, N> +impl<'a, T, N> Drop for GrantR<'a, T, N> where - N: ArrayLength, + T: Sized, + N: ArrayLength, { fn drop(&mut self) { self.release_inner(0) } } -impl<'a, N> Deref for GrantW<'a, N> +impl<'a, T, N> Deref for GrantW<'a, T, N> where - N: ArrayLength, + T: Sized, + N: ArrayLength, { - type Target = [u8]; + type Target = [T]; fn deref(&self) -> &Self::Target { self.buf } } -impl<'a, N> DerefMut for GrantW<'a, N> +impl<'a, T, N> DerefMut for GrantW<'a, T, N> where - N: ArrayLength, + T: Sized, + N: ArrayLength, { - fn deref_mut(&mut self) -> &mut [u8] { + fn deref_mut(&mut self) -> &mut [T] { self.buf } } -impl<'a, N> Deref for GrantR<'a, N> +impl<'a, T, N> Deref for GrantR<'a, T, N> where - N: ArrayLength, + T: Sized, + N: ArrayLength, { - type Target = [u8]; + type Target = [T]; fn deref(&self) -> &Self::Target { self.buf } } -impl<'a, N> DerefMut for GrantR<'a, N> +impl<'a, T, N> DerefMut for GrantR<'a, T, N> where - N: ArrayLength, + T: Sized, + N: ArrayLength, { - fn deref_mut(&mut self) -> &mut [u8] { + fn deref_mut(&mut self) -> &mut [T] { self.buf } } diff --git a/core/src/framed.rs b/core/src/framed.rs index 0bddbf3..7b083b3 100644 --- a/core/src/framed.rs +++ b/core/src/framed.rs @@ -88,7 +88,7 @@ pub struct FrameProducer<'a, N> where N: ArrayLength, { - pub(crate) producer: Producer<'a, N>, + pub(crate) producer: Producer<'a, u8, N>, } impl<'a, N> FrameProducer<'a, N> @@ -113,7 +113,7 @@ pub struct FrameConsumer<'a, N> where N: ArrayLength, { - pub(crate) consumer: Consumer<'a, N>, + pub(crate) consumer: Consumer<'a, u8, N>, } impl<'a, N> FrameConsumer<'a, N> @@ -156,7 +156,7 @@ pub struct FrameGrantW<'a, N> where N: ArrayLength, { - grant_w: GrantW<'a, N>, + grant_w: GrantW<'a, u8, N>, hdr_len: u8, } @@ -169,7 +169,7 @@ pub struct FrameGrantR<'a, N> where N: ArrayLength, { - grant_r: GrantR<'a, N>, + grant_r: GrantR<'a, u8, N>, hdr_len: u8, } diff --git a/core/src/lib.rs b/core/src/lib.rs index ed7048e..16e0f3d 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -53,12 +53,12 @@ //! //! ```rust, no_run //! # #[cfg(feature = "atomic")] -//! # use bbqueue::atomic::{BBBuffer, ConstBBBuffer, consts::*}; +//! # use bbqueue::atomic::{BBBuffer, GenericBBBuffer, ConstBBBuffer, consts::*}; //! # #[cfg(not(feature = "atomic"))] -//! # use bbqueue::cm_mutex::{BBBuffer, ConstBBBuffer, consts::*}; +//! # use bbqueue::cm_mutex::{BBBuffer, GenericBBBuffer, ConstBBBuffer, consts::*}; //! # //! // Create a buffer with six elements -//! static BB: BBBuffer = BBBuffer( ConstBBBuffer::new() ); +//! static BB: BBBuffer = GenericBBBuffer( ConstBBBuffer::new() ); //! //! fn main() { //! // Split the bbqueue into producer and consumer halves.