Implement interpolation

This commit is contained in:
Gavrilikhin Daniil 2023-05-07 10:21:49 +08:00
parent b65872011c
commit cb5a1d35e0
1 changed files with 55 additions and 40 deletions

View File

@ -16,7 +16,7 @@
/// # let resource = 0; /// # let resource = 0;
/// # /// #
/// if !has_permission(user, resource) { /// if !has_permission(user, resource) {
/// bail!("permission denied for accessing {}", resource); /// bail!("permission denied for accessing {resource}");
/// } /// }
/// # Ok(()) /// # Ok(())
/// # } /// # }
@ -54,24 +54,26 @@
/// ///
/// fn divide(x: f64, y: f64) -> Result<f64> { /// fn divide(x: f64, y: f64) -> Result<f64> {
/// if y.abs() < 1e-3 { /// if y.abs() < 1e-3 {
/// bail!("dividing by value close to 0", severity = Severity::Warning); /// bail!(
/// severity = Severity::Warning;
/// "dividing by value ({y}) close to 0"
/// );
/// } /// }
/// Ok(x / y) /// Ok(x / y)
/// } /// }
/// ``` /// ```
#[macro_export] #[macro_export]
macro_rules! bail { macro_rules! bail {
($msg:literal $(,)?) => {
return $crate::private::Err($crate::miette!($msg));
};
($err:expr $(,)?) => { ($err:expr $(,)?) => {
return $crate::private::Err($crate::miette!($err)); return $crate::private::Err($crate::miette!($err));
}; };
($fmt:expr $(, $key:ident = $value:expr)* $(,)?) => { ($($key:ident = $value:expr),+; $($fmt:tt)+) => {
return $crate::private::Err($crate::miette!($fmt, $($key = $value),*)); return $crate::private::Err(
$crate::miette!($($key = $value),+; $($fmt)+)
);
}; };
($fmt:expr, $($arg:tt)*) => { ($($fmt:tt)+) => {
return $crate::private::Err($crate::miette!($fmt, $($arg)*)); return $crate::private::Err($crate::miette!($($fmt)+));
}; };
} }
@ -126,8 +128,8 @@ macro_rules! bail {
/// fn divide(x: f64, y: f64) -> Result<f64> { /// fn divide(x: f64, y: f64) -> Result<f64> {
/// ensure!( /// ensure!(
/// y.abs() >= 1e-3, /// y.abs() >= 1e-3,
/// "dividing by value close to 0", /// severity = Severity::Warning;
/// severity = Severity::Warning /// "dividing by value ({y}) close to 0"
/// ); /// );
/// Ok(x / y) /// Ok(x / y)
/// } /// }
@ -144,9 +146,11 @@ macro_rules! ensure {
return $crate::private::Err($crate::miette!($err)); return $crate::private::Err($crate::miette!($err));
} }
}; };
($cond:expr, $fmt:expr $(, $key:ident = $value:expr)* $(,)?) => { ($cond:expr, $($key:ident = $value:expr),+; $($fmt:tt)+) => {
if !$cond { if !$cond {
return $crate::private::Err($crate::miette!($fmt, $($key = $value),*)); return $crate::private::Err(
$crate::miette!($($key = $value),+; $($fmt)+)
);
} }
}; };
($cond:expr, $fmt:expr, $($arg:tt)*) => { ($cond:expr, $fmt:expr, $($arg:tt)*) => {
@ -162,33 +166,32 @@ macro_rules! ensure {
/// ///
/// With string literal and interpolation: /// With string literal and interpolation:
/// ``` /// ```
/// # type V = (); /// # use miette::miette;
/// # /// let x = 1;
/// use miette::{miette, Result}; /// let y = 2;
/// let report = miette!("{x} + {} = {z}", y, z = x + y);
/// assert_eq!(report.to_string().as_str(), "1 + 2 = 3");
/// ///
/// fn lookup(key: &str) -> Result<V> { /// let report = miette!("{x} + {y} = {x + y}");
/// if key.len() != 16 { /// assert_eq!(report.to_string().as_str(), "1 + 2 = 3");
/// return Err(miette!("key length must be 16 characters, got {:?}", key));
/// }
///
/// // ...
/// # Ok(())
/// }
/// ``` /// ```
/// ///
/// With [`MietteDiagnostic`]-like arguments: /// With [`diagnostic!`]-like arguments:
/// ``` /// ```
/// use miette::{miette, LabeledSpan, Severity}; /// use miette::{miette, LabeledSpan, Severity};
/// ///
/// let source = "(2 + 2".to_string(); /// let source = "(2 + 2".to_string();
/// let report = miette!( /// let report = miette!(
/// "expected closing ')'",
/// // Those fields are optional /// // Those fields are optional
/// severity = Severity::Error, /// severity = Severity::Error,
/// code = "expected::rparen", /// code = "expected::rparen",
/// help = "always close your parens", /// help = "always close your parens",
/// labels = vec![LabeledSpan::at_offset(6, "here")], /// labels = vec![LabeledSpan::at_offset(6, "here")],
/// url = "https://example.com" /// url = "https://example.com"; // <- semicolon separates fields from message
///
/// // Rest of the arguments are passed to `format!`
/// // to form diagnostic message
/// "expected closing ')'"
/// ) /// )
/// .with_source_code(source); /// .with_source_code(source);
/// ``` /// ```
@ -198,21 +201,18 @@ macro_rules! ensure {
/// You can just replace `use`s of the `anyhow!`/`eyre!` macros with `miette!`. /// You can just replace `use`s of the `anyhow!`/`eyre!` macros with `miette!`.
#[macro_export] #[macro_export]
macro_rules! miette { macro_rules! miette {
($msg:literal $(,)?) => {
// Handle $:literal as a special case to make cargo-expanded code more
// concise in the common case.
$crate::private::new_adhoc($msg)
};
($err:expr $(,)?) => ({ ($err:expr $(,)?) => ({
use $crate::private::kind::*; use $crate::private::kind::*;
let error = $err; let error = $err;
(&error).miette_kind().new(error) (&error).miette_kind().new(error)
}); });
($fmt:expr $(, $key:ident = $value:expr)* $(,)?) => { ($($key:ident = $value:expr),+; $($fmt:tt)+) => {
$crate::Report::from($crate::diagnostic!($fmt, $($key = $value,)*)) $crate::Report::from(
$crate::diagnostic!($($key = $value),+; $($fmt)+)
)
}; };
($fmt:expr, $($arg:tt)*) => { ($($fmt:tt)+) => {
$crate::private::new_adhoc(format!($fmt, $($arg)*)) $crate::private::new_adhoc(format!($($fmt)+))
}; };
} }
@ -224,20 +224,35 @@ macro_rules! miette {
/// ///
/// let source = "(2 + 2".to_string(); /// let source = "(2 + 2".to_string();
/// let diag = diagnostic!( /// let diag = diagnostic!(
/// "expected closing ')'",
/// // Those fields are optional /// // Those fields are optional
/// severity = Severity::Error, /// severity = Severity::Error,
/// code = "expected::rparen", /// code = "expected::rparen",
/// help = "always close your parens", /// help = "always close your parens",
/// labels = vec![LabeledSpan::at_offset(6, "here")], /// labels = vec![LabeledSpan::at_offset(6, "here")],
/// url = "https://example.com" /// url = "https://example.com"; // <- semicolon separates fields from message
///
/// // Rest of the arguments are passed to `format!`
/// // to form diagnostic message
/// "expected closing ')'",
/// ); /// );
/// ``` /// ```
/// Diagnostic without any fields:
/// ```
/// # use miette::diagnostic;
/// let x = 1;
/// let y = 2;
///
/// let diag = diagnostic!("{x} + {} = {z}", y, z = x + y);
/// assert_eq!(diag.message, "1 + 2 = 3");
/// ```
#[macro_export] #[macro_export]
macro_rules! diagnostic { macro_rules! diagnostic {
($fmt:expr $(, $key:ident = $value:expr)* $(,)?) => {{ ($($key:ident = $value:expr),+; $($fmt:tt)+) => {{
let mut diag = $crate::MietteDiagnostic::new(format!("{}", $fmt)); let mut diag = $crate::MietteDiagnostic::new(format!($($fmt)+));
$(diag.$key = Some($value.into());)* $(diag.$key = Some($value.into());)*
diag diag
}}; }};
($($fmt:tt)+) => {{
$crate::MietteDiagnostic::new(format!($($fmt)+))
}};
} }