I have a personal annoyance with how the likes of unwrap() work in Rust.
Specifically that they do not report the line of the code where the issue happened but instead display where panic! was called, and that is inside the Option or Result source code.
I decided to make it panic inside the code through something like map_err(Result only) or unwrap_or_else:
Is there a way to merge these without introducing much runtime overhead?
Doing "trickery" through implementing Into / From(and than using these appropriately) feels like an unclean solution here.
Macros don't have access to type information, so no - you can't distinguish between an option and result in a macro.
However, there is already the expect method on both types, which takes a string as input and prints that on panic. For Results, it also prints the error type. You can do this, at it will Just Work:
Even though it does not propagate the error from Result, it would be an option.
At moment at least, seems like there is no silver bullet and something has to be sacrificed.
Here's an idea that uses a trait to turn Option into Result before checking it: Rust Playground
It's inspired by the ideas for how try! could be made generic over result carriers. The error type of the new Result is an Option that is used to check if a canned error message should be written or not.
thread '<main>' panicked at 'called `Option::unwrap()` on a `None` value', ../src/libcore/option.rs:330
note: Run with `RUST_BACKTRACE=1` for a backtrace.
Which, yes, shows the panic inside of the Option library. However, if you run it with RUST_BACKTRACE=1, as that message suggests, then it will display the line number:
$ cat src/main.rs
fn main() {
let x: Option<i32> = None;
x.unwrap();
}
$ cargo run
Running `target/debug/unwrap`
thread '<main>' panicked at 'called `Option::unwrap()` on a `None` value', ../src/libcore/option.rs:330
note: Run with `RUST_BACKTRACE=1` for a backtrace.
Process didn't exit successfully: `target/debug/unwrap` (exit code: 101)
$ RUST_BACKTRACE=1 cargo run
Running `target/debug/unwrap`
thread '<main>' panicked at 'called `Option::unwrap()` on a `None` value', ../src/libcore/option.rs:330
stack backtrace:
1: 0x5562fbb2cd80 - sys::backtrace::tracing::imp::write::h3675b4f0ca767761Xcv
2: 0x5562fbb2ee5b - panicking::default_handler::_$u7b$$u7b$closure$u7d$$u7d$::closure.44519
3: 0x5562fbb2eac8 - panicking::default_handler::h18faf4fbd296d909lSz
4: 0x5562fbb2943c - sys_common::unwind::begin_unwind_inner::hfb5d07d6e405c6bbg1t
5: 0x5562fbb29658 - sys_common::unwind::begin_unwind_fmt::h8b491a76ae84af35m0t
6: 0x5562fbb2c331 - rust_begin_unwind
7: 0x5562fbb5d17f - panicking::panic_fmt::h98b8cbb286f5298alcM
8: 0x5562fbb5d458 - panicking::panic::h4265c0105caa1121SaM
9: 0x5562fbb28a51 - option::Option<T>::unwrap::h5201650903339503995
at ../src/libcore/macros.rs:21
10: 0x5562fbb289fb - main::h3529877efd0d4ad4eaa
at src/main.rs:3 <------------------------- line number reported here
11: 0x5562fbb2e724 - sys_common::unwind::try::try_fn::h14622312129452522850
12: 0x5562fbb2c2bb - __rust_try
13: 0x5562fbb2e1bb - rt::lang_start::h0ba42f7a8c46a626rKz
14: 0x5562fbb28aa9 - main
15: 0x7f9e4fa12740 - __libc_start_main
16: 0x5562fbb288d8 - _start
17: 0x0 - <unknown>
Process didn't exit successfully: `target/debug/unwrap` (exit code: 101)
If you want to take your From/Into approach, you can still do it without polluting the From/Into traits:
(EDIT: I think ogeon did something like this already. I didn't read the replies very carefully.)
I like @ogeon's solution that it compiles to more efficient code in the end, although of course it doesn't matter when right before that the application will panick(this is not run in a hot code path many times, it is called only once)
Why I didn't want to use the From/Into solution is because of this question:
Now, I ask, why wouldn't such a macro be added to the std?
Or do you think the benefits(that using this will show the line with the problem without running through the backtrace - probably useful only for small codebases and beginners) are not worth polluting the std?