Skip to content

Commit

Permalink
WIP: New traits
Browse files Browse the repository at this point in the history
  • Loading branch information
agerasev committed Mar 27, 2023
1 parent 83f6fa6 commit 1cede7f
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 84 deletions.
File renamed without changes.
2 changes: 1 addition & 1 deletion src/consumer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
ring_buffer::{RbBase, RbRead, RbReadCache, RbRef, RbWrap},
raw::UnsafeConsumer,
utils::{slice_assume_init_mut, slice_assume_init_ref, write_uninit_slice},
};
use core::{cmp, iter::ExactSizeIterator, marker::PhantomData, mem::MaybeUninit};
Expand Down
12 changes: 7 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,17 +135,18 @@ extern crate alloc;
#[cfg(feature = "std")]
extern crate std;

mod alias;
pub mod raw;

//mod alias;
mod utils;

/// [`Consumer`] and additional types.
pub mod consumer;
/// [`Producer`] and additional types.
pub mod observer;
pub mod producer;
/// Ring buffer traits and implementations.
pub mod ring_buffer;
mod transfer;
//mod transfer;

/*
#[cfg(feature = "alloc")]
pub use alias::{HeapConsumer, HeapProducer, HeapRb};
pub use alias::{StaticConsumer, StaticProducer, StaticRb};
Expand All @@ -161,3 +162,4 @@ mod tests;
extern crate test;
#[cfg(feature = "bench")]
mod benchmarks;
*/
37 changes: 32 additions & 5 deletions src/ring_buffer/local.rs → src/local.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use super::{Container, Rb, RbBase, RbRead, RbWrite, SharedStorage};
use super::{
raw::{UnsafeConsumer, UnsafeObserver, UnsafeProducer},
storage::{Container, SharedStorage},
};
use crate::{consumer::Consumer, producer::Producer};
use core::{
cell::Cell,
Expand Down Expand Up @@ -41,7 +44,7 @@ pub struct LocalRb<T, C: Container<T>> {
tail: Cell<usize>,
}

impl<T, C: Container<T>> RbBase<T> for LocalRb<T, C> {
impl<T, C: Container<T>> UnsafeObserver<T> for LocalRb<T, C> {
#[inline]
unsafe fn slices(
&self,
Expand All @@ -67,14 +70,14 @@ impl<T, C: Container<T>> RbBase<T> for LocalRb<T, C> {
}
}

impl<T, C: Container<T>> RbRead<T> for LocalRb<T, C> {
impl<T, C: Container<T>> UnsafeConsumer<T> for LocalRb<T, C> {
#[inline]
unsafe fn set_head(&self, value: usize) {
self.head.set(value);
}
}

impl<T, C: Container<T>> RbWrite<T> for LocalRb<T, C> {
impl<T, C: Container<T>> UnsafeProducer<T> for LocalRb<T, C> {
#[inline]
unsafe fn set_tail(&self, value: usize) {
self.tail.set(value);
Expand All @@ -95,7 +98,7 @@ impl<T, C: Container<T>> LocalRb<T, C> {
/// # Safety
///
/// The items in container inside `head..tail` range must be initialized, items outside this range must be uninitialized.
/// `head` and `tail` values must be valid (see [`RbBase`](`crate::ring_buffer::RbBase`)).
/// `head` and `tail` values must be valid (see [`UnsafeObserver`](`crate::ring_buffer::UnsafeObserver`)).
pub unsafe fn from_raw_parts(container: C, head: usize, tail: usize) -> Self {
Self {
storage: SharedStorage::new(container),
Expand Down Expand Up @@ -137,3 +140,27 @@ impl<T, C: Container<T>> LocalRb<T, C> {
unsafe { (Producer::new(self), Consumer::new(self)) }
}
}

use crate::utils::uninit_array;
use core::mem::MaybeUninit;

#[cfg(feature = "alloc")]
use alloc::vec::Vec;

impl<T, const N: usize> Default for LocalRb<T, [MaybeUninit<T>; N]> {
fn default() -> Self {
unsafe { Self::from_raw_parts(uninit_array(), 0, 0) }
}
}

#[cfg(feature = "alloc")]
impl<T> LocalRb<T, Vec<MaybeUninit<T>>> {
/// Creates a new instance of a ring buffer.
///
/// *Panics if `capacity` is zero.*
pub fn new(capacity: usize) -> Self {
let mut data = Vec::new();
data.resize_with(capacity, MaybeUninit::uninit);
unsafe { Self::from_raw_parts(data, 0, 0) }
}
}
Empty file added src/observer.rs
Empty file.
28 changes: 22 additions & 6 deletions src/ring_buffer/base.rs → src/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ use core::{mem::MaybeUninit, num::NonZeroUsize, ops::Range, ptr};
/// It allows us to distinguish situations when the buffer is empty (`head == tail`) and when the buffer is full (`tail - head` modulo `2 * capacity` equals to `capacity`)
/// without using the space for an extra element in container.
/// And obviously we cannot store more than `capacity` items in the buffer, so `tail - head` modulo `2 * capacity` is not allowed to be greater than `capacity`.
pub trait RbBase<T> {
pub trait UnsafeObserver {
/// Item type.
type Item: Sized;

/// Returns part of underlying raw ring buffer memory as slices.
///
/// For more information see [`SharedStorage::as_mut_slices`](`crate::ring_buffer::storage::SharedStorage::as_mut_slices`).
Expand All @@ -34,7 +37,10 @@ pub trait RbBase<T> {
&self,
head: usize,
tail: usize,
) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]);
) -> (
&mut [MaybeUninit<Self::Item>],
&mut [MaybeUninit<Self::Item>],
);

/// Capacity of the ring buffer.
///
Expand Down Expand Up @@ -83,7 +89,7 @@ pub trait RbBase<T> {
/// Provides access to occupied memory and mechanism of item extraction.
///
/// *It is recommended not to use this trait directly. Use [`Producer`](`crate::Producer`) and [`Consumer`](`crate::Consumer`) instead.*
pub trait RbRead<T>: RbBase<T> {
pub trait UnsafeConsumer: UnsafeObserver {
/// Sets the new **head** position.
///
/// # Safety
Expand Down Expand Up @@ -124,7 +130,12 @@ pub trait RbRead<T>: RbBase<T> {
/// *This method must be followed by [`Self::advance_head`] call with the number of items being removed previously as argument.*
/// *No other mutating calls allowed before that.*
#[inline]
unsafe fn occupied_slices(&self) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]) {
unsafe fn occupied_slices(
&self,
) -> (
&mut [MaybeUninit<Self::Item>],
&mut [MaybeUninit<Self::Item>],
) {
self.slices(self.head(), self.tail())
}

Expand Down Expand Up @@ -162,7 +173,7 @@ pub trait RbRead<T>: RbBase<T> {
/// Provides access to vacant memory and mechanism of item insertion.
///
/// *It is recommended not to use this trait directly. Use [`Producer`](`crate::Producer`) and [`Consumer`](`crate::Consumer`) instead.*
pub trait RbWrite<T>: RbBase<T> {
pub trait UnsafeProducer: UnsafeObserver {
/// Sets the new **tail** position.
///
/// # Safety
Expand Down Expand Up @@ -205,7 +216,12 @@ pub trait RbWrite<T>: RbBase<T> {
/// *This method must be followed by [`Self::advance_tail`] call with the number of items being put previously as argument.*
/// *No other mutating calls allowed before that.*
#[inline]
unsafe fn vacant_slices(&self) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]) {
unsafe fn vacant_slices(
&self,
) -> (
&mut [MaybeUninit<Self::Item>],
&mut [MaybeUninit<Self::Item>],
) {
self.slices(self.tail(), self.head() + self.capacity_nonzero().get())
}
}
File renamed without changes.
40 changes: 0 additions & 40 deletions src/ring_buffer/init.rs

This file was deleted.

15 changes: 0 additions & 15 deletions src/ring_buffer/mod.rs

This file was deleted.

24 changes: 24 additions & 0 deletions src/ring_buffer/shared.rs → src/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,27 @@ impl<T, C: Container<T>> SharedRb<T, C> {
unsafe { (Producer::new(self), Consumer::new(self)) }
}
}

use crate::utils::uninit_array;
use core::mem::MaybeUninit;

#[cfg(feature = "alloc")]
use alloc::vec::Vec;

impl<T, const N: usize> Default for SharedRb<T, [MaybeUninit<T>; N]> {
fn default() -> Self {
unsafe { Self::from_raw_parts(uninit_array(), 0, 0) }
}
}

#[cfg(feature = "alloc")]
impl<T> SharedRb<T, Vec<MaybeUninit<T>>> {
/// Creates a new instance of a ring buffer.
///
/// *Panics if `capacity` is zero.*
pub fn new(capacity: usize) -> Self {
let mut data = Vec::new();
data.resize_with(capacity, MaybeUninit::uninit);
unsafe { Self::from_raw_parts(data, 0, 0) }
}
}
31 changes: 19 additions & 12 deletions src/ring_buffer/storage.rs → src/storage.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::utils::ring_buffer_ranges;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::{cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, num::NonZeroUsize, slice};
use core::{cell::UnsafeCell, mem::MaybeUninit, num::NonZeroUsize, slice};

/// Abstract container for the ring buffer.
///
Expand All @@ -12,7 +12,10 @@ use core::{cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, num::NonZero
/// *[`Self::len`]/[`Self::is_empty`] must always return the same value.*
///
/// *Container must not cause data race on concurrent [`Self::as_mut_slice`]/[`Self::as_mut_ptr`] calls.*
pub unsafe trait Container<T> {
pub unsafe trait Container {
/// Item type.
type Item: Sized;

/// Internal representation of the container.
///
/// *Must not be aliased with its content.*
Expand All @@ -28,12 +31,14 @@ pub unsafe trait Container<T> {
unsafe fn from_internal(this: Self::Internal) -> Self;

/// Return pointer to the beginning of the container items.
fn as_mut_ptr(this: &Self::Internal) -> *mut MaybeUninit<T>;
fn as_mut_ptr(this: &Self::Internal) -> *mut MaybeUninit<Self::Item>;
/// Length of the container.
fn len(this: &Self::Internal) -> usize;
}

unsafe impl<'a, T> Container<T> for &'a mut [MaybeUninit<T>] {
unsafe impl<'a, T> Container for &'a mut [MaybeUninit<T>] {
type Item = T;

type Internal = (*mut MaybeUninit<T>, usize);

fn into_internal(self) -> Self::Internal {
Expand All @@ -53,7 +58,9 @@ unsafe impl<'a, T> Container<T> for &'a mut [MaybeUninit<T>] {
}
}

unsafe impl<T, const N: usize> Container<T> for [MaybeUninit<T>; N] {
unsafe impl<T, const N: usize> Container for [MaybeUninit<T>; N] {
type Item = T;

type Internal = UnsafeCell<[MaybeUninit<T>; N]>;

fn into_internal(self) -> Self::Internal {
Expand All @@ -74,7 +81,9 @@ unsafe impl<T, const N: usize> Container<T> for [MaybeUninit<T>; N] {
}

#[cfg(feature = "alloc")]
unsafe impl<T> Container<T> for Vec<MaybeUninit<T>> {
unsafe impl<T> Container for Vec<MaybeUninit<T>> {
type Item = T;

type Internal = Self;

fn into_internal(self) -> Self::Internal {
Expand All @@ -95,14 +104,13 @@ unsafe impl<T> Container<T> for Vec<MaybeUninit<T>> {
}

/// Wrapper for container that provides multiple write access to it.
pub(crate) struct SharedStorage<T, C: Container<T>> {
pub(crate) struct SharedStorage<C: Container> {
container: C::Internal,
_p: PhantomData<T>,
}

unsafe impl<T, C: Container<T>> Sync for SharedStorage<T, C> where T: Send {}
unsafe impl<C: Container> Sync for SharedStorage<C> where C::Item: Send {}

impl<T, C: Container<T>> SharedStorage<T, C> {
impl<C: Container> SharedStorage<C> {
/// Create new storage.
///
/// *Panics if container is empty.*
Expand All @@ -111,7 +119,6 @@ impl<T, C: Container<T>> SharedStorage<T, C> {
assert!(C::len(&internal) > 0);
Self {
container: internal,
_p: PhantomData,
}
}

Expand All @@ -132,7 +139,7 @@ impl<T, C: Container<T>> SharedStorage<T, C> {
&self,
head: usize,
tail: usize,
) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]) {
) -> (&mut [MaybeUninit<C::Item>], &mut [MaybeUninit<C::Item>]) {
let ranges = ring_buffer_ranges(self.len(), head, tail);
let ptr = C::as_mut_ptr(&self.container);
(
Expand Down

0 comments on commit 1cede7f

Please sign in to comment.