Building a Simple Async Data Processor with Rust Streams
Asynchronous programming in Rust, particularly with async streams, allows for efficient handling of data that arrives over time without blocking the main thread. This challenge will guide you through creating a basic asynchronous data processing pipeline, demonstrating how to generate, transform, and consume data asynchronously.
Problem Description
Your task is to implement a Rust program that simulates processing a stream of data asynchronously. You will need to:
- Create an asynchronous stream that generates a sequence of numbers.
- Transform this stream by applying a function to each element.
- Consume the transformed stream and print each element.
This exercise will involve using the futures and tokio crates to manage asynchronous operations and streams.
Key Requirements
- Stream Generation: Implement a custom
Streamthat yieldsu32values. - Stream Transformation: Use
stream.map()to transform eachu32into its double. - Stream Consumption: Iterate over the transformed stream asynchronously and print each doubled number.
- Asynchronous Runtime: Utilize
tokioas the asynchronous runtime.
Expected Behavior
The program should start, generate numbers from 0 up to a certain limit, double each number, and print the doubled numbers to the console, each on a new line.
Edge Cases to Consider
- What happens if the stream generation is very slow? (Though for this basic example, we'll simulate quick generation.)
- How do you correctly handle the end of the stream?
Examples
Example 1:
Input: Stream generates numbers from 0 to 4.
Output:
0
2
4
6
8
Explanation: The stream generates 0, 1, 2, 3, 4. Each number is doubled (0*2=0, 1*2=2, etc.) and printed.
Example 2:
Input: Stream generates numbers from 0 to 2.
Output:
0
2
4
Explanation: The stream generates 0, 1, 2. Each number is doubled (0*2=0, 1*2=2, 2*2=4) and printed.
Constraints
- The stream should generate at most 100 numbers (from 0 to 99).
- The numbers generated will be unsigned 32-bit integers (
u32). - The transformation function should be simple multiplication by 2.
- The output should be printed to standard output.
- Your solution must use the
tokioruntime and thefuturescrate.
Notes
- You'll need to add
tokioandfuturesto yourCargo.tomldependencies. - Consider using
tokio::time::sleepto simulate some work if you want to observe the asynchronous nature more clearly, although it's not strictly required for the core functionality. - The
futurescrate provides theStreamtrait and various combinator methods likemap. - Remember to use
#[tokio::main]to set up the asynchronous entry point for your application. - The
futures::stream::StreamExttrait provides useful extension methods for streams.