Struct mutringbuf::iterators::sync_iterators::prod_iter::ProdIter

source ·
pub struct ProdIter<B: MutRB> { /* private fields */ }
Expand description

Iterator used to push data into the buffer.

When working with types which implement both Copy and Clone traits, copy methods should be preferred over clone methods.

§TL;DR about uninitialised memory

If you created the buffer with either default or from methods and you are not going to use ConsIter::pop, then it is safe to use normal methods from this struct.

If you either created the buffer with new_zeroed or are going to move items out of the buffer (e.g. using ConsIter::pop), then you must pay attention to what you do and ensure that all the locations cleared by pop will be re-filled with *_init methods. After that you can use normal methods again. Read below to know why and how.

It would be a good idea to do a check with miri, which is able to tell if and when something bad has happened.

§A note about how this buffer is made:

Every element in this buffer is wrapped in an UnsafeSyncCell, which in the end is a MaybeUninit. MaybeUninit (read the official docs if you want to know more) is a way to deal with possibly uninitialised data.

When one creates a buffer from this crate, they may choose to build it either with default and from methods, or with new_zeroed ones.

When using the former, an initialised buffer is created, so there are no problems concerning uninitialised memory. With the latter methods, a zeroed buffer is rather created. To write data into an uninitialised (or zeroed) block of memory, one has to use write method, which overwrites a memory location, without reading or dropping the old value.

Remember that a zeroed location must never be read or dropped. Doing so would cause UB!

On the other hand, using write on an initialised block doesn’t drop the old value, causing then a memory leak.

For each of the methods in this struct, there exists a *_init one (e.g. Self::push and Self::push_init). Normal methods are faster than *_init ones, and should be preferred over these when dealing with surely initialised memory.

On the other hand, *_init methods always perform a check over the memory they are going to write and choose the proper way to write it. So they are safe to use upon a possibly uninitialised block.

Implementations§

source§

impl<B: MutRB<Item = T>, T> ProdIter<B>

source

pub fn is_work_alive(&self) -> bool

Returns true if the worker iterator is still alive, false if it has been dropped.

Note: when the buffer is used in non-mutable mode this will always return false.

source

pub fn is_cons_alive(&self) -> bool

Returns true if the consumer iterator is still alive, false if it has been dropped.

source

pub fn push(&mut self, value: T) -> Result<(), T>

Tries to push a new item by moving or copying it.

This method must not be used to push items after a ConsIter::pop. In this case, Self::push_init has to be used, instead. For more info, refer to the main documentation above.

Returns:

  • Err(value), if the buffer is full;
  • Ok(()), otherwise.
source

pub fn push_init(&mut self, value: T) -> Result<(), T>

Same as Self::push_slice, but can be used when dealing with possibly uninitialised locations within the buffer, e.g. after a ConsIter::pop.

Returns:

  • Err(value), if the buffer is full;
  • Ok(()), otherwise.
source

pub fn push_slice(&mut self, slice: &[T]) -> Option<()>
where T: Copy,

Tries to push a slice of items by copying the elements. The elements must implement Copy trait.

This method must not be used to push items after a ConsIter::pop. In this case, Self::push_slice_init has to be used, instead. For more info, refer to the main documentation above.

Returns:

  • None, if the buffer is full;
  • Some(()), otherwise.
source

pub fn push_slice_init(&mut self, slice: &[T]) -> Option<()>
where T: Copy,

Same as Self::push_slice, but can be used when dealing with possibly uninitialised locations within the buffer, e.g. after a ConsIter::pop.

Returns:

  • None, if the buffer is full;
  • Some(()), otherwise.
source

pub fn _push_slice_clone( &mut self, slice: &[T], f: fn(_: &mut [T], _: &[T]) ) -> Option<()>
where T: Clone,

source

pub fn push_slice_clone(&mut self, slice: &[T]) -> Option<()>
where T: Clone,

Tries to push a slice of items by cloning the elements. The elements must implement Clone trait.

This method must not be used to push items after a ConsIter::pop. In this case, Self::push_slice_clone_init has to be used, instead. For more info, refer to the main documentation above.

Returns:

  • None, if the buffer is full;
  • Some(()), otherwise.
source

pub fn push_slice_clone_init(&mut self, slice: &[T]) -> Option<()>
where T: Clone,

Same as Self::push_slice_clone, but can be used when dealing with possibly uninitialised locations within the buffer, e.g. after a ConsIter::pop.

Returns:

  • None, if the buffer is full;
  • Some(()), otherwise.
source

pub unsafe fn get_next_item_mut<'a>(&mut self) -> Option<&'a mut T>

If available, returns a mutable reference to the next item. This reference can be used to write data into an initialised item.

Items can be initialised by calling Self::get_next_item_mut_init or by creating a buffer using default constructor. E.g.: ConcurrentHeapRB::default or LocalStackRB::default.

For uninitialised items, use Self::get_next_item_mut_init, instead.

Being this a reference, Self::advance has to be called when done with the mutation in order to move the iterator.

§Safety

The retrieved item must be initialised! For more info, refer to MaybeUninit::assume_init_mut.

source

pub fn get_next_item_mut_init(&mut self) -> Option<*mut T>

If available, returns a mutable pointer to the next item. This pointer can be used to write data into the item, even if this is not already initialised. It is important to note that reading from this pointer or turning it into a reference is still undefined behavior, unless the item is initialized.

If the memory pointed by this pointer is already initialised, it is possible to write into it with a simple:

*ptr = value;

Doing so, the old value will be automatically dropped and no leak will be created.

If the memory is not initialised, the write must be done with:

ptr.write(value);

The reason is that write does not drop the old value, which is good, because dropping an uninitialised value is UB!

One should be able to test whether a piece of memory is initialised with UnsafeSyncCell::check_zeroed.

For more info, refer to MaybeUninit::as_mut_ptr.

Being this a pointer, Self::advance has to be called when done with the mutation in order to move the iterator.

Trait Implementations§

source§

impl<B: MutRB + IterManager> Drop for ProdIter<B>

source§

fn drop(&mut self)

Executes the destructor for this type. Read more
source§

impl<B: MutRB<Item = T>, T> MRBIterator<T> for ProdIter<B>

source§

fn available(&mut self) -> usize

Returns the number of items available for an iterator.
source§

unsafe fn advance(&mut self, count: usize)

Advances the iterator by count. Read more
source§

fn index(&self) -> usize

Returns the index of the iterator.
source§

fn buf_len(&self) -> usize

Returns the length of the buffer.
source§

impl<B: ConcurrentRB + MutRB<Item = T>, T> Send for ProdIter<B>

Auto Trait Implementations§

§

impl<B> Freeze for ProdIter<B>

§

impl<B> RefUnwindSafe for ProdIter<B>
where B: RefUnwindSafe,

§

impl<B> !Sync for ProdIter<B>

§

impl<B> Unpin for ProdIter<B>

§

impl<B> UnwindSafe for ProdIter<B>
where B: RefUnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.