Hone logo
Hone
Problems

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 Stream trait for AsyncDataStream.
  • The next() method of the Stream trait should asynchronously yield the next integer in the sequence (starting from 1).
  • Introduce a delay of delay_ms milliseconds between yielding each integer.
  • When the sequence is exhausted (i.e., the next integer would be greater than n), the next() method should return None.
  • Use tokio for 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:

  • n is 0: The stream should immediately return None without any delay.
  • delay_ms is 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 of n without 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

  • n will be a non-negative integer.
  • delay_ms will be a non-negative integer.
  • You must use the tokio crate 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 your Cargo.toml file.
  • Consider using tokio::time::sleep to introduce the delay.
  • The Stream trait requires you to return a Pin<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 AsyncDataStream struct.
  • Focus on correctness and clarity of code. While performance is a consideration, prioritize a well-structured and understandable solution.
Loading editor...
rust