pub(crate) struct SortPreservingMergeStream<C: CursorValues> {Show 17 fields
in_progress: BatchBuilder,
streams: Box<dyn PartitionedStream<Output = Result<(C, RecordBatch)>>>,
metrics: BaselineMetrics,
done: bool,
loser_tree: Vec<usize>,
loser_tree_adjusted: bool,
batch_size: usize,
cursors: Vec<Option<Cursor<C>>>,
enable_round_robin_tie_breaker: bool,
round_robin_tie_breaker_mode: bool,
num_of_polled_with_same_value: Vec<usize>,
poll_reset_epochs: Vec<usize>,
current_reset_epoch: usize,
prev_cursors: Vec<Option<Cursor<C>>>,
fetch: Option<usize>,
produced: usize,
uninitiated_partitions: Vec<usize>,
}Expand description
Merges a stream of sorted cursors and record batches into a single sorted stream
Fields§
§in_progress: BatchBuilder§streams: Box<dyn PartitionedStream<Output = Result<(C, RecordBatch)>>>The sorted input streams to merge together
metrics: BaselineMetricsused to record execution metrics
done: boolIf the stream has encountered an error or reaches the
fetch limit.
loser_tree: Vec<usize>A loser tree that always produces the minimum cursor
Node 0 stores the top winner, Nodes 1..num_streams store the loser nodes
This implements a “Tournament Tree” (aka Loser Tree) to keep
track of the current smallest element at the top. When the top
record is taken, the tree structure is not modified, and only
the path from bottom to top is visited, keeping the number of
comparisons close to the theoretical limit of log(S).
The current implementation uses a vector to store the tree. Conceptually, it looks like this (assuming 8 streams):
0 (winner)
1
/ \
2 3
/ \ / \
4 5 6 7Where element at index 0 in the vector is the current winner. Element at index 1 is the root of the loser tree, element at index 2 is the left child of the root, and element at index 3 is the right child of the root and so on.
reference: https://en.wikipedia.org/wiki/K-way_merge_algorithm#Tournament_Tree
loser_tree_adjusted: boolIf the most recently yielded overall winner has been replaced
within the loser tree. A value of false indicates that the
overall winner has been yielded but the loser tree has not
been updated
batch_size: usizeTarget batch size
cursors: Vec<Option<Cursor<C>>>Cursors for each input partition. None means the input is exhausted
enable_round_robin_tie_breaker: boolConfiguration parameter to enable round-robin selection of tied winners of loser tree.
This option controls the tie-breaker strategy and attempts to avoid the issue of unbalanced polling between partitions
If true, when multiple partitions have the same value, the partition
that has the fewest poll counts is selected. This strategy ensures that
multiple partitions with the same value are chosen equally, distributing
the polling load in a round-robin fashion. This approach balances the
workload more effectively across partitions and avoids excessive buffer
growth.
if false, partitions with smaller indices are consistently chosen as
the winners, which can lead to an uneven distribution of polling and potentially
causing upstream operator buffers for the other partitions to grow
excessively, as they continued receiving data without consuming it.
For example, an upstream operator like RepartitionExec execution would
keep sending data to certain partitions, but those partitions wouldn’t
consume the data if they weren’t selected as winners. This resulted in
inefficient buffer usage.
round_robin_tie_breaker_mode: boolFlag indicating whether we are in the mode of round-robin tie breaker for the loser tree winners.
num_of_polled_with_same_value: Vec<usize>Total number of polls returning the same value, as per partition. We select the one that has less poll counts for tie-breaker in loser tree.
poll_reset_epochs: Vec<usize>To keep track of reset counts
current_reset_epoch: usizeCurrent reset count
prev_cursors: Vec<Option<Cursor<C>>>Stores the previous value of each partitions for tracking the poll counts on the same value.
fetch: Option<usize>Optional number of rows to fetch
produced: usizenumber of rows produced
uninitiated_partitions: Vec<usize>This vector contains the indices of the partitions that have not started emitting yet.
Implementations§
Source§impl<C: CursorValues> SortPreservingMergeStream<C>
impl<C: CursorValues> SortPreservingMergeStream<C>
pub(crate) fn new( streams: Box<dyn PartitionedStream<Output = Result<(C, RecordBatch)>>>, schema: SchemaRef, metrics: BaselineMetrics, batch_size: usize, fetch: Option<usize>, reservation: MemoryReservation, enable_round_robin_tie_breaker: bool, ) -> Self
Sourcefn maybe_poll_stream(
&mut self,
cx: &mut Context<'_>,
idx: usize,
) -> Poll<Result<()>>
fn maybe_poll_stream( &mut self, cx: &mut Context<'_>, idx: usize, ) -> Poll<Result<()>>
If the stream at the given index is not exhausted, and the last cursor for the stream is finished, poll the stream for the next RecordBatch and create a new cursor for the stream from the returned result
fn poll_next_inner( &mut self, cx: &mut Context<'_>, ) -> Poll<Option<Result<RecordBatch>>>
Sourcefn update_poll_count_on_the_same_value(&mut self, partition_idx: usize)
fn update_poll_count_on_the_same_value(&mut self, partition_idx: usize)
For the given partition, updates the poll count. If the current value is the same of the previous value, it increases the count by 1; otherwise, it is reset as 0.
fn fetch_reached(&mut self) -> bool
Sourcefn advance_cursors(&mut self, stream_idx: usize) -> bool
fn advance_cursors(&mut self, stream_idx: usize) -> bool
Advances the actual cursor. If it reaches its end, update the previous cursor with it.
If the given partition is not exhausted, the function returns true.
Sourcefn is_gt(&self, a: usize, b: usize) -> bool
fn is_gt(&self, a: usize, b: usize) -> bool
Returns true if the cursor at index a is greater than at index b.
In an equality case, it compares the partition indices given.
fn is_poll_count_gt(&self, a: usize, b: usize) -> bool
fn update_winner( &mut self, cmp_node: usize, winner: &mut usize, challenger: usize, )
Sourcefn lt_leaf_node_index(&self, cursor_index: usize) -> usize
fn lt_leaf_node_index(&self, cursor_index: usize) -> usize
Find the leaf node index in the loser tree for the given cursor index
Note that this is not necessarily a leaf node in the tree, but it can also be a half-node (a node with only one child). This happens when the number of cursors/streams is not a power of two. Thus, the loser tree will be unbalanced, but it will still work correctly.
For example, with 5 streams, the loser tree will look like this:
0 (winner)
1
/ \
2 3
/ \ / \
4 | | |
/ \ | | |
-+---+--+---+---+---- Below is not a part of loser tree
S3 S4 S0 S1 S2S0, S1, … S4 are the streams (read: stream at index 0, stream at index 1, etc.)
Zooming in at node 2 in the loser tree as an example, we can see that it takes as input the next item at (S0) and the loser of (S3, S4).
Sourcefn lt_parent_node_index(&self, node_idx: usize) -> usize
fn lt_parent_node_index(&self, node_idx: usize) -> usize
Find the parent node index for the given node index
Sourcefn init_loser_tree(&mut self)
fn init_loser_tree(&mut self)
Attempts to initialize the loser tree with one value from each non exhausted input, if possible
Sourcefn reset_poll_counts(&mut self)
fn reset_poll_counts(&mut self)
Resets the poll count by incrementing the reset epoch.
Sourcefn handle_tie(&mut self, cmp_node: usize, winner: &mut usize, challenger: usize)
fn handle_tie(&mut self, cmp_node: usize, winner: &mut usize, challenger: usize)
Handles tie-breaking logic during the adjustment of the loser tree.
When comparing elements from multiple partitions in the update_loser_tree process, a tie can occur
between the current winner and a challenger. This function is invoked when such a tie needs to be
resolved according to the round-robin tie-breaker mode.
If round-robin tie-breaking is not active, it is enabled, and the poll counts for all elements are reset. The function then compares the poll counts of the current winner and the challenger:
- If the winner remains at the top after the final comparison, it increments the winner’s poll count.
- If the challenger has a lower poll count than the current winner, the challenger becomes the new winner.
- If the poll counts are equal but the challenger’s index is smaller, the challenger is preferred.
§Parameters
cmp_node: The index of the comparison node in the loser tree where the tie-breaking is happening.winner: A mutable reference to the current winner, which may be updated based on the tie-breaking result.challenger: The index of the challenger being compared against the winner.
This function ensures fair selection among elements with equal values when tie-breaking mode is enabled, aiming to balance the polling across different partitions.
Sourcefn update_loser_tree(&mut self)
fn update_loser_tree(&mut self)
Updates the loser tree to reflect the new winner after the previous winner is consumed. This function adjusts the tree by comparing the current winner with challengers from other partitions.
If enable_round_robin_tie_breaker is true and a tie occurs at the final level, the
tie-breaker logic will be applied to ensure fair selection among equal elements.
Trait Implementations§
Source§impl<C: Debug + CursorValues> Debug for SortPreservingMergeStream<C>
impl<C: Debug + CursorValues> Debug for SortPreservingMergeStream<C>
Source§impl<C: CursorValues + Unpin> RecordBatchStream for SortPreservingMergeStream<C>
impl<C: CursorValues + Unpin> RecordBatchStream for SortPreservingMergeStream<C>
Source§impl<C: CursorValues + Unpin> Stream for SortPreservingMergeStream<C>
impl<C: CursorValues + Unpin> Stream for SortPreservingMergeStream<C>
Source§type Item = Result<RecordBatch, DataFusionError>
type Item = Result<RecordBatch, DataFusionError>
Auto Trait Implementations§
impl<C> Freeze for SortPreservingMergeStream<C>
impl<C> !RefUnwindSafe for SortPreservingMergeStream<C>
impl<C> Send for SortPreservingMergeStream<C>where
C: Send,
impl<C> !Sync for SortPreservingMergeStream<C>
impl<C> Unpin for SortPreservingMergeStream<C>where
C: Unpin,
impl<C> !UnwindSafe for SortPreservingMergeStream<C>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
§impl<T> StreamExt for Twhere
T: Stream + ?Sized,
impl<T> StreamExt for Twhere
T: Stream + ?Sized,
§fn next(&mut self) -> Next<'_, Self>where
Self: Unpin,
fn next(&mut self) -> Next<'_, Self>where
Self: Unpin,
§fn into_future(self) -> StreamFuture<Self>
fn into_future(self) -> StreamFuture<Self>
§fn map<T, F>(self, f: F) -> Map<Self, F>
fn map<T, F>(self, f: F) -> Map<Self, F>
§fn enumerate(self) -> Enumerate<Self>where
Self: Sized,
fn enumerate(self) -> Enumerate<Self>where
Self: Sized,
§fn filter<Fut, F>(self, f: F) -> Filter<Self, Fut, F>
fn filter<Fut, F>(self, f: F) -> Filter<Self, Fut, F>
§fn filter_map<Fut, T, F>(self, f: F) -> FilterMap<Self, Fut, F>
fn filter_map<Fut, T, F>(self, f: F) -> FilterMap<Self, Fut, F>
§fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F>
fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F>
§fn collect<C>(self) -> Collect<Self, C>
fn collect<C>(self) -> Collect<Self, C>
§fn unzip<A, B, FromA, FromB>(self) -> Unzip<Self, FromA, FromB>
fn unzip<A, B, FromA, FromB>(self) -> Unzip<Self, FromA, FromB>
§fn concat(self) -> Concat<Self>
fn concat(self) -> Concat<Self>
§fn count(self) -> Count<Self>where
Self: Sized,
fn count(self) -> Count<Self>where
Self: Sized,
§fn fold<T, Fut, F>(self, init: T, f: F) -> Fold<Self, Fut, T, F>
fn fold<T, Fut, F>(self, init: T, f: F) -> Fold<Self, Fut, T, F>
§fn any<Fut, F>(self, f: F) -> Any<Self, Fut, F>
fn any<Fut, F>(self, f: F) -> Any<Self, Fut, F>
true if any element in stream satisfied a predicate. Read more§fn all<Fut, F>(self, f: F) -> All<Self, Fut, F>
fn all<Fut, F>(self, f: F) -> All<Self, Fut, F>
true if all element in stream satisfied a predicate. Read more§fn flatten(self) -> Flatten<Self>where
Self::Item: Stream,
Self: Sized,
fn flatten(self) -> Flatten<Self>where
Self::Item: Stream,
Self: Sized,
§fn flatten_unordered(
self,
limit: impl Into<Option<usize>>,
) -> FlattenUnorderedWithFlowController<Self, ()>
fn flatten_unordered( self, limit: impl Into<Option<usize>>, ) -> FlattenUnorderedWithFlowController<Self, ()>
§fn flat_map_unordered<U, F>(
self,
limit: impl Into<Option<usize>>,
f: F,
) -> FlatMapUnordered<Self, U, F>
fn flat_map_unordered<U, F>( self, limit: impl Into<Option<usize>>, f: F, ) -> FlatMapUnordered<Self, U, F>
StreamExt::map] but flattens nested Streams
and polls them concurrently, yielding items in any order, as they made
available. Read more§fn scan<S, B, Fut, F>(self, initial_state: S, f: F) -> Scan<Self, S, Fut, F>
fn scan<S, B, Fut, F>(self, initial_state: S, f: F) -> Scan<Self, S, Fut, F>
StreamExt::fold] that holds internal state
and produces a new stream. Read more§fn skip_while<Fut, F>(self, f: F) -> SkipWhile<Self, Fut, F>
fn skip_while<Fut, F>(self, f: F) -> SkipWhile<Self, Fut, F>
true. Read more§fn take_while<Fut, F>(self, f: F) -> TakeWhile<Self, Fut, F>
fn take_while<Fut, F>(self, f: F) -> TakeWhile<Self, Fut, F>
true. Read more§fn take_until<Fut>(self, fut: Fut) -> TakeUntil<Self, Fut>
fn take_until<Fut>(self, fut: Fut) -> TakeUntil<Self, Fut>
§fn for_each<Fut, F>(self, f: F) -> ForEach<Self, Fut, F>
fn for_each<Fut, F>(self, f: F) -> ForEach<Self, Fut, F>
§fn for_each_concurrent<Fut, F>(
self,
limit: impl Into<Option<usize>>,
f: F,
) -> ForEachConcurrent<Self, Fut, F>
fn for_each_concurrent<Fut, F>( self, limit: impl Into<Option<usize>>, f: F, ) -> ForEachConcurrent<Self, Fut, F>
§fn take(self, n: usize) -> Take<Self>where
Self: Sized,
fn take(self, n: usize) -> Take<Self>where
Self: Sized,
n items of the underlying stream. Read more§fn skip(self, n: usize) -> Skip<Self>where
Self: Sized,
fn skip(self, n: usize) -> Skip<Self>where
Self: Sized,
n items of the underlying stream. Read more§fn catch_unwind(self) -> CatchUnwind<Self>where
Self: Sized + UnwindSafe,
fn catch_unwind(self) -> CatchUnwind<Self>where
Self: Sized + UnwindSafe,
§fn boxed<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + Send + 'a>>
fn boxed<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + Send + 'a>>
§fn boxed_local<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + 'a>>where
Self: Sized + 'a,
fn boxed_local<'a>(self) -> Pin<Box<dyn Stream<Item = Self::Item> + 'a>>where
Self: Sized + 'a,
§fn buffered(self, n: usize) -> Buffered<Self>
fn buffered(self, n: usize) -> Buffered<Self>
§fn buffer_unordered(self, n: usize) -> BufferUnordered<Self>
fn buffer_unordered(self, n: usize) -> BufferUnordered<Self>
§fn zip<St>(self, other: St) -> Zip<Self, St>where
St: Stream,
Self: Sized,
fn zip<St>(self, other: St) -> Zip<Self, St>where
St: Stream,
Self: Sized,
§fn chain<St>(self, other: St) -> Chain<Self, St>where
St: Stream<Item = Self::Item>,
Self: Sized,
fn chain<St>(self, other: St) -> Chain<Self, St>where
St: Stream<Item = Self::Item>,
Self: Sized,
§fn peekable(self) -> Peekable<Self>where
Self: Sized,
fn peekable(self) -> Peekable<Self>where
Self: Sized,
peek method. Read more§fn chunks(self, capacity: usize) -> Chunks<Self>where
Self: Sized,
fn chunks(self, capacity: usize) -> Chunks<Self>where
Self: Sized,
§fn ready_chunks(self, capacity: usize) -> ReadyChunks<Self>where
Self: Sized,
fn ready_chunks(self, capacity: usize) -> ReadyChunks<Self>where
Self: Sized,
§fn forward<S>(self, sink: S) -> Forward<Self, S>where
S: Sink<Self::Ok, Error = Self::Error>,
Self: Sized + TryStream,
fn forward<S>(self, sink: S) -> Forward<Self, S>where
S: Sink<Self::Ok, Error = Self::Error>,
Self: Sized + TryStream,
§fn inspect<F>(self, f: F) -> Inspect<Self, F>
fn inspect<F>(self, f: F) -> Inspect<Self, F>
§fn left_stream<B>(self) -> Either<Self, B>where
B: Stream<Item = Self::Item>,
Self: Sized,
fn left_stream<B>(self) -> Either<Self, B>where
B: Stream<Item = Self::Item>,
Self: Sized,
§fn right_stream<B>(self) -> Either<B, Self>where
B: Stream<Item = Self::Item>,
Self: Sized,
fn right_stream<B>(self) -> Either<B, Self>where
B: Stream<Item = Self::Item>,
Self: Sized,
§fn poll_next_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>where
Self: Unpin,
fn poll_next_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>where
Self: Unpin,
Stream::poll_next] on Unpin
stream types.§fn select_next_some(&mut self) -> SelectNextSome<'_, Self>where
Self: Unpin + FusedStream,
fn select_next_some(&mut self) -> SelectNextSome<'_, Self>where
Self: Unpin + FusedStream,
§impl<S, T, E> TryStream for S
impl<S, T, E> TryStream for S
§impl<S> TryStreamExt for Swhere
S: TryStream + ?Sized,
impl<S> TryStreamExt for Swhere
S: TryStream + ?Sized,
§fn err_into<E>(self) -> ErrInto<Self, E>
fn err_into<E>(self) -> ErrInto<Self, E>
§fn map_ok<T, F>(self, f: F) -> MapOk<Self, F>
fn map_ok<T, F>(self, f: F) -> MapOk<Self, F>
§fn map_err<E, F>(self, f: F) -> MapErr<Self, F>
fn map_err<E, F>(self, f: F) -> MapErr<Self, F>
§fn and_then<Fut, F>(self, f: F) -> AndThen<Self, Fut, F>
fn and_then<Fut, F>(self, f: F) -> AndThen<Self, Fut, F>
f. Read more§fn or_else<Fut, F>(self, f: F) -> OrElse<Self, Fut, F>
fn or_else<Fut, F>(self, f: F) -> OrElse<Self, Fut, F>
f. Read more§fn inspect_ok<F>(self, f: F) -> InspectOk<Self, F>
fn inspect_ok<F>(self, f: F) -> InspectOk<Self, F>
§fn inspect_err<F>(self, f: F) -> InspectErr<Self, F>
fn inspect_err<F>(self, f: F) -> InspectErr<Self, F>
§fn into_stream(self) -> IntoStream<Self>where
Self: Sized,
fn into_stream(self) -> IntoStream<Self>where
Self: Sized,
§fn try_next(&mut self) -> TryNext<'_, Self>where
Self: Unpin,
fn try_next(&mut self) -> TryNext<'_, Self>where
Self: Unpin,
§fn try_for_each<Fut, F>(self, f: F) -> TryForEach<Self, Fut, F>
fn try_for_each<Fut, F>(self, f: F) -> TryForEach<Self, Fut, F>
§fn try_skip_while<Fut, F>(self, f: F) -> TrySkipWhile<Self, Fut, F>
fn try_skip_while<Fut, F>(self, f: F) -> TrySkipWhile<Self, Fut, F>
true. Read more§fn try_take_while<Fut, F>(self, f: F) -> TryTakeWhile<Self, Fut, F>
fn try_take_while<Fut, F>(self, f: F) -> TryTakeWhile<Self, Fut, F>
true. Read more§fn try_for_each_concurrent<Fut, F>(
self,
limit: impl Into<Option<usize>>,
f: F,
) -> TryForEachConcurrent<Self, Fut, F>
fn try_for_each_concurrent<Fut, F>( self, limit: impl Into<Option<usize>>, f: F, ) -> TryForEachConcurrent<Self, Fut, F>
§fn try_collect<C>(self) -> TryCollect<Self, C>
fn try_collect<C>(self) -> TryCollect<Self, C>
§fn try_chunks(self, capacity: usize) -> TryChunks<Self>where
Self: Sized,
fn try_chunks(self, capacity: usize) -> TryChunks<Self>where
Self: Sized,
§fn try_ready_chunks(self, capacity: usize) -> TryReadyChunks<Self>where
Self: Sized,
fn try_ready_chunks(self, capacity: usize) -> TryReadyChunks<Self>where
Self: Sized,
§fn try_filter<Fut, F>(self, f: F) -> TryFilter<Self, Fut, F>
fn try_filter<Fut, F>(self, f: F) -> TryFilter<Self, Fut, F>
§fn try_filter_map<Fut, F, T>(self, f: F) -> TryFilterMap<Self, Fut, F>
fn try_filter_map<Fut, F, T>(self, f: F) -> TryFilterMap<Self, Fut, F>
§fn try_flatten_unordered(
self,
limit: impl Into<Option<usize>>,
) -> TryFlattenUnordered<Self>
fn try_flatten_unordered( self, limit: impl Into<Option<usize>>, ) -> TryFlattenUnordered<Self>
§fn try_flatten(self) -> TryFlatten<Self>
fn try_flatten(self) -> TryFlatten<Self>
§fn try_fold<T, Fut, F>(self, init: T, f: F) -> TryFold<Self, Fut, T, F>
fn try_fold<T, Fut, F>(self, init: T, f: F) -> TryFold<Self, Fut, T, F>
§fn try_concat(self) -> TryConcat<Self>
fn try_concat(self) -> TryConcat<Self>
§fn try_buffer_unordered(self, n: usize) -> TryBufferUnordered<Self>where
Self::Ok: TryFuture<Error = Self::Error>,
Self: Sized,
fn try_buffer_unordered(self, n: usize) -> TryBufferUnordered<Self>where
Self::Ok: TryFuture<Error = Self::Error>,
Self: Sized,
§fn try_buffered(self, n: usize) -> TryBuffered<Self>where
Self::Ok: TryFuture<Error = Self::Error>,
Self: Sized,
fn try_buffered(self, n: usize) -> TryBuffered<Self>where
Self::Ok: TryFuture<Error = Self::Error>,
Self: Sized,
§fn try_poll_next_unpin(
&mut self,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Self::Ok, Self::Error>>>where
Self: Unpin,
fn try_poll_next_unpin(
&mut self,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Self::Ok, Self::Error>>>where
Self: Unpin,
TryStream::try_poll_next] on Unpin
stream types.§fn into_async_read(self) -> IntoAsyncRead<Self>
fn into_async_read(self) -> IntoAsyncRead<Self>
AsyncBufRead. Read more§fn try_all<Fut, F>(self, f: F) -> TryAll<Self, Fut, F>
fn try_all<Fut, F>(self, f: F) -> TryAll<Self, Fut, F>
Err is encountered or if an Ok item is found
that does not satisfy the predicate. Read more