use tracing::error;
use tracing::event;
use tracing::level_filters::LevelFilter;
use tracing::Level;
use tracing_subscriber::fmt;
use tracing_subscriber::prelude::*;
use tracing_subscriber::EnvFilter;
pub fn tracing_configuration() {
tracing_subscriber::registry()
.with(fmt::layer().with_file(true).with_line_number(true))
.with(
EnvFilter::builder()
.with_default_directive(LevelFilter::INFO.into())
.from_env()
.unwrap_or(EnvFilter::from_default_env()),
)
.init();
event!(Level::INFO, "Program has started.");
}
fn main() {
tracing_configuration();
}
pub fn checked_u16_parse() -> Option<u16> {
// I prefer this:
let u_16 = "123".parse::<u16>().unwrap_or_else(|err| {
error!("Failed to parse. Extra info: `{err}`.");
return None;
});
// But I currently have to do this:
let u_16 = match "123".parse::<u16>() {
Ok(u_16) => u_16,
Err(err) => {
error!("Failed to parse. Extra info: `{err}`.");
return None;
}
};
Some(u_16)
}
This would simplify my code in many places, since this situation occurs frequently throughout the code when I want a program to never crash.
The general feature you're asking for is called "TCP-preserving closures" -- closures that can affect control flow in the containing function; TCP in this case stands for "Tennant's Correspondence Principle" -- and as I understand it, it's very unlikely to ever happen because it would have a lot of side effects on the rest of the language that nobody knows how to handle.
The specific case you are struggling with can be simplified by use of map_err and ok:
fn checked_u16_parse(s: &str) -> Option<u16> {
s.parse::<u16>().map_err(|err| {
eprintln!("Failed to parse. Extra info: `{err}`.");
}).ok()
}
The map_err converts any Err(...) value into Err(()) after reporting the error, and then ok() turns the Result into an Option, which can be returned directly.
If you want to do more processing after the parse, you can use ? on Option as well as Result: for example
fn checked_u16_parse(s: &str, min: u16, max: u16) -> Option<u16> {
let v = s.parse::<u16>().map_err(|err| {
eprintln!("Failed to parse. Extra info: `{err}`.");
}).ok()?;
if !(min..=max).contains(&v) {
eprintln!("Value {v} not within acceptable range [{min}, {max}]");
return None;
}
Some(v)
}