Asynchronous Data Stream Processing with Async Iterators in Rust
Asynchronous iterators are crucial for efficiently handling data streams that arrive over time, such as from network connections or file reads. This challenge asks you to implement an asynchronous iterator that yields values from a simulated asynchronous data source. Successfully completing this challenge demonstrates understanding of Rust's async and Stream traits, enabling you to build responsive and performant applications dealing with asynchronous data.
Problem Description
You are tasked with creating an AsyncDataStream struct that implements the Stream trait. This struct will simulate an asynchronous data source that produces a sequence of integers. The data source will yield integers from 1 to n (inclusive), with a delay of delay_ms milliseconds between each integer. The AsyncDataStream should be initialized with the upper bound n and the delay in milliseconds delay_ms.
Key Requirements:
- Implement the
Streamtrait forAsyncDataStream. - The
next()method of theStreamtrait should asynchronously yield the next integer in the sequence (starting from 1). - Introduce a delay of
delay_msmilliseconds between yielding each integer. - When the sequence is exhausted (i.e., the next integer would be greater than
n), thenext()method should returnNone. - Use
tokiofor asynchronous operations.
Expected Behavior:
The AsyncDataStream should behave as an asynchronous iterator, yielding integers one at a time with the specified delay. The stream should terminate gracefully when all integers from 1 to n have been yielded.
Edge Cases to Consider:
nis 0: The stream should immediately returnNonewithout any delay.delay_msis 0: The integers should be yielded as quickly as possible (though not necessarily instantaneously due to Rust's async runtime).- Large
n: The stream should handle large values ofnwithout excessive memory usage.
Examples
Example 1:
Input: n = 3, delay_ms = 100
Output: 1, 2, 3 (each yielded with a 100ms delay)
Explanation: The stream yields integers from 1 to 3, pausing for 100ms between each.
Example 2:
Input: n = 0, delay_ms = 50
Output: None
Explanation: The stream immediately returns None because n is 0.
Example 3:
Input: n = 5, delay_ms = 200
Output: 1, 2, 3, 4, 5 (each yielded with a 200ms delay)
Explanation: The stream yields integers from 1 to 5, pausing for 200ms between each.
Constraints
nwill be a non-negative integer.delay_mswill be a non-negative integer.- You must use the
tokiocrate for asynchronous operations. - The solution should be efficient in terms of memory usage. Avoid storing the entire sequence in memory.
- The solution should compile and run without panics.
Notes
- You'll need to add
tokio = { version = "1", features = ["full"] }to yourCargo.tomlfile. - Consider using
tokio::time::sleepto introduce the delay. - The
Streamtrait requires you to return aPin<Box<dyn Future<Output = Option<T>>>>. - Think about how to manage the state of the iterator (current integer, whether the stream is exhausted) within the
AsyncDataStreamstruct. - Focus on correctness and clarity of code. While performance is a consideration, prioritize a well-structured and understandable solution.