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>
impl<B: MutRB<Item = T>, T> ProdIter<B>
sourcepub fn is_work_alive(&self) -> bool
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
.
sourcepub fn is_cons_alive(&self) -> bool
pub fn is_cons_alive(&self) -> bool
Returns true
if the consumer iterator is still alive, false
if it has been dropped.
sourcepub fn push(&mut self, value: T) -> Result<(), T>
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.
sourcepub fn push_init(&mut self, value: T) -> Result<(), T>
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.
sourcepub fn push_slice(&mut self, slice: &[T]) -> Option<()>where
T: Copy,
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.
sourcepub fn push_slice_init(&mut self, slice: &[T]) -> Option<()>where
T: Copy,
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.
pub fn _push_slice_clone(
&mut self,
slice: &[T],
f: fn(_: &mut [T], _: &[T])
) -> Option<()>where
T: Clone,
sourcepub fn push_slice_clone(&mut self, slice: &[T]) -> Option<()>where
T: Clone,
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.
sourcepub fn push_slice_clone_init(&mut self, slice: &[T]) -> Option<()>where
T: Clone,
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.
sourcepub unsafe fn get_next_item_mut<'a>(&mut self) -> Option<&'a mut T>
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
.
sourcepub fn get_next_item_mut_init(&mut self) -> Option<*mut T>
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.