mirror of https://github.com/zkat/miette.git
Allow optional sources in derive
This commit is contained in:
parent
ba313282a8
commit
0d68f798a5
|
|
@ -10,6 +10,7 @@ use crate::{
|
||||||
|
|
||||||
pub struct SourceCode {
|
pub struct SourceCode {
|
||||||
source_code: syn::Member,
|
source_code: syn::Member,
|
||||||
|
is_option: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SourceCode {
|
impl SourceCode {
|
||||||
|
|
@ -27,6 +28,19 @@ impl SourceCode {
|
||||||
for (i, field) in fields.iter().enumerate() {
|
for (i, field) in fields.iter().enumerate() {
|
||||||
for attr in &field.attrs {
|
for attr in &field.attrs {
|
||||||
if attr.path().is_ident("source_code") {
|
if attr.path().is_ident("source_code") {
|
||||||
|
let is_option = if let syn::Type::Path(syn::TypePath {
|
||||||
|
path: syn::Path { segments, .. },
|
||||||
|
..
|
||||||
|
}) = &field.ty
|
||||||
|
{
|
||||||
|
segments
|
||||||
|
.last()
|
||||||
|
.map(|seg| seg.ident == "Option")
|
||||||
|
.unwrap_or(false)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
let source_code = if let Some(ident) = field.ident.clone() {
|
let source_code = if let Some(ident) = field.ident.clone() {
|
||||||
syn::Member::Named(ident)
|
syn::Member::Named(ident)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -35,7 +49,10 @@ impl SourceCode {
|
||||||
span: field.span(),
|
span: field.span(),
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
return Ok(Some(SourceCode { source_code }));
|
return Ok(Some(SourceCode {
|
||||||
|
source_code,
|
||||||
|
is_option,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -45,11 +62,21 @@ impl SourceCode {
|
||||||
pub(crate) fn gen_struct(&self, fields: &syn::Fields) -> Option<TokenStream> {
|
pub(crate) fn gen_struct(&self, fields: &syn::Fields) -> Option<TokenStream> {
|
||||||
let (display_pat, _display_members) = display_pat_members(fields);
|
let (display_pat, _display_members) = display_pat_members(fields);
|
||||||
let src = &self.source_code;
|
let src = &self.source_code;
|
||||||
|
let ret = if self.is_option {
|
||||||
|
quote! {
|
||||||
|
self.#src.as_ref().map(|s| s as _)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
Some(&self.#src)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Some(quote! {
|
Some(quote! {
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn source_code(&self) -> std::option::Option<&dyn miette::SourceCode> {
|
fn source_code(&self) -> std::option::Option<&dyn miette::SourceCode> {
|
||||||
let Self #display_pat = self;
|
let Self #display_pat = self;
|
||||||
Some(&self.#src)
|
#ret
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -68,10 +95,19 @@ impl SourceCode {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let variant_name = ident.clone();
|
let variant_name = ident.clone();
|
||||||
|
let ret = if source_code.is_option {
|
||||||
|
quote! {
|
||||||
|
#field.as_ref().map(|s| s as _)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
std::option::Option::Some(#field)
|
||||||
|
}
|
||||||
|
};
|
||||||
match &fields {
|
match &fields {
|
||||||
syn::Fields::Unit => None,
|
syn::Fields::Unit => None,
|
||||||
_ => Some(quote! {
|
_ => Some(quote! {
|
||||||
Self::#variant_name #display_pat => std::option::Option::Some(#field),
|
Self::#variant_name #display_pat => #ret,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -584,3 +584,45 @@ fn test_unit_enum_display() {
|
||||||
"hello from unit help"
|
"hello from unit help"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_optional_source_code() {
|
||||||
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
#[error("struct with optional source")]
|
||||||
|
struct Struct {
|
||||||
|
#[source_code]
|
||||||
|
src: Option<String>,
|
||||||
|
}
|
||||||
|
assert!(Struct { src: None }.source_code().is_none());
|
||||||
|
assert!(Struct {
|
||||||
|
src: Some("".to_string())
|
||||||
|
}
|
||||||
|
.source_code()
|
||||||
|
.is_some());
|
||||||
|
|
||||||
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
enum Enum {
|
||||||
|
#[error("variant1 with optional source")]
|
||||||
|
Variant1 {
|
||||||
|
#[source_code]
|
||||||
|
src: Option<String>,
|
||||||
|
},
|
||||||
|
#[error("variant2 with optional source")]
|
||||||
|
Variant2 {
|
||||||
|
#[source_code]
|
||||||
|
src: Option<String>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert!(Enum::Variant1 { src: None }.source_code().is_none());
|
||||||
|
assert!(Enum::Variant1 {
|
||||||
|
src: Some("".to_string())
|
||||||
|
}
|
||||||
|
.source_code()
|
||||||
|
.is_some());
|
||||||
|
assert!(Enum::Variant2 { src: None }.source_code().is_none());
|
||||||
|
assert!(Enum::Variant2 {
|
||||||
|
src: Some("".to_string())
|
||||||
|
}
|
||||||
|
.source_code()
|
||||||
|
.is_some());
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue