aboutsummaryrefslogtreecommitdiff
path: root/vendor/miette-derive/src/forward.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/miette-derive/src/forward.rs')
-rw-r--r--vendor/miette-derive/src/forward.rs161
1 files changed, 161 insertions, 0 deletions
diff --git a/vendor/miette-derive/src/forward.rs b/vendor/miette-derive/src/forward.rs
new file mode 100644
index 0000000..171019a
--- /dev/null
+++ b/vendor/miette-derive/src/forward.rs
@@ -0,0 +1,161 @@
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+use syn::{
+ parenthesized,
+ parse::{Parse, ParseStream},
+ spanned::Spanned,
+};
+
+pub enum Forward {
+ Unnamed(usize),
+ Named(syn::Ident),
+}
+
+impl Parse for Forward {
+ fn parse(input: ParseStream) -> syn::Result<Self> {
+ let forward = input.parse::<syn::Ident>()?;
+ if forward != "forward" {
+ return Err(syn::Error::new(forward.span(), "msg"));
+ }
+ let content;
+ parenthesized!(content in input);
+ let looky = content.lookahead1();
+ if looky.peek(syn::LitInt) {
+ let int: syn::LitInt = content.parse()?;
+ let index = int.base10_parse()?;
+ return Ok(Forward::Unnamed(index));
+ }
+ Ok(Forward::Named(content.parse()?))
+ }
+}
+
+#[derive(Copy, Clone)]
+pub enum WhichFn {
+ Code,
+ Help,
+ Url,
+ Severity,
+ Labels,
+ SourceCode,
+ Related,
+ DiagnosticSource,
+}
+
+impl WhichFn {
+ pub fn method_call(&self) -> TokenStream {
+ match self {
+ Self::Code => quote! { code() },
+ Self::Help => quote! { help() },
+ Self::Url => quote! { url() },
+ Self::Severity => quote! { severity() },
+ Self::Labels => quote! { labels() },
+ Self::SourceCode => quote! { source_code() },
+ Self::Related => quote! { related() },
+ Self::DiagnosticSource => quote! { diagnostic_source() },
+ }
+ }
+
+ pub fn signature(&self) -> TokenStream {
+ match self {
+ Self::Code => quote! {
+ fn code(& self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>>
+ },
+ Self::Help => quote! {
+ fn help(& self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>>
+ },
+ Self::Url => quote! {
+ fn url(& self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>>
+ },
+ Self::Severity => quote! {
+ fn severity(&self) -> std::option::Option<miette::Severity>
+ },
+ Self::Related => quote! {
+ fn related(&self) -> std::option::Option<std::boxed::Box<dyn std::iter::Iterator<Item = &dyn miette::Diagnostic> + '_>>
+ },
+ Self::Labels => quote! {
+ fn labels(&self) -> std::option::Option<std::boxed::Box<dyn std::iter::Iterator<Item = miette::LabeledSpan> + '_>>
+ },
+ Self::SourceCode => quote! {
+ fn source_code(&self) -> std::option::Option<&dyn miette::SourceCode>
+ },
+ Self::DiagnosticSource => quote! {
+ fn diagnostic_source(&self) -> std::option::Option<&dyn miette::Diagnostic>
+ },
+ }
+ }
+
+ pub fn catchall_arm(&self) -> TokenStream {
+ quote! { _ => std::option::Option::None }
+ }
+}
+
+impl Forward {
+ pub fn for_transparent_field(fields: &syn::Fields) -> syn::Result<Self> {
+ let make_err = || {
+ syn::Error::new(
+ fields.span(),
+ "you can only use #[diagnostic(transparent)] with exactly one field",
+ )
+ };
+ match fields {
+ syn::Fields::Named(named) => {
+ let mut iter = named.named.iter();
+ let field = iter.next().ok_or_else(make_err)?;
+ if iter.next().is_some() {
+ return Err(make_err());
+ }
+ let field_name = field
+ .ident
+ .clone()
+ .unwrap_or_else(|| format_ident!("unnamed"));
+ Ok(Self::Named(field_name))
+ }
+ syn::Fields::Unnamed(unnamed) => {
+ if unnamed.unnamed.iter().len() != 1 {
+ return Err(make_err());
+ }
+ Ok(Self::Unnamed(0))
+ }
+ _ => Err(syn::Error::new(
+ fields.span(),
+ "you cannot use #[diagnostic(transparent)] with a unit struct or a unit variant",
+ )),
+ }
+ }
+
+ pub fn gen_struct_method(&self, which_fn: WhichFn) -> TokenStream {
+ let signature = which_fn.signature();
+ let method_call = which_fn.method_call();
+
+ let field_name = match self {
+ Forward::Named(field_name) => quote!(#field_name),
+ Forward::Unnamed(index) => {
+ let index = syn::Index::from(*index);
+ quote!(#index)
+ }
+ };
+
+ quote! {
+ #[inline]
+ #signature {
+ self.#field_name.#method_call
+ }
+ }
+ }
+
+ pub fn gen_enum_match_arm(&self, variant: &syn::Ident, which_fn: WhichFn) -> TokenStream {
+ let method_call = which_fn.method_call();
+ match self {
+ Forward::Named(field_name) => quote! {
+ Self::#variant { #field_name, .. } => #field_name.#method_call,
+ },
+ Forward::Unnamed(index) => {
+ let underscores: Vec<_> = core::iter::repeat(quote! { _, }).take(*index).collect();
+ let unnamed = format_ident!("unnamed");
+ quote! {
+ Self::#variant ( #(#underscores)* #unnamed, .. ) => #unnamed.#method_call,
+ }
+ }
+ }
+ }
+}