Getting Started
This guide will help you get started with Ichika, from installation to your first pipeline.
Installation
Add Ichika to your Cargo.toml:
[dependencies]
ichika = "0.1"
Feature Flags
Ichika supports different async runtimes via feature flags:
# For tokio support (default)
ichika = { version = "0.1", features = ["tokio"] }
# For async-std support
ichika = { version = "0.1", features = ["async-std"] }
# For both runtimes
ichika = { version = "0.1", features = ["tokio", "async-std"] }
Your First Pipeline
Let’s create a simple pipeline that processes strings:
use ichika::prelude::*;
fn main() -> anyhow::Result<()> {
// Define a 3-stage pipeline
let pool = pipe![
// Stage 1: Parse string to number
|req: String| -> anyhow::Result<usize> {
req.parse::<usize>()
.map_err(|e| anyhow::anyhow!("Failed to parse: {}", e))
},
// Stage 2: Double the number
|req: anyhow::Result<usize>| -> anyhow::Result<usize> {
req.map(|n| n * 2)
},
// Stage 3: Convert back to string
|req: anyhow::Result<usize>| -> String {
req.map(|n| n.to_string())
.unwrap_or_else(|e| format!("Error: {}", e))
}
]?;
// Process some data
pool.send("42".to_string())?;
pool.send("100".to_string())?;
pool.send("invalid".to_string())?;
// Collect results
for _ in 0..3 {
if let Some(result) = pool.recv()? {
println!("Result: {}", result);
}
}
Ok(())
}
Understanding the Basics
The pipe! Macro
The pipe! macro creates a chain of processing stages. Each stage:
- Receives input from the previous stage (or the initial
send()call) - Processes the data in a thread pool
- Passes the result to the next stage
Type Propagation
Ichika automatically infers the types flowing through your pipeline:
#![allow(unused)]
fn main() {
let pool = pipe![
|req: String| -> usize { req.len() }, // String -> usize
|req: usize| -> String { req.to_string() } // usize -> String
]?;
}
Error Handling
Each stage can return a Result, and errors are automatically propagated:
#![allow(unused)]
fn main() {
let pool = pipe![
|req: String| -> anyhow::Result<i32> {
req.parse().map_err(Into::into)
},
|req: anyhow::Result<i32>| -> i32 {
req.unwrap() // or handle the error appropriately
}
]?;
}
Next Steps
- Learn more about the pipe! macro
- Understand the ThreadPool trait
- Explore error handling in depth
- See more examples