Skip to content

REQUEST: Add method to iterate entire context chain, not just errors #434

@stevenroose

Description

@stevenroose

Currently, anyhow::Error::chain exposes a chain over all Error types in the context chain. Additionally, anyhow::Error::downcast[_ref] gives access to a single non-Error context in the chain. There is however no way to access all non-Error contexts in the chain.

Imagine if one wants to tag errors with a Tag enum type. And then later one wants to extract all the tags places on the context. That's currently impossible:

use anyhow::{bail, Context};

#[derive(Debug)]
pub enum Tag {
	One,
	Two,
}

impl std::fmt::Display for Tag {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
	    std::fmt::Debug::fmt(self, f)
	}
}

fn bails() -> anyhow::Result<()> {
	bail!("bad!");
}

fn add_one_tag() -> anyhow::Result<()> {
	bails().context(Tag::One)?;
	Ok(())
}

fn add_two_tag() -> anyhow::Result<()> {
	add_one_tag().context(Tag::Two)?;
	Ok(())
}

fn main() {
	match add_two_tag() {
		Ok(()) => {}, // all good
		Err(e) => {
			// some error, let's get the tags...
			if let Some(tag) = e.downcast_ref::<Tag>() {
				println!("found tag through downcast: {}", tag);
			}

			for _item in e.chain() {
				// can't do this because Tag doesn't implement Error
				// if let Some(tag) = item.downcast_ref::<Tag>() {
				// 	println!("found tag through chain: {}", tag);
				// }
			}
		}
	}
}

I would like to propose either

  • a anyhow::Error::context_chain(&self) -> ContextChain that allows iterating through the entire chain as a dyn Any chain
  • a anyhow::Error::downcast_chain<T>(&self) -> DowncastChain<T> that iterates over all the contexts that succesfully downcast to type T.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions