Skip to content

Commit

Permalink
feat(derive): Allow optional sources in derive (#301)
Browse files Browse the repository at this point in the history
Fixes: #217
  • Loading branch information
gavrilikhin-d authored Oct 21, 2023
1 parent ba31328 commit 88d00e0
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 3 deletions.
42 changes: 39 additions & 3 deletions miette-derive/src/source_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::{

pub struct SourceCode {
source_code: syn::Member,
is_option: bool,
}

impl SourceCode {
Expand All @@ -27,6 +28,19 @@ impl SourceCode {
for (i, field) in fields.iter().enumerate() {
for attr in &field.attrs {
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() {
syn::Member::Named(ident)
} else {
Expand All @@ -35,7 +49,10 @@ impl SourceCode {
span: field.span(),
})
};
return Ok(Some(SourceCode { source_code }));
return Ok(Some(SourceCode {
source_code,
is_option,
}));
}
}
}
Expand All @@ -45,11 +62,21 @@ impl SourceCode {
pub(crate) fn gen_struct(&self, fields: &syn::Fields) -> Option<TokenStream> {
let (display_pat, _display_members) = display_pat_members(fields);
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! {
#[allow(unused_variables)]
fn source_code(&self) -> std::option::Option<&dyn miette::SourceCode> {
let Self #display_pat = self;
Some(&self.#src)
#ret
}
})
}
Expand All @@ -68,10 +95,19 @@ impl SourceCode {
}
};
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 {
syn::Fields::Unit => None,
_ => Some(quote! {
Self::#variant_name #display_pat => std::option::Option::Some(#field),
Self::#variant_name #display_pat => #ret,
}),
}
})
Expand Down
42 changes: 42 additions & 0 deletions tests/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,3 +584,45 @@ fn test_unit_enum_display() {
"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());
}

0 comments on commit 88d00e0

Please sign in to comment.