nok

Crates.ionok
lib.rsnok
version0.0.1
created_at2025-12-06 16:53:51.502504+00
updated_at2025-12-06 16:53:51.502504+00
descriptionConcrete Error type built around a pseudo stack trace
homepage
repositoryhttps://github.com/seavaux/nok
max_upload_size
id1970419
size46,574
(seavaux)

documentation

README

N(ot) Ok

Lightweight error source determination using pseudo stack traces.

The primary component is the Origin instance, which is determined at compile time and always present.

pub struct Origin {
    pub file: &'static str,
    pub line: u32,
    pub column: u32,
}

The complete error type

... optionally includes:

  • a string message
  • an instance of a user defined data type (i.e. Payload)
  • an actual backtrace (i.e. std::backtrace::Backtrace::force_capture().to_string())
pub struct Error<Payload> {
    pub origin: Origin,
    pub message: Option<String>,
    pub payload: Option<Payload>,
    pub precursor: Option<Box<Error<Payload>>>,
    pub backtrace: Option<String>,
}

Utilizing the optional precursor a single linked is formed, representing the pseudo stack trace.

pub struct ErrorStack<Payload> {
    pub head: Box<Error<Payload>>,
}

The ErrorStack<Payload> type forms the E part in Result<T, E>.

type Res<T> = Result<T, ErrorStack<Payload>>;

Premise of this crate

  • in early development the origin of an error alone is usually sufficient
    • with optional additional context in the form of a string
  • knowing the entire call stack is almost never required
    • rather knowing specific ancestors in the call stack at certain crossroads is relevant
      • and even then rarely needed, therefore manually triggering the determination of said ancestors is acceptable
  • arbitrary diagnostic data is required in some cases
  • later on and especially when returning an error in a public api, standardized error code enums with a separately stored textual explanation become the predominant pattern
  • std::backtrace::Backtrace is expensive and in certain environments like WASM not helpful

Example Usage

use nok::{ErrorStack, rethrow_err};

type Payload = u32;

// to add `#[macro_export]` to each macro use `generate_macros!(payload_type: Payload, export_globally: true)`
nok::generate_macros!(payload_type: Payload);

type Res<T> = Result<T, ErrorStack<Payload>>;

fn lookup_even_number(key: &str, lut: &std::collections::HashMap<i32, u32>) -> Res<u32> {
    let num = rethrow_err!(lookup_bounded_number(key, lut))?;
    if num % 2 == 0 {
        Ok(num)
    } else {
        err!("number was not even")
    }
}

fn lookup_bounded_number(key: &str, lut: &std::collections::HashMap<i32, u32>) -> Res<u32> {
    let key: i32 = map_err!(key.parse())?;
    verify!(0 <= key && key <= 100, "key has to be in the range [0; 100] but was {key}")?;
    let val = ok_or!(lut.get(&key), "there is no entry for the key {key}")?;
    Ok(*val)
}

Related Projects

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Commit count: 0

cargo fmt