scoped-error 0.1.3

Structured error handling with semantic context trees. Zero proc-macros. Zero backtrace overhead.
Documentation
// Copyright (C) 2026 Kan-Ru Chen <kanru@kanru.info>
//
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

use std::error::Error;

use scoped_error::Many;
use scoped_error::impl_context_error;

impl_context_error!(ValidationError);

impl ValidationError {
    fn new(msg: &'static str) -> Self {
        Self {
            message: msg.into(),
            source: None,
            location: None,
        }
    }
}

struct UserInput {
    name: String,
    email: String,
    age: u32,
}

fn validate_user(input: &UserInput) -> Result<(), Many> {
    let mut errors = Vec::new();

    if input.name.is_empty() {
        errors.push(ValidationError::new("name is required"));
    }
    if input.email.is_empty() {
        errors.push(ValidationError::new("email is required"));
    }
    if input.age < 18 {
        errors.push(ValidationError::new("must be 18 or older"));
    }

    if errors.is_empty() {
        Ok(())
    } else {
        Err(Many::from_errors("user validation failed", errors))
    }
}

fn main() -> Result<(), Box<dyn Error>> {
    validate_user(&UserInput {
        name: "John".to_string(),
        email: "".to_string(),
        age: 14,
    })?;
    Ok(())
}