summaryrefslogtreecommitdiff
path: root/vendor/miette-derive/src/utils.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/miette-derive/src/utils.rs')
-rw-r--r--vendor/miette-derive/src/utils.rs140
1 files changed, 140 insertions, 0 deletions
diff --git a/vendor/miette-derive/src/utils.rs b/vendor/miette-derive/src/utils.rs
new file mode 100644
index 0000000..b867849
--- /dev/null
+++ b/vendor/miette-derive/src/utils.rs
@@ -0,0 +1,140 @@
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote, ToTokens};
+use syn::{
+ parse::{Parse, ParseStream},
+ spanned::Spanned,
+};
+
+pub(crate) enum MemberOrString {
+ Member(syn::Member),
+ String(syn::LitStr),
+}
+
+impl ToTokens for MemberOrString {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ use MemberOrString::*;
+ match self {
+ Member(member) => member.to_tokens(tokens),
+ String(string) => string.to_tokens(tokens),
+ }
+ }
+}
+
+impl Parse for MemberOrString {
+ fn parse(input: ParseStream) -> syn::Result<Self> {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(syn::Ident) || lookahead.peek(syn::LitInt) {
+ Ok(MemberOrString::Member(input.parse()?))
+ } else if lookahead.peek(syn::LitStr) {
+ Ok(MemberOrString::String(input.parse()?))
+ } else {
+ Err(syn::Error::new(
+ input.span(),
+ "Expected a string or a field reference.",
+ ))
+ }
+ }
+}
+
+use crate::{
+ diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
+ forward::WhichFn,
+};
+
+pub(crate) fn gen_all_variants_with(
+ variants: &[DiagnosticDef],
+ which_fn: WhichFn,
+ mut f: impl FnMut(&syn::Ident, &syn::Fields, &DiagnosticConcreteArgs) -> Option<TokenStream>,
+) -> Option<TokenStream> {
+ let pairs = variants
+ .iter()
+ .filter_map(|def| {
+ def.args
+ .forward_or_override_enum(&def.ident, which_fn, |concrete| {
+ f(&def.ident, &def.fields, concrete)
+ })
+ })
+ .collect::<Vec<_>>();
+ if pairs.is_empty() {
+ return None;
+ }
+ let signature = which_fn.signature();
+ let catchall = which_fn.catchall_arm();
+ Some(quote! {
+ #signature {
+ #[allow(unused_variables, deprecated)]
+ match self {
+ #(#pairs)*
+ #catchall
+ }
+ }
+ })
+}
+
+use crate::fmt::Display;
+use std::collections::HashSet;
+
+pub(crate) fn gen_unused_pat(fields: &syn::Fields) -> TokenStream {
+ match fields {
+ syn::Fields::Named(_) => quote! { { .. } },
+ syn::Fields::Unnamed(_) => quote! { ( .. ) },
+ syn::Fields::Unit => quote! {},
+ }
+}
+
+/// Goes in the slot `let Self #pat = self;` or `match self { Self #pat => ...
+/// }`.
+fn gen_fields_pat(fields: &syn::Fields) -> TokenStream {
+ let member_idents = fields.iter().enumerate().map(|(i, field)| {
+ field
+ .ident
+ .as_ref()
+ .cloned()
+ .unwrap_or_else(|| format_ident!("_{}", i))
+ });
+ match fields {
+ syn::Fields::Named(_) => quote! {
+ { #(#member_idents),* }
+ },
+ syn::Fields::Unnamed(_) => quote! {
+ ( #(#member_idents),* )
+ },
+ syn::Fields::Unit => quote! {},
+ }
+}
+
+/// The returned tokens go in the slot `let Self #pat = self;` or `match self {
+/// Self #pat => ... }`. The members can be passed to
+/// `Display::expand_shorthand[_cloned]`.
+pub(crate) fn display_pat_members(fields: &syn::Fields) -> (TokenStream, HashSet<syn::Member>) {
+ let pat = gen_fields_pat(fields);
+ let members: HashSet<syn::Member> = fields
+ .iter()
+ .enumerate()
+ .map(|(i, field)| {
+ if let Some(ident) = field.ident.as_ref().cloned() {
+ syn::Member::Named(ident)
+ } else {
+ syn::Member::Unnamed(syn::Index {
+ index: i as u32,
+ span: field.span(),
+ })
+ }
+ })
+ .collect();
+ (pat, members)
+}
+
+impl Display {
+ /// Returns `(fmt, args)` which must be passed to some kind of format macro
+ /// without tokens in between, i.e. `format!(#fmt #args)`.
+ pub(crate) fn expand_shorthand_cloned(
+ &self,
+ members: &HashSet<syn::Member>,
+ ) -> (syn::LitStr, TokenStream) {
+ let mut display = self.clone();
+ display.expand_shorthand(members);
+ let Display { fmt, args, .. } = display;
+ (fmt, args)
+ }
+}