pub trait BulkConsumer: Consumer {
// Required method
async fn expose_slots_gracefully<F, R>(
&mut self,
f: F,
) -> Result<R, (F, Self::Error)>
where F: AsyncFnOnce(&mut [Self::Item]) -> (usize, R);
}Expand description
A BulkConsumer is a producer that can accept multiple items with a single call of the BulkConsumer::expose_slots_gracefully method.
This method takes an async function as its sole argument. The consumer calls that function, passing it a mutable, non-empty slice of items. The function can mutate these items in any way, and then returns a pair of values: first, the number of items the consumer should now consider as having been consumed, and second, an arbitrary value, to be returned by the expose_slots call.
See BulkConsumerExt::expose_slots for a variant of expose_slots_gracefully which simplifies error handling by not returning the supplied function.
See BulkConsumerExt::bulk_consume for using bulk consumers in a way analogous to std::io::Write::write.
use ufotofu::prelude::*;
let mut arr = [0, 0, 0];
let mut c = (&mut arr).into_consumer();
assert_eq!(c.expose_slots(async |mut slots| {
slots[0] = 1;
slots[1] = 2;
slots[2] = 4;
(3, "hi!")
}).await?, "hi!");
assert_eq!(c.consume_item(8).await, Err(()));
assert_eq!(arr, [1, 2, 4]);
// If we reported that we only wrote two items, the consumer would later accept another item:
let mut arr2 = [0, 0, 0];
let mut c2 = (&mut arr2).into_consumer();
assert_eq!(c2.expose_slots(async |mut slots| {
slots[0] = 1;
slots[1] = 2;
slots[2] = 4;
(2, "hi!")
}).await?, "hi!");
assert_eq!(c2.consume_item(8).await, Ok(()));
assert_eq!(arr2, [1, 2, 8]);Semantically, there should be no difference between bulk consumption or item-by-item consumption.
Counterpart: the BulkProducer trait.
Required Methods§
Sourceasync fn expose_slots_gracefully<F, R>(
&mut self,
f: F,
) -> Result<R, (F, Self::Error)>
async fn expose_slots_gracefully<F, R>( &mut self, f: F, ) -> Result<R, (F, Self::Error)>
Exposes a non-empty number of item slots to a given async function, the function mutates those slots and then then reports to the consumer how many items should now be considered consumed.
When the consumer needs to return an error, it must return it immediately from this method. Otherwise, i.e., when it wants to consume regular items, it must call the passed function f with a non-empty slice of items as the argument, and then poll f to completion. When f has yielded (amount, t), the consumer must adjust its state as if consume had been called amount many times with copies of the first amount many items in the slice it had passed to f, and then return Ok(t). It must not return Err(_) when having called f.
When passing a slice to f, if f does not report that every provided slot was filled, then the consumer must be able to consume the remaining number of items without emitting an error. For example: a consumer passes a slice of five slots to f, and f returns (3, _). Then the next two calls to consume must return Ok(()).
After this function returns the final value or after it returns an error, no further methods of this trait may be invoked.
The intention is for f to not read any contents of the passed slice, but to simply write items into the slice that should be consumed. Sadly, we cannot enforce this on the type level.
Because f might still be needed after the consumer reports an error, this method returns f alongside its error value. For more convenient error handling with the ? operator in cases where f does not need to be preserved, see expose_slots.
§Invariants
Must not be called after this consumer has been closed, or after any method of this trait has returned an error.
f must not return an amount strictly greater than the length of the buffer passed to it.
§Examples
use ufotofu::prelude::*;
let mut arr = [0, 0, 0];
let mut c = (&mut arr).into_consumer();
assert_eq!(c.expose_slots_gracefully(async |mut slots| {
slots[0] = 1;
slots[1] = 2;
slots[2] = 4;
(3, "hi!")
}).await.map_err(|(_f, err)| err), Ok("hi!"));
assert_eq!(c.consume_item(8).await, Err(()));
assert_eq!(arr, [1, 2, 4]);
// If we reported that we only wrote two items, the consumer would later accept another item:
let mut arr2 = [0, 0, 0];
let mut c2 = (&mut arr2).into_consumer();
assert_eq!(c2.expose_slots_gracefully(async |mut slots| {
slots[0] = 1;
slots[1] = 2;
slots[2] = 4;
(2, "hi!")
}).await.map_err(|(_f, err)| err), Ok("hi!"));
assert_eq!(c2.consume_item(8).await, Ok(()));
assert_eq!(arr2, [1, 2, 8]);
// If the consumer reports an error on a call to `expose_slots_gracefully`, the supplied async function is returned for later use:
let mut no_room: [u8; 0] = [];
let mut overflow = [0u8; 3];
let mut c3 = (&mut no_room).into_consumer();
let mut c4 = (&mut overflow).into_consumer();
let f = match c3.expose_slots_gracefully(async |mut slots| {
slots[0] = 17;
(1, "hi!")
}).await {
Err((f, _err)) => f,
Ok(_) => unreachable!(),
};
assert_eq!(c4.expose_slots_gracefully(f).await.map_err(|(_f, err)| err), Ok("hi!"));
assert_eq!(overflow, [17, 0, 0]);
Counterpart: the BulkProducer::expose_items_gracefully method.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".
Implementations on Foreign Types§
Source§impl<C> BulkConsumer for &mut Cwhere
C: BulkConsumer + ?Sized,
impl<C> BulkConsumer for &mut Cwhere
C: BulkConsumer + ?Sized,
async fn expose_slots_gracefully<F, R>( &mut self, f: F, ) -> Result<R, (F, Self::Error)>
Source§impl<C> BulkConsumer for Box<C>where
C: BulkConsumer + ?Sized,
Available on crate feature alloc only.
impl<C> BulkConsumer for Box<C>where
C: BulkConsumer + ?Sized,
alloc only.async fn expose_slots_gracefully<F, R>( &mut self, f: F, ) -> Result<R, (F, Self::Error)>
Implementors§
impl BulkConsumer for Infallible
impl<'a, T, const N: usize> BulkConsumer for ufotofu::consumer::compat::array::IntoConsumerMut<'a, T, N>
impl<'a, T: Default> BulkConsumer for ufotofu::consumer::compat::vec::IntoConsumerMut<'a, T>
impl<'a, T> BulkConsumer for ufotofu::consumer::compat::slice::IntoConsumerMut<'a, T>
impl<'s, T> BulkConsumer for IntoConsumerBoxedMut<'s, T>
alloc only.impl<C, Fun, NewErr> BulkConsumer for MapAsyncError<C, Fun>
impl<C, Fun, NewErr> BulkConsumer for MapError<C, Fun>
impl<C, Fun, NewFinal> BulkConsumer for MapAsyncFinal<C, Fun, NewFinal>
impl<C, Fun, NewFinal> BulkConsumer for MapFinal<C, Fun, NewFinal>
impl<C, Q> BulkConsumer for Buffered<C, Q>
impl<C, Q> BulkConsumer for BulkBuffered<C, Q>
impl<C, Q> BulkConsumer for BulkScrambled<C, Q>
impl<C, Q> BulkConsumer for Scrambled<C, Q>
impl<C: BulkConsumer> BulkConsumer for Limit<C>
impl<C> BulkConsumer for Stats<C>where
C: BulkConsumer,
impl<C> BulkConsumer for Watch<C>where
C: BulkConsumer,
impl<Err> BulkConsumer for ErrorImmediately<Err>
impl<Item, Final, Error> BulkConsumer for TestConsumer<Item, Final, Error>where
Item: Default,
impl<P, Q> BulkConsumer for Chain<P, Q>
impl<P, Q> BulkConsumer for CloningChain<P, Q>
impl<Q: Queue, F> BulkConsumer for ufotofu::channels::sssr::Sender<Q, F>
impl<R: Deref<Target = State<Q, F>>, Q: Queue, F> BulkConsumer for ufotofu::channels::advanced::sssr::Sender<R, Q, F>
impl<S, T> BulkConsumer for MoveIntoOwnedSlice<S, T>
impl<T, const N: usize> BulkConsumer for ufotofu::consumer::compat::array::IntoConsumer<T, N>
impl<T: Default> BulkConsumer for ufotofu::consumer::compat::vec::IntoConsumer<T>
impl<T> BulkConsumer for IntoConsumerBoxed<T>
alloc only.