scoped-error 0.1.5

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

use std::borrow::Cow;
use std::error::Error as StdError;
use std::panic::Location;

use crate::{Error, Frame, WithContext};

/// Provides the context method for Result.
pub trait Context<T, E> {
    /// Wrap the error value with additional context.
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Into<Cow<'static, str>>;
    /// Wrap the error value with additional context that is evaluated lazily only once an error does occur.
    fn with_context<C, F>(self, f: F) -> Result<T, Error>
    where
        C: Into<Cow<'static, str>>,
        F: FnOnce() -> C;
}

impl<T, E> Context<T, E> for Result<T, E>
where
    E: StdError + Send + Sync + 'static,
{
    #[track_caller]
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Into<Cow<'static, str>>,
    {
        let location = Location::caller();
        self.map_err(|e| {
            let source = e.into();
            let frame = Frame { source, location };
            Error::new(context).with_context(frame)
        })
    }

    #[track_caller]
    fn with_context<C, F>(self, f: F) -> Result<T, Error>
    where
        C: Into<Cow<'static, str>>,
        F: FnOnce() -> C,
    {
        let location = Location::caller();
        self.map_err(|e| {
            let source = e.into();
            let frame = Frame { source, location };
            Error::new(f()).with_context(frame)
        })
    }
}