dtolnay/anyhow

Is there a nice way to track line number?

Closed this issue · 4 comments

Something like

.context(concat!(file!(), ":", line!()))

but a bit more concise

You could make a macro that captures both in one call:

use anyhow::{bail, Context, Result};

macro_rules! here {
    () => {
        concat!("at ", file!(), " line ", line!(), " column ", column!())
    };
}

fn f() -> Result<()> {
    bail!("oh no!");
}

fn main() -> Result<()> {
    f().context(here!())?;
    Ok(())
}
Error: at src/main.rs line 14 column 17

Caused by:
    oh no!

Or get a little fancier with an extension trait:

use anyhow::{bail, Context, Result};
use std::fmt::Display;

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

pub trait ErrorLocation<T, E> {
    fn location(self, loc: &'static Location) -> Result<T>;
}

impl<T, E> ErrorLocation<T, E> for Result<T, E>
where
    E: Display,
    Result<T, E>: Context<T, E>,
{
    fn location(self, loc: &'static Location) -> Result<T> {
        let msg = self.as_ref().err().map(ToString::to_string);
        self.with_context(|| format!(
            "{} at {} line {} column {}",
            msg.unwrap(), loc.file, loc.line, loc.column,
        ))
    }
}

macro_rules! here {
    () => {
        &Location {
            file: file!(),
            line: line!(),
            column: column!(),
        }
    };
}

fn f() -> Result<()> {
    bail!("oh no!");
}

fn main() -> Result<()> {
    f().location(here!())?;
    Ok(())
}

No way to go without a macro, I guess? Well, even like this, it's almost perfect :) Do you plan adding such macro to a crate itself?

est31 commented

std errors will contain backtraces in the future: rust-lang/rust#53487

I'll stick with macro then, until the backtrace in std is usable. Thanks @dtolnay @est31 !