Skip to content

Commit 88d00e0

Browse files
authoredOct 21, 2023
feat(derive): Allow optional sources in derive (#301)
Fixes: #217
1 parent ba31328 commit 88d00e0

File tree

2 files changed

+81
-3
lines changed

2 files changed

+81
-3
lines changed
 

‎miette-derive/src/source_code.rs

+39-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::{
1010

1111
pub struct SourceCode {
1212
source_code: syn::Member,
13+
is_option: bool,
1314
}
1415

1516
impl SourceCode {
@@ -27,6 +28,19 @@ impl SourceCode {
2728
for (i, field) in fields.iter().enumerate() {
2829
for attr in &field.attrs {
2930
if attr.path().is_ident("source_code") {
31+
let is_option = if let syn::Type::Path(syn::TypePath {
32+
path: syn::Path { segments, .. },
33+
..
34+
}) = &field.ty
35+
{
36+
segments
37+
.last()
38+
.map(|seg| seg.ident == "Option")
39+
.unwrap_or(false)
40+
} else {
41+
false
42+
};
43+
3044
let source_code = if let Some(ident) = field.ident.clone() {
3145
syn::Member::Named(ident)
3246
} else {
@@ -35,7 +49,10 @@ impl SourceCode {
3549
span: field.span(),
3650
})
3751
};
38-
return Ok(Some(SourceCode { source_code }));
52+
return Ok(Some(SourceCode {
53+
source_code,
54+
is_option,
55+
}));
3956
}
4057
}
4158
}
@@ -45,11 +62,21 @@ impl SourceCode {
4562
pub(crate) fn gen_struct(&self, fields: &syn::Fields) -> Option<TokenStream> {
4663
let (display_pat, _display_members) = display_pat_members(fields);
4764
let src = &self.source_code;
65+
let ret = if self.is_option {
66+
quote! {
67+
self.#src.as_ref().map(|s| s as _)
68+
}
69+
} else {
70+
quote! {
71+
Some(&self.#src)
72+
}
73+
};
74+
4875
Some(quote! {
4976
#[allow(unused_variables)]
5077
fn source_code(&self) -> std::option::Option<&dyn miette::SourceCode> {
5178
let Self #display_pat = self;
52-
Some(&self.#src)
79+
#ret
5380
}
5481
})
5582
}
@@ -68,10 +95,19 @@ impl SourceCode {
6895
}
6996
};
7097
let variant_name = ident.clone();
98+
let ret = if source_code.is_option {
99+
quote! {
100+
#field.as_ref().map(|s| s as _)
101+
}
102+
} else {
103+
quote! {
104+
std::option::Option::Some(#field)
105+
}
106+
};
71107
match &fields {
72108
syn::Fields::Unit => None,
73109
_ => Some(quote! {
74-
Self::#variant_name #display_pat => std::option::Option::Some(#field),
110+
Self::#variant_name #display_pat => #ret,
75111
}),
76112
}
77113
})

‎tests/derive.rs

+42
Original file line numberDiff line numberDiff line change
@@ -584,3 +584,45 @@ fn test_unit_enum_display() {
584584
"hello from unit help"
585585
);
586586
}
587+
588+
#[test]
589+
fn test_optional_source_code() {
590+
#[derive(Debug, Diagnostic, Error)]
591+
#[error("struct with optional source")]
592+
struct Struct {
593+
#[source_code]
594+
src: Option<String>,
595+
}
596+
assert!(Struct { src: None }.source_code().is_none());
597+
assert!(Struct {
598+
src: Some("".to_string())
599+
}
600+
.source_code()
601+
.is_some());
602+
603+
#[derive(Debug, Diagnostic, Error)]
604+
enum Enum {
605+
#[error("variant1 with optional source")]
606+
Variant1 {
607+
#[source_code]
608+
src: Option<String>,
609+
},
610+
#[error("variant2 with optional source")]
611+
Variant2 {
612+
#[source_code]
613+
src: Option<String>,
614+
},
615+
}
616+
assert!(Enum::Variant1 { src: None }.source_code().is_none());
617+
assert!(Enum::Variant1 {
618+
src: Some("".to_string())
619+
}
620+
.source_code()
621+
.is_some());
622+
assert!(Enum::Variant2 { src: None }.source_code().is_none());
623+
assert!(Enum::Variant2 {
624+
src: Some("".to_string())
625+
}
626+
.source_code()
627+
.is_some());
628+
}

0 commit comments

Comments
 (0)
Please sign in to comment.