Web Error Handling Rust Samples

Web Rust error handling examples including exception catching, logging, and parameter validation

Key Facts

Category
Rust
Items
3
Format Families
audio

Sample Overview

Web Rust error handling examples including exception catching, logging, and parameter validation This sample set belongs to Rust and can be used to test related workflows inside Elysia Tools.

💻 Logging rust

🟢 simple ⭐⭐⭐

Write logs to files and console with different levels

⏱️ 20 min 🏷️ rust, web, error handling
Prerequisites: Basic Rust, chrono crate
// Web Rust Logging Examples
// Log writing to files and console
//
// Add to Cargo.toml:
// [dependencies]
// log = "0.4"
// env_logger = "0.10"
// chrono = "0.4"

use std::fs::{File, OpenOptions};
use std::io::Write;
use std::path::Path;

// 1. Simple Logging to File

/// Log message to file
fn log_to_file(path: &str, message: &str) -> std::io::Result<()> {
    let mut file = OpenOptions::new()
        .create(true)
        .append(true)
        .open(path)?;
    writeln!(file, "{}", message)?;
    Ok(())
}

/// Log with timestamp
fn log_with_timestamp(path: &str, level: &str, message: &str) -> std::io::Result<()> {
    let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S");
    let log_entry = format!("[{}] {} - {}", timestamp, level, message);
    log_to_file(path, &log_entry)
}

// 2. Log Levels

/// Log debug message
fn log_debug(path: &str, message: &str) -> std::io::Result<()> {
    log_with_timestamp(path, "DEBUG", message)
}

/// Log info message
fn log_info(path: &str, message: &str) -> std::io::Result<()> {
    log_with_timestamp(path, "INFO", message)
}

/// Log warning message
fn log_warning(path: &str, message: &str) -> std::io::Result<()> {
    log_with_timestamp(path, "WARNING", message)
}

/// Log error message
fn log_error(path: &str, message: &str) -> std::io::Result<()> {
    log_with_timestamp(path, "ERROR", message)
}

// 3. Structured Logging

/// Structured log entry
#[derive(Debug)]
struct LogEntry {
    timestamp: String,
    level: String,
    message: String,
    module: Option<String>,
}

impl LogEntry {
    fn new(level: &str, message: &str) -> Self {
        LogEntry {
            timestamp: chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f").to_string(),
            level: level.to_string(),
            message: message.to_string(),
            module: None,
        }
    }

    fn with_module(mut self, module: &str) -> Self {
        self.module = Some(module.to_string());
        self
    }

    fn format(&self) -> String {
        match &self.module {
            Some(m) => format!("[{}] [{}] [{}] - {}", self.timestamp, self.level, m, self.message),
            None => format!("[{}] [{}] - {}", self.timestamp, self.level, self.message),
        }
    }
}

/// Write structured log
fn write_structured_log(path: &str, entry: &LogEntry) -> std::io::Result<()> {
    log_to_file(path, &entry.format())
}

// 4. Logger with Multiple Outputs

/// Simple logger that writes to multiple destinations
struct MultiLogger {
    log_file: String,
    console: bool,
}

impl MultiLogger {
    fn new(log_file: &str, console: bool) -> Self {
        MultiLogger {
            log_file: log_file.to_string(),
            console,
        }
    }

    fn log(&self, level: &str, message: &str) -> std::io::Result<()> {
        let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S");
        let log_entry = format!("[{}] {} - {}", timestamp, level, message);

        // Write to file
        if !self.log_file.is_empty() {
            log_to_file(&self.log_file, &log_entry)?;
        }

        // Write to console
        if self.console {
            println!("{}", log_entry);
        }

        Ok(())
    }

    fn info(&self, message: &str) -> std::io::Result<()> {
        self.log("INFO", message)
    }

    fn warning(&self, message: &str) -> std::io::Result<()> {
        self.log("WARNING", message)
    }

    fn error(&self, message: &str) -> std::io::Result<()> {
        self.log("ERROR", message)
    }

    fn debug(&self, message: &str) -> std::io::Result<()> {
        self.log("DEBUG", message)
    }
}

// 5. Rotating Log Files

/// Rotating logger
struct RotatingLogger {
    base_path: String,
    max_size: u64,
    current_file: String,
    current_size: u64,
}

impl RotatingLogger {
    fn new(base_path: &str, max_size: u64) -> Self {
        let current_file = format!("{}.log", base_path);
        RotatingLogger {
            base_path: base_path.to_string(),
            max_size,
            current_file: current_file.clone(),
            current_size: std::fs::metadata(&current_file).map(|m| m.len()).unwrap_or(0),
        }
    }

    fn log(&mut self, message: &str) -> std::io::Result<()> {
        let entry = format!("{}\n", message);
        let entry_size = entry.len() as u64;

        // Check if rotation needed
        if self.current_size + entry_size > self.max_size {
            self.rotate()?;
        }

        // Append to current file
        let mut file = OpenOptions::new()
            .create(true)
            .append(true)
            .open(&self.current_file)?;
        file.write_all(entry.as_bytes())?;
        self.current_size += entry_size;

        Ok(())
    }

    fn rotate(&mut self) -> std::io::Result<()> {
        // Find next available number
        let mut counter = 1;
        loop {
            let archive_name = format!("{}.{}.log", self.base_path, counter);
            if !Path::new(&archive_name).exists() {
                std::fs::rename(&self.current_file, &archive_name)?;
                break;
            }
            counter += 1;
        }

        // Reset current file
        self.current_size = 0;
        Ok(())
    }
}

// 6. Conditional Logging

/// Logger with level filtering
struct LevelLogger {
    log_file: String,
    min_level: String,
}

impl LevelLogger {
    fn new(log_file: &str, min_level: &str) -> Self {
        LevelLogger {
            log_file: log_file.to_string(),
            min_level: min_level.to_string(),
        }
    }

    fn should_log(&self, level: &str) -> bool {
        let levels = vec!["DEBUG", "INFO", "WARNING", "ERROR"];
        let current = levels.iter().position(|&l| l == level).unwrap_or(0);
        let min = levels.iter().position(|&l| l == &self.min_level).unwrap_or(0);
        current >= min
    }

    fn log(&self, level: &str, message: &str) -> std::io::Result<()> {
        if self.should_log(level) {
            log_with_timestamp(&self.log_file, level, message)?;
        }
        Ok(())
    }
}

// 7. Async Logging (Simplified)

/// Async-style logger using channels
use std::sync::mpsc;
use std::thread;

struct AsyncLogger {
    sender: mpsc::Sender<String>,
}

impl AsyncLogger {
    fn new(log_file: &str) -> Self {
        let (sender, receiver) = mpsc::channel();
        let log_file = log_file.to_string();

        thread::spawn(move || {
            let mut file = OpenOptions::new()
                .create(true)
                .append(true)
                .open(&log_file)
                .unwrap();

            for message in receiver {
                writeln!(file, "{}", message).unwrap();
            }
        });

        AsyncLogger { sender }
    }

    fn log(&self, message: &str) -> std::io::Result<()> {
        self.sender.send(message.to_string()).map_err(|e| {
            std::io::Error::new(std::io::ErrorKind::Other, e)
        })?;
        Ok(())
    }
}

// 8. Performance Logging

/// Performance logger
fn log_performance(path: &str, operation: &str, duration_ms: u128) -> std::io::Result<()> {
    let message = format!("Operation '{}' took {}ms", operation, duration_ms);
    log_with_timestamp(path, "PERF", &message)
}

/// Measure execution time
fn measure_time<F, T>(f: F) -> T
where
    F: FnOnce() -> T,
{
    f()
}

/// Measure and log execution time
fn measure_and_log<F, T>(path: &str, operation: &str, f: F) -> T
where
    F: FnOnce() -> T,
{
    let start = std::time::Instant::now();
    let result = f();
    let duration = start.elapsed().as_millis();
    let _ = log_performance(path, operation, duration);
    result
}

// 9. Error Logging

/// Log error with backtrace
fn log_error_with_context(path: &str, error: &str, context: &str) -> std::io::Result<()> {
    let message = format!("Error in '{}': {}", context, error);
    log_with_timestamp(path, "ERROR", &message)
}

/// Log warning with details
fn log_warning_details(path: &str, message: &str, details: &str) -> std::io::Result<()> {
    let log_msg = format!("{} | Details: {}", message, details);
    log_with_timestamp(path, "WARNING", &log_msg)
}

// 10. Batch Logging

/// Log multiple messages efficiently
fn log_batch(path: &str, messages: &[&str]) -> std::io::Result<()> {
    let mut file = OpenOptions::new()
        .create(true)
        .append(true)
        .open(path)?;

    for message in messages {
        let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S");
        writeln!(file, "[{}] - {}", timestamp, message)?;
    }

    Ok(())
}

// Usage Examples
fn main() -> std::io::Result<()> {
    println!("=== Web Rust Logging Examples ===\n");

    let log_file = "application.log";

    // 1. Basic logging
    println!("--- 1. Basic Logging ---");
    log_to_file(log_file, "Application started")?;
    log_with_timestamp(log_file, "INFO", "System initialized")?;

    // 2. Log levels
    println!("
--- 2. Log Levels ---");
    log_debug(log_file, "Debug information")?;
    log_info(log_file, "Application running")?;
    log_warning(log_file, "High memory usage")?;
    log_error(log_file, "Connection failed")?;

    // 3. Structured logging
    println!("
--- 3. Structured Logging ---");
    let entry = LogEntry::new("INFO", "User logged in").with_module("Auth");
    write_structured_log(log_file, &entry)?;

    // 4. Multi-logger
    println!("
--- 4. Multi-Logger ---");
    let logger = MultiLogger::new("multi.log", true);
    logger.info("Multi-logger initialized")?;
    logger.warning("This goes to console and file")?;
    logger.error("Error occurred")?;

    // 5. Level filtering
    println!("
--- 5. Level Filtering ---");
    let level_logger = LevelLogger::new("filtered.log", "WARNING");
    level_logger.log("DEBUG", "This won't be logged")?;
    level_logger.log("WARNING", "This will be logged")?;
    level_logger.log("ERROR", "This will be logged")?;

    // 6. Performance logging
    println!("
--- 6. Performance Logging ---");
    let result = measure_and_log(log_file, "test_operation", || {
        std::thread::sleep(std::time::Duration::from_millis(100));
        42
    });
    println!("Result: {}", result);

    // 7. Error logging
    println!("
--- 7. Error Logging ---");
    log_error_with_context(log_file, "File not found", "load_config")?;
    log_warning_details(log_file, "Slow query", "took 5 seconds")?;

    // 8. Batch logging
    println!("
--- 8. Batch Logging ---");
    let messages = vec![
        "Message 1",
        "Message 2",
        "Message 3",
    ];
    log_batch(log_file, &messages)?;

    // 9. Rotating logger
    println!("
--- 9. Rotating Logger ---");
    let mut rotating_logger = RotatingLogger::new("rotating", 1024);
    for i in 0..10 {
        rotating_logger.log(&format!("Log entry {}", i))?;
    }

    println!("
=== All Logging Examples Completed ===");
    println!("Check {} for log output", log_file);
    Ok(())
}

💻 Parameter Validation rust

🟢 simple ⭐⭐⭐

Validate function parameters with custom rules and error messages

⏱️ 20 min 🏷️ rust, web, error handling
Prerequisites: Basic Rust
// Web Rust Parameter Validation Examples
// Function parameter validation with custom rules

use std::fmt;

// 1. Validation Error Types

/// Validation error
#[derive(Debug, Clone, PartialEq)]
enum ValidationError {
    TooShort(String, usize),
    TooLong(String, usize),
    InvalidFormat(String),
    OutOfRange(String, String),
    Required(String),
    Custom(String),
}

impl fmt::Display for ValidationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ValidationError::TooShort(field, min) => {
                write!(f, "{} must be at least {} characters", field, min)
            },
            ValidationError::TooLong(field, max) => {
                write!(f, "{} must be at most {} characters", field, max)
            },
            ValidationError::InvalidFormat(field) => {
                write!(f, "{} has invalid format", field)
            },
            ValidationError::OutOfRange(field, range) => {
                write!(f, "{} must be in range {}", field, range)
            },
            ValidationError::Required(field) => {
                write!(f, "{} is required", field)
            },
            ValidationError::Custom(msg) => {
                write!(f, "{}", msg)
            },
        }
    }
}

impl std::error::Error for ValidationError {}

// 2. String Validation

/// Validate string length
fn validate_length(value: &str, field: &str, min: usize, max: usize) -> Result<(), ValidationError> {
    if value.is_empty() {
        return Err(ValidationError::Required(field.to_string()));
    }
    if value.len() < min {
        return Err(ValidationError::TooShort(field.to_string(), min));
    }
    if value.len() > max {
        return Err(ValidationError::TooLong(field.to_string(), max));
    }
    Ok(())
}

/// Validate email format
fn validate_email(email: &str) -> Result<(), ValidationError> {
    if email.is_empty() {
        return Err(ValidationError::Required("Email".to_string()));
    }

    // Basic email validation
    if !email.contains('@') || !email.contains('.') {
        return Err(ValidationError::InvalidFormat("Email".to_string()));
    }

    let parts: Vec<&str> = email.split('@').collect();
    if parts.len() != 2 {
        return Err(ValidationError::InvalidFormat("Email".to_string()));
    }

    let (local, domain) = (parts[0], parts[1]);
    if local.is_empty() || domain.is_empty() || !domain.contains('.') {
        return Err(ValidationError::InvalidFormat("Email".to_string()));
    }

    Ok(())
}

/// Validate URL format
fn validate_url(url: &str) -> Result<(), ValidationError> {
    if url.is_empty() {
        return Err(ValidationError::Required("URL".to_string()));
    }

    if !url.starts_with("http://") && !url.starts_with("https://") {
        return Err(ValidationError::InvalidFormat("URL".to_string()));
    }

    Ok(())
}

/// Validate username
fn validate_username(username: &str) -> Result<(), ValidationError> {
    validate_length(username, "Username", 3, 20)?;

    // Must be alphanumeric with underscores
    if !username.chars().all(|c| c.is_alphanumeric() || c == '_') {
        return Err(ValidationError::InvalidFormat("Username".to_string()));
    }

    Ok(())
}

/// Validate password
fn validate_password(password: &str) -> Result<(), ValidationError> {
    validate_length(password, "Password", 8, 128)?;

    let has_upper = password.chars().any(|c| c.is_uppercase());
    let has_lower = password.chars().any(|c| c.is_lowercase());
    let has_digit = password.chars().any(|c| c.is_ascii_digit());

    if !has_upper {
        return Err(ValidationError::Custom(
            "Password must contain at least one uppercase letter".to_string()
        ));
    }
    if !has_lower {
        return Err(ValidationError::Custom(
            "Password must contain at least one lowercase letter".to_string()
        ));
    }
    if !has_digit {
        return Err(ValidationError::Custom(
            "Password must contain at least one digit".to_string()
        ));
    }

    Ok(())
}

// 3. Numeric Validation

/// Validate number in range
fn validate_range<T: PartialOrd>(value: T, field: &str, min: T, max: T) -> Result<(), ValidationError> {
    if value < min || value > max {
        return Err(ValidationError::OutOfRange(
            field.to_string(),
            format!("{:?} to {:?}", min, max)
        ));
    }
    Ok(())
}

/// Validate positive number
fn validate_positive<T: PartialOrd + Default>(value: T, field: &str) -> Result<(), ValidationError> {
    if value <= T::default() {
        return Err(ValidationError::Custom(
            format!("{} must be positive", field)
        ));
    }
    Ok(())
}

/// Validate non-negative number
fn validate_non_negative<T: PartialOrd + Default>(value: T, field: &str) -> Result<(), ValidationError> {
    if value < T::default() {
        return Err(ValidationError::Custom(
            format!("{} must be non-negative", field)
        ));
    }
    Ok(())
}

// 4. Collection Validation

/// Validate collection not empty
fn validate_not_empty<T>(collection: &[T], field: &str) -> Result<(), ValidationError> {
    if collection.is_empty() {
        return Err(ValidationError::Custom(
            format!("{} must not be empty", field)
        ));
    }
    Ok(())
}

/// Validate collection size
fn validate_collection_size<T>(collection: &[T], field: &str, min: usize, max: usize) -> Result<(), ValidationError> {
    if collection.len() < min {
        return Err(ValidationError::Custom(
            format!("{} must have at least {} items", field, min)
        ));
    }
    if collection.len() > max {
        return Err(ValidationError::Custom(
            format!("{} must have at most {} items", field, max)
        ));
    }
    Ok(())
}

/// Validate all unique
fn validate_all_unique<T: std::hash::Hash + Eq + std::fmt::Debug>(collection: &[T], field: &str) -> Result<(), ValidationError> {
    use std::collections::HashSet;
    let unique: HashSet<_> = collection.iter().collect();
    if unique.len() != collection.len() {
        return Err(ValidationError::Custom(
            format!("{} must contain only unique items", field)
        ));
    }
    Ok(())
}

// 5. Date/Time Validation

/// Validate age range
fn validate_age(age: u32) -> Result<(), ValidationError> {
    if age < 0 {
        return Err(ValidationError::Custom("Age cannot be negative".to_string()));
    }
    if age > 150 {
        return Err(ValidationError::Custom("Age cannot exceed 150".to_string()));
    }
    Ok(())
}

/// Validate year range
fn validate_year(year: i32) -> Result<(), ValidationError> {
    validate_range(year, "Year", 1900, 2100)
}

// 6. Custom Validation Rules

/// Validation rule type
type ValidationRule<T> = Box<dyn Fn(&T) -> Result<(), ValidationError>>;

/// Apply multiple validation rules
fn validate_with_rules<T>(value: &T, rules: &[ValidationRule<T>]) -> Result<(), ValidationError> {
    for rule in rules {
        rule(value)?;
    }
    Ok(())
}

/// Create length rule
fn length_rule(field: &'static str, min: usize, max: usize) -> ValidationRule<String> {
    Box::new(move |value: &String| {
        validate_length(value, field, min, max)
    })
}

/// Create range rule
fn range_rule<T: PartialOrd + Copy>(field: &'static str, min: T, max: T) -> ValidationRule<T> {
    Box::new(move |value: &T| {
        validate_range(*value, field, min, max)
    })
}

// 7. Composite Validation

/// User data validation
#[derive(Debug)]
struct User {
    username: String,
    email: String,
    age: u32,
}

impl User {
    fn validate(&self) -> Result<(), Vec<ValidationError>> {
        let mut errors = Vec::new();

        if let Err(e) = validate_username(&self.username) {
            errors.push(e);
        }

        if let Err(e) = validate_email(&self.email) {
            errors.push(e);
        }

        if let Err(e) = validate_age(self.age) {
            errors.push(e);
        }

        if errors.is_empty() {
            Ok(())
        } else {
            Err(errors)
        }
    }
}

/// Product validation
#[derive(Debug)]
struct Product {
    name: String,
    price: f64,
    quantity: u32,
}

impl Product {
    fn validate(&self) -> Result<(), Vec<ValidationError>> {
        let mut errors = Vec::new();

        validate_length(&self.name, "Name", 1, 100)
            .map_err(|e| errors.push(e)).ok();

        validate_range(self.price, "Price", 0.0, 1000000.0)
            .map_err(|e| errors.push(e)).ok();

        validate_non_negative(self.quantity, "Quantity")
            .map_err(|e| errors.push(e)).ok();

        if errors.is_empty() {
            Ok(())
        } else {
            Err(errors)
        }
    }
}

// 8. Conditional Validation

/// Validate with condition
fn validate_if(condition: bool, validation: Result<(), ValidationError>) -> Result<(), ValidationError> {
    if condition {
        validation
    } else {
        Ok(())
    }
}

/// Validate required if
fn validate_required_if(value: &str, condition: bool, field: &str) -> Result<(), ValidationError> {
    validate_if(condition && value.is_empty(), Err(ValidationError::Required(field.to_string())))
}

// 9. Sanitization

/// Trim and validate
fn validate_trimmed(value: &str, field: &str, min: usize, max: usize) -> Result<(), ValidationError> {
    let trimmed = value.trim();
    validate_length(trimmed, field, min, max)
}

/// Sanitize email
fn sanitize_email(email: &str) -> String {
    email.trim().to_lowercase()
}

// 10. Validation Builder

/// Simple validation builder
struct Validator<'a, T> {
    value: &'a T,
    errors: Vec<ValidationError>,
}

impl<'a, T> Validator<'a, T> {
    fn new(value: &'a T) -> Self {
        Validator {
            value,
            errors: Vec::new(),
        }
    }

    fn add_rule<F>(mut self, rule: F) -> Self
    where
        F: FnOnce(&T) -> Result<(), ValidationError>,
    {
        if let Err(e) = rule(self.value) {
            self.errors.push(e);
        }
        self
    }

    fn validate(self) -> Result<(), Vec<ValidationError>> {
        if self.errors.is_empty() {
            Ok(())
        } else {
            Err(self.errors)
        }
    }
}

// Usage Examples
fn main() {
    println!("=== Web Rust Parameter Validation Examples ===\n");

    // 1. String validation
    println!("--- 1. String Validation ---");
    match validate_username("user123") {
        Ok(_) => println!("'user123' is valid"),
        Err(e) => println!("Error: {}", e),
    }
    match validate_username("ab") {
        Ok(_) => println!("'ab' is valid"),
        Err(e) => println!("Error: {}", e),
    }

    // 2. Email validation
    println!("
--- 2. Email Validation ---");
    match validate_email("[email protected]") {
        Ok(_) => println!("'[email protected]' is valid"),
        Err(e) => println!("Error: {}", e),
    }
    match validate_email("invalid-email") {
        Ok(_) => println!("'invalid-email' is valid"),
        Err(e) => println!("Error: {}", e),
    }

    // 3. Password validation
    println!("
--- 3. Password Validation ---");
    match validate_password("SecurePass123") {
        Ok(_) => println!("Password is valid"),
        Err(e) => println!("Error: {}", e),
    }
    match validate_password("weak") {
        Ok(_) => println!("Password is valid"),
        Err(e) => println!("Error: {}", e),
    }

    // 4. Numeric validation
    println!("
--- 4. Numeric Validation ---");
    match validate_range(50, "Age", 0, 120) {
        Ok(_) => println!("Age 50 is valid"),
        Err(e) => println!("Error: {}", e),
    }
    match validate_range(150, "Age", 0, 120) {
        Ok(_) => println!("Age 150 is valid"),
        Err(e) => println!("Error: {}", e),
    }

    // 5. Collection validation
    println!("
--- 5. Collection Validation ---");
    let items = vec![1, 2, 3, 4, 5];
    match validate_collection_size(&items, "Items", 1, 10) {
        Ok(_) => println!("Collection size is valid"),
        Err(e) => println!("Error: {}", e),
    }

    let empty: Vec<i32> = vec![];
    match validate_not_empty(&empty, "Items") {
        Ok(_) => println!("Collection is valid"),
        Err(e) => println!("Error: {}", e),
    }

    // 6. User validation
    println!("
--- 6. User Validation ---");
    let user = User {
        username: "john_doe".to_string(),
        email: "[email protected]".to_string(),
        age: 25,
    };
    match user.validate() {
        Ok(_) => println!("User is valid: {:?}", user),
        Err(errors) => {
            println!("User validation failed:");
            for e in errors {
                println!("  - {}", e);
            }
        },
    }

    // 7. Product validation
    println!("
--- 7. Product Validation ---");
    let product = Product {
        name: "Laptop".to_string(),
        price: 999.99,
        quantity: 10,
    };
    match product.validate() {
        Ok(_) => println!("Product is valid: {:?}", product),
        Err(errors) => {
            println!("Product validation failed:");
            for e in errors {
                println!("  - {}", e);
            }
        },
    }

    // 8. Validation builder
    println!("
--- 8. Validation Builder ---");
    let result = Validator::new(&"test value")
        .add_rule(|v| validate_length(v, "Field", 3, 20))
        .add_rule(|v| if v.chars().all(|c| c.is_alphanumeric()) {
            Ok(())
        } else {
            Err(ValidationError::InvalidFormat("Field".to_string()))
        })
        .validate();

    match result {
        Ok(_) => println!("Builder validation passed"),
        Err(errors) => {
            println!("Builder validation failed:");
            for e in errors {
                println!("  - {}", e);
            }
        },
    }

    // 9. URL validation
    println!("
--- 9. URL Validation ---");
    match validate_url("https://example.com") {
        Ok(_) => println!("URL is valid"),
        Err(e) => println!("Error: {}", e),
    }

    println!("
=== All Parameter Validation Examples Completed ===");
}

💻 Exception Catching rust

🟡 intermediate ⭐⭐⭐

Handle errors using Result, Option, and custom error types

⏱️ 25 min 🏷️ rust, web, error handling
Prerequisites: Intermediate Rust
// Web Rust Exception Catching Examples
// Error handling with Result, Option, and custom errors

use std::fmt;
use std::io;

// 1. Custom Error Types

/// Custom error type with detailed information
#[derive(Debug)]
enum AppError {
    Io(io::Error),
    Parse(String),
    Validation(String),
    NotFound(String),
    Permission(String),
}

impl fmt::Display for AppError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            AppError::Io(err) => write!(f, "IO error: {}", err),
            AppError::Parse(msg) => write!(f, "Parse error: {}", msg),
            AppError::Validation(msg) => write!(f, "Validation error: {}", msg),
            AppError::NotFound(msg) => write!(f, "Not found: {}", msg),
            AppError::Permission(msg) => write!(f, "Permission denied: {}", msg),
        }
    }
}

impl std::error::Error for AppError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            AppError::Io(err) => Some(err),
            _ => None,
        }
    }
}

impl From<io::Error> for AppError {
    fn from(err: io::Error) -> Self {
        AppError::Io(err)
    }
}

// 2. Result Handling

/// Basic Result handling
fn divide(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 {
        Err(String::from("Division by zero"))
    } else {
        Ok(a / b)
    }
}

/// Result with custom error
fn read_file_content(path: &str) -> Result<String, AppError> {
    std::fs::read_to_string(path).map_err(AppError::from)
}

/// Chain multiple Results
fn process_file(path: &str) -> Result<usize, AppError> {
    let content = read_file_content(path)?;
    let count = content.lines().count();
    Ok(count)
}

// 3. Option Handling

/// Safe division returning Option
fn safe_divide(a: f64, b: f64) -> Option<f64> {
    if b == 0.0 {
        None
    } else {
        Some(a / b)
    }
}

/// Get element from vector
fn get_element<T>(vec: &[T], index: usize) -> Option<&T> {
    vec.get(index)
}

/// Parse to integer with Option
fn parse_optional(s: &str) -> Option<i32> {
    s.parse().ok()
}

// 4. Error Propagation

/// Function that propagates errors
fn load_config(path: &str) -> Result<String, AppError> {
    let content = std::fs::read_to_string(path)?;
    Ok(content)
}

/// Function with custom error creation
fn validate_username(name: &str) -> Result<(), AppError> {
    if name.is_empty() {
        return Err(AppError::Validation("Username cannot be empty".to_string()));
    }
    if name.len() < 3 {
        return Err(AppError::Validation("Username must be at least 3 characters".to_string()));
    }
    if name.len() > 20 {
        return Err(AppError::Validation("Username must be at most 20 characters".to_string()));
    }
    Ok(())
}

// 5. Multiple Error Types

/// Operation that can fail in multiple ways
fn complex_operation(path: &str) -> Result<String, Box<dyn std::error::Error>> {
    let content = std::fs::read_to_string(path)?;
    let trimmed = content.trim();
    if trimmed.is_empty() {
        return Err("File is empty".into());
    }
    Ok(trimmed.to_string())
}

// 6. Error Recovery

/// Attempt operation with fallback
fn read_with_fallback(path: &str, fallback: &str) -> String {
    read_file_content(path).unwrap_or_else(|_| fallback.to_string())
}

/// Try multiple alternatives
fn try_alternatives(paths: &[&str]) -> Result<String, AppError> {
    for path in paths {
        if let Ok(content) = read_file_content(path) {
            return Ok(content);
        }
    }
    Err(AppError::NotFound("No valid path found".to_string()))
}

// 7. Error Context

/// Add context to errors
fn read_file_with_context(path: &str) -> Result<String, AppError> {
    std::fs::read_to_string(path)
        .map_err(|e| AppError::Io(e))
        .and_then(|content| {
            if content.is_empty() {
                Err(AppError::Parse(format!("File {} is empty", path)))
            } else {
                Ok(content)
            }
        })
}

// 8. Panic Handling

/// Function that may panic
fn risky_operation(value: i32) -> i32 {
    if value < 0 {
        panic!("Negative value not allowed: {}", value);
    }
    value * 2
}

/// Catch panic using std::panic
fn safe_risky_operation(value: i32) -> Result<i32, String> {
    std::panic::catch_unwind(|| risky_operation(value))
        .map_err(|_| "Panic occurred".to_string())
}

// 9. Combining Results

/// Combine multiple Results
fn combine_results(results: Vec<Result<i32, String>>) -> Result<Vec<i32>, String> {
    results.into_iter().collect()
}

/// Collect first error or all successes
fn collect_first_error<T, E>(results: Vec<Result<T, E>>) -> Result<Vec<T>, E> {
    results.into_iter().collect()
}

// 10. Conditional Error Handling

/// Handle error based on type
fn handle_io_error(result: Result<String, io::Error>) -> String {
    match result {
        Ok(content) => content,
        Err(e) if e.kind() == io::ErrorKind::NotFound => "File not found".to_string(),
        Err(e) if e.kind() == io::ErrorKind::PermissionDenied => "Permission denied".to_string(),
        Err(e) => format!("IO error: {}", e),
    }
}

// Usage Examples
fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Web Rust Exception Catching Examples ===\n");

    // 1. Basic Result handling
    println!("--- 1. Basic Result ---");
    match divide(10.0, 2.0) {
        Ok(result) => println!("10 / 2 = {}", result),
        Err(e) => println!("Error: {}", e),
    }
    match divide(10.0, 0.0) {
        Ok(result) => println!("10 / 0 = {}", result),
        Err(e) => println!("Error: {}", e),
    }

    // 2. Option handling
    println!("
--- 2. Option ---");
    println!("10 / 2 = {:?}", safe_divide(10.0, 2.0));
    println!("10 / 0 = {:?}", safe_divide(10.0, 0.0));

    let vec = vec![1, 2, 3];
    println!("Element at index 1: {:?}", get_element(&vec, 1));
    println!("Element at index 10: {:?}", get_element(&vec, 10));

    // 3. Custom errors
    println!("
--- 3. Custom Errors ---");
    match validate_username("") {
        Ok(_) => println!("Username valid"),
        Err(e) => println!("Validation error: {}", e),
    }
    match validate_username("ab") {
        Ok(_) => println!("Username valid"),
        Err(e) => println!("Validation error: {}", e),
    }
    match validate_username("valid_user") {
        Ok(_) => println!("Username valid"),
        Err(e) => println!("Validation error: {}", e),
    }

    // 4. Error propagation
    println!("
--- 4. Error Propagation ---");
    match load_config("nonexistent.txt") {
        Ok(_) => println!("Config loaded"),
        Err(e) => println!("Load error: {}", e),
    }

    // 5. Multiple error types
    println!("
--- 5. Multiple Error Types ---");
    match complex_operation("test.txt") {
        Ok(content) => println!("Content length: {}", content.len()),
        Err(e) => println!("Error: {}", e),
    }

    // 6. Fallback
    println!("
--- 6. Fallback ---");
    let result = read_with_fallback("missing.txt", "default content");
    println!("With fallback: {}", result);

    // 7. Try alternatives
    println!("
--- 7. Try Alternatives ---");
    let paths = ["file1.txt", "file2.txt", "file3.txt"];
    match try_alternatives(&paths) {
        Ok(_) => println!("Found a valid file"),
        Err(e) => println!("All alternatives failed: {}", e),
    }

    // 8. Combine results
    println!("
--- 8. Combine Results ---");
    let results = vec![
        Ok(1),
        Ok(2),
        Err("Error 3".to_string()),
        Ok(4),
    ];
    match combine_results(results) {
        Ok(values) => println!("All results: {:?}", values),
        Err(e) => println!("Failed with: {}", e),
    }

    // 9. Panic handling
    println!("
--- 9. Panic Handling ---");
    match safe_risky_operation(10) {
        Ok(result) => println!("Result: {}", result),
        Err(e) => println!("Panic caught: {}", e),
    }
    match safe_risky_operation(-5) {
        Ok(result) => println!("Result: {}", result),
        Err(e) => println!("Panic caught: {}", e),
    }

    // 10. Conditional error handling
    println!("
--- 10. Conditional Error Handling ---");
    let io_result: Result<String, io::Error> = Err(io::Error::new(io::ErrorKind::NotFound, "Not found"));
    println!("IO error: {}", handle_io_error(io_result));

    println!("
=== All Exception Catching Examples Completed ===");
    Ok(())
}