mirror of https://github.com/zkat/miette.git
feat(help): allow non-option values in #[help] fields
This commit is contained in:
parent
23ee3642d1
commit
ea55f458fa
|
|
@ -18,7 +18,7 @@ use crate::{
|
||||||
|
|
||||||
pub enum Help {
|
pub enum Help {
|
||||||
Display(Display),
|
Display(Display),
|
||||||
Field(syn::Member),
|
Field(syn::Member, Box<syn::Type>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Help {
|
impl Parse for Help {
|
||||||
|
|
@ -78,7 +78,7 @@ impl Help {
|
||||||
span: field.span(),
|
span: field.span(),
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
return Ok(Some(Help::Field(help)));
|
return Ok(Some(Help::Field(help, Box::new(field.ty.clone()))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -97,15 +97,19 @@ impl Help {
|
||||||
Self::#ident #display_pat => std::option::Option::Some(std::boxed::Box::new(format!(#fmt #args))),
|
Self::#ident #display_pat => std::option::Option::Some(std::boxed::Box::new(format!(#fmt #args))),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Help::Field(member) => {
|
Help::Field(member, ty) => {
|
||||||
let help = match &member {
|
let help = match &member {
|
||||||
syn::Member::Named(ident) => ident.clone(),
|
syn::Member::Named(ident) => ident.clone(),
|
||||||
syn::Member::Unnamed(syn::Index { index, .. }) => {
|
syn::Member::Unnamed(syn::Index { index, .. }) => {
|
||||||
format_ident!("_{}", index)
|
format_ident!("_{}", index)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let var = quote! { __miette_internal_var };
|
||||||
Some(quote! {
|
Some(quote! {
|
||||||
Self::#ident #display_pat => #help.as_ref().map(|h| -> std::boxed::Box<dyn std::fmt::Display + 'a> { std::boxed::Box::new(format!("{}", h)) }),
|
Self::#ident #display_pat => {
|
||||||
|
use miette::macro_helpers::ToOption;
|
||||||
|
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(&#help).as_ref().map(|#var| -> std::boxed::Box<dyn std::fmt::Display + 'a> { std::boxed::Box::new(format!("{}", #var)) })
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -126,13 +130,17 @@ impl Help {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Help::Field(member) => Some(quote! {
|
Help::Field(member, ty) => {
|
||||||
fn help<'a>(&'a self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + 'a>> {
|
let var = quote! { __miette_internal_var };
|
||||||
#[allow(unused_variables, deprecated)]
|
Some(quote! {
|
||||||
let Self #display_pat = self;
|
fn help<'a>(&'a self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + 'a>> {
|
||||||
self.#member.as_ref().map(|h| -> std::boxed::Box<dyn std::fmt::Display + 'a> { std::boxed::Box::new(format!("{}", h)) })
|
#[allow(unused_variables, deprecated)]
|
||||||
}
|
let Self #display_pat = self;
|
||||||
}),
|
use miette::macro_helpers::ToOption;
|
||||||
|
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(&self.#member).as_ref().map(|#var| -> std::boxed::Box<dyn std::fmt::Display + 'a> { std::boxed::Box::new(format!("{}", #var)) })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -589,6 +589,8 @@ mod eyreish;
|
||||||
#[cfg(feature = "fancy-no-backtrace")]
|
#[cfg(feature = "fancy-no-backtrace")]
|
||||||
mod handler;
|
mod handler;
|
||||||
mod handlers;
|
mod handlers;
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub mod macro_helpers;
|
||||||
mod named_source;
|
mod named_source;
|
||||||
#[cfg(feature = "fancy")]
|
#[cfg(feature = "fancy")]
|
||||||
mod panic;
|
mod panic;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub trait IsOption {}
|
||||||
|
impl <T> IsOption for Option<T> {}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct OptionalWrapper<T>(pub core::marker::PhantomData<T>);
|
||||||
|
|
||||||
|
impl<T> OptionalWrapper<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(core::marker::PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub trait ToOption {
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn to_option<T>(self, value: T) -> Option<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> OptionalWrapper<T> where T: IsOption {
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn to_option(self, value: &T) -> &T {
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ToOption for &OptionalWrapper<T> {
|
||||||
|
fn to_option<U>(self, value: U) -> Option<U> {
|
||||||
|
Some(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -292,6 +292,16 @@ fn help_field() {
|
||||||
"x".to_string(),
|
"x".to_string(),
|
||||||
Baz(Some("x".into())).help().unwrap().to_string()
|
Baz(Some("x".into())).help().unwrap().to_string()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
#[error("welp")]
|
||||||
|
#[diagnostic()]
|
||||||
|
struct Quux(#[help] String);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
"x".to_string(),
|
||||||
|
Quux("x".into()).help().unwrap().to_string()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue