#[cfg(feature = "context")]
use pleme_error::{ServiceError, Result, Context};
#[cfg(feature = "context")]
use uuid::Uuid;
#[cfg(feature = "context")]
#[derive(Debug)]
struct User {
id: Uuid,
email: String,
age: u32,
}
#[cfg(feature = "context")]
#[derive(Debug)]
struct RegisterInput {
email: String,
password: String,
age: u32,
}
#[cfg(feature = "context")]
fn validate_input(input: &RegisterInput) -> Result<()> {
if !input.email.contains('@') {
return Err(ServiceError::invalid_field("email", "Must be valid email"));
}
if input.password.len() < 8 {
return Err(ServiceError::invalid_field("password", "Must be at least 8 characters"));
}
if input.age < 18 {
return Err(ServiceError::invalid_field("age", "Must be 18 or older"));
}
Ok(()) }
#[cfg(feature = "context")]
fn check_unique_email(email: &str) -> Result<()> {
let existing_users = vec!["existing@example.com", "taken@example.com"];
if existing_users.contains(&email) {
return Err(ServiceError::Conflict(
"Email already registered".to_string()
));
}
Ok(()) }
#[cfg(feature = "context")]
fn create_user(input: RegisterInput) -> Result<User> {
Ok(User {
id: Uuid::new_v4(),
email: input.email,
age: input.age,
})
}
#[cfg(feature = "context")]
fn send_welcome_email(user: &User) -> Result<()> {
println!("📧 Sending welcome email to {}", user.email);
if user.email.contains("bounce") {
return Err(ServiceError::external_service(
"SendGrid",
"Email bounce",
std::io::Error::new(std::io::ErrorKind::Other, "Bounce")
));
}
Ok(()) }
#[cfg(feature = "context")]
fn register_user(input: RegisterInput) -> Result<User> {
validate_input(&input)?; check_unique_email(&input.email)?; let user = create_user(input)?; send_welcome_email(&user)?;
Ok(user) }
#[cfg(feature = "context")]
fn load_config() -> Result<String> {
std::fs::read_to_string("nonexistent.yaml")
.context("Failed to read config file")
.map_err(|e| ServiceError::Configuration(e.to_string()))
}
#[cfg(feature = "context")]
fn main() {
println!("=== Railway-Oriented Programming Examples ===\n");
println!("1. Success Track:");
let valid_input = RegisterInput {
email: "alice@example.com".to_string(),
password: "secure123".to_string(),
age: 25,
};
match register_user(valid_input) {
Ok(user) => println!("✓ User registered: {:?}", user),
Err(e) => println!("✗ Registration failed: {}", e),
}
println!();
println!("2. Error Track - Invalid Email:");
let invalid_email = RegisterInput {
email: "invalid".to_string(), password: "secure123".to_string(),
age: 25,
};
match register_user(invalid_email) {
Ok(user) => println!("✓ User registered: {:?}", user),
Err(e) => println!("✗ Registration failed: {}", e),
}
println!();
println!("3. Error Track - Weak Password:");
let weak_password = RegisterInput {
email: "bob@example.com".to_string(),
password: "123".to_string(), age: 25,
};
match register_user(weak_password) {
Ok(user) => println!("✓ User registered: {:?}", user),
Err(e) => println!("✗ Registration failed: {}", e),
}
println!();
println!("4. Error Track - Underage:");
let underage = RegisterInput {
email: "young@example.com".to_string(),
password: "secure123".to_string(),
age: 16, };
match register_user(underage) {
Ok(user) => println!("✓ User registered: {:?}", user),
Err(e) => println!("✗ Registration failed: {}", e),
}
println!();
println!("5. Error Track - Duplicate Email:");
let duplicate = RegisterInput {
email: "existing@example.com".to_string(), password: "secure123".to_string(),
age: 25,
};
match register_user(duplicate) {
Ok(user) => println!("✓ User registered: {:?}", user),
Err(e) => println!("✗ Registration failed: {}", e),
}
println!();
println!("6. Error Track - Email Service Failure:");
let bounce = RegisterInput {
email: "bounce@example.com".to_string(), password: "secure123".to_string(),
age: 25,
};
match register_user(bounce) {
Ok(user) => println!("✓ User registered: {:?}", user),
Err(e) => println!("✗ Registration failed: {}", e),
}
println!();
println!("7. Error Context:");
match load_config() {
Ok(config) => println!("✓ Config loaded: {}", config),
Err(e) => println!("✗ Config load failed: {}", e),
}
println!();
println!("\n=== Key Principles ===");
println!("1. Two tracks: Success path and Error path");
println!("2. Any operation can switch to error track (using ?)");
println!("3. Once on error track, skip remaining operations");
println!("4. Errors flow to final error handler");
println!("5. Composable: Each function returns Result<T>");
}
#[cfg(not(feature = "context"))]
fn main() {
eprintln!("This example requires the 'context' feature.");
eprintln!("Run with: cargo run --example railway_oriented --features context");
}