mirror of
https://github.com/Noratrieb/dilaria.git
synced 2026-01-16 02:15:01 +01:00
vendor dbg-pls
This commit is contained in:
parent
a633546c8f
commit
57ba4cef3c
23 changed files with 2240 additions and 419 deletions
17
dbg-pls/debug-derive/Cargo.toml
Normal file
17
dbg-pls/debug-derive/Cargo.toml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "dbg-pls-derive"
|
||||
version = "0.2.1"
|
||||
authors = ["Conrad Ludgate <conradludgate@gmail.com>"]
|
||||
edition = "2018"
|
||||
description = "derive(Debug)"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/conradludgate/dbg-pls"
|
||||
readme = "../README.md"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "1.0"
|
||||
syn = "1.0"
|
||||
proc-macro2 = "1.0"
|
||||
117
dbg-pls/debug-derive/src/debug.rs
Normal file
117
dbg-pls/debug-derive/src/debug.rs
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
use crate::pat::{named_idents, unnamed_idents, PatternImpl};
|
||||
use proc_macro2::{Ident, TokenStream as TokenStream2};
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::{spanned::Spanned, Data, DataEnum, DataStruct, DeriveInput, Fields, Path, Variant};
|
||||
|
||||
pub struct DebugImpl<T>(pub T);
|
||||
|
||||
impl ToTokens for DebugImpl<(Path, DeriveInput)> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||
let (path, input) = &self.0;
|
||||
|
||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
|
||||
let ident = &input.ident;
|
||||
let body = DebugImpl((ident, &input.data));
|
||||
|
||||
tokens.extend(quote! {
|
||||
impl #impl_generics #path::DebugPls for #ident #ty_generics #where_clause {
|
||||
fn fmt(&self, f: #path::Formatter<'_>) {
|
||||
#body
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToTokens for DebugImpl<(&'a Ident, &'a Data)> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||
let (name, data) = self.0;
|
||||
match data {
|
||||
Data::Struct(s) => DebugImpl((name, s)).to_tokens(tokens),
|
||||
Data::Enum(e) => DebugImpl((name, e)).to_tokens(tokens),
|
||||
Data::Union(_) => tokens
|
||||
.extend(syn::Error::new(self.span(), "unions not supported").into_compile_error()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToTokens for DebugImpl<(&'a Ident, &'a DataStruct)> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||
let (name, data) = self.0;
|
||||
let pat = PatternImpl(&data.fields);
|
||||
tokens.extend(quote! {
|
||||
let #name #pat = self;
|
||||
});
|
||||
DebugImpl((name, &data.fields)).to_tokens(tokens)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToTokens for DebugImpl<(&'a Ident, &'a DataEnum)> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||
let (name, data) = self.0;
|
||||
let variants = data.variants.iter().map(|v| DebugImpl((name, v)));
|
||||
tokens.extend(quote! {
|
||||
match self {
|
||||
#( #variants )*
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToTokens for DebugImpl<(&'a Ident, &'a Variant)> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||
let (name, variant) = self.0;
|
||||
let Variant {
|
||||
attrs: _,
|
||||
ident,
|
||||
fields,
|
||||
discriminant: _,
|
||||
} = &variant;
|
||||
let pattern = PatternImpl(fields);
|
||||
let debug = DebugImpl((ident, fields));
|
||||
|
||||
tokens.extend(quote! {
|
||||
#name::#ident #pattern => { #debug }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToTokens for DebugImpl<(&'a Ident, &'a Fields)> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||
let (name, fields) = self.0;
|
||||
let name = name.to_string();
|
||||
match fields {
|
||||
Fields::Named(named) => {
|
||||
tokens.extend(quote! {
|
||||
f.debug_struct(#name)
|
||||
});
|
||||
named_idents(named).for_each(|ident| {
|
||||
let name = ident.to_string();
|
||||
tokens.extend(quote! {
|
||||
.field(#name, #ident)
|
||||
})
|
||||
});
|
||||
tokens.extend(quote! {
|
||||
.finish()
|
||||
});
|
||||
}
|
||||
Fields::Unnamed(unnamed) => {
|
||||
tokens.extend(quote! {
|
||||
f.debug_tuple_struct(#name)
|
||||
});
|
||||
unnamed_idents(unnamed).for_each(|ident| {
|
||||
tokens.extend(quote! {
|
||||
.field(#ident)
|
||||
})
|
||||
});
|
||||
tokens.extend(quote! {
|
||||
.finish()
|
||||
});
|
||||
}
|
||||
Fields::Unit => tokens.extend(quote! {
|
||||
f.debug_ident(#name)
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
61
dbg-pls/debug-derive/src/lib.rs
Normal file
61
dbg-pls/debug-derive/src/lib.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
use debug::DebugImpl;
|
||||
use predicate::predicate;
|
||||
use proc_macro::TokenStream;
|
||||
use quote::ToTokens;
|
||||
use syn::{parse_macro_input, DeriveInput, parse_quote, Attribute, Path};
|
||||
|
||||
mod debug;
|
||||
mod pat;
|
||||
mod predicate;
|
||||
|
||||
/// Derives the standard `DebugPls` implementation.
|
||||
///
|
||||
/// Works exactly like [`Debug`]
|
||||
#[proc_macro_derive(DebugPls, attributes(dbg_pls))]
|
||||
pub fn derive(input: TokenStream) -> TokenStream {
|
||||
let mut input = parse_macro_input!(input as DeriveInput);
|
||||
|
||||
let path = match get_crate(&input.attrs) {
|
||||
Ok(path) => path,
|
||||
Err(err) => return err.into_compile_error().into_token_stream().into(),
|
||||
};
|
||||
|
||||
predicate(&mut input, path.clone());
|
||||
DebugImpl((path, input)).into_token_stream().into()
|
||||
}
|
||||
|
||||
fn get_crate(attrs: &[Attribute]) -> syn::Result<Path> {
|
||||
fn parse_crate(lit: syn::Lit) -> syn::Result<Path> {
|
||||
match lit {
|
||||
syn::Lit::Str(s) => syn::parse_str(&s.value()),
|
||||
_ => Err(syn::Error::new(lit.span(), "invalid crate name")),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_meta(meta: syn::Meta) -> Option<syn::Result<Path>> {
|
||||
if let syn::Meta::List(list) = meta {
|
||||
for meta in list.nested {
|
||||
if let syn::NestedMeta::Meta(syn::Meta::NameValue(nv)) = meta {
|
||||
if let Some(ident) = nv.path.get_ident() {
|
||||
if *ident == "crate" {
|
||||
return Some(parse_crate(nv.lit));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
for attr in attrs {
|
||||
if let Some(ident) = attr.path.get_ident() {
|
||||
if *ident == "dbg_pls" {
|
||||
if let Some(path) = parse_meta(Attribute::parse_meta(attr)?).transpose()? {
|
||||
return Ok(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(parse_quote! { ::dbg_pls })
|
||||
}
|
||||
46
dbg-pls/debug-derive/src/pat.rs
Normal file
46
dbg-pls/debug-derive/src/pat.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
use proc_macro2::{Delimiter, Group, Ident, TokenStream as TokenStream2, TokenTree};
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
use syn::{spanned::Spanned, Fields, FieldsNamed, FieldsUnnamed};
|
||||
|
||||
pub struct PatternImpl<T>(pub T);
|
||||
|
||||
impl<'a> ToTokens for PatternImpl<&'a Fields> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||
match &self.0 {
|
||||
Fields::Named(named) => PatternImpl(named).to_tokens(tokens),
|
||||
Fields::Unnamed(unnamed) => PatternImpl(unnamed).to_tokens(tokens),
|
||||
Fields::Unit => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToTokens for PatternImpl<&'a FieldsNamed> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||
let idents = named_idents(self.0);
|
||||
let inner = quote! { #(#idents),* };
|
||||
tokens.extend([TokenTree::Group(Group::new(Delimiter::Brace, inner))])
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToTokens for PatternImpl<&'a FieldsUnnamed> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||
let idents = unnamed_idents(self.0);
|
||||
let inner = quote! { #(#idents),* };
|
||||
tokens.extend([TokenTree::Group(Group::new(Delimiter::Parenthesis, inner))])
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unnamed_idents(fields: &FieldsUnnamed) -> impl Iterator<Item = Ident> + '_ {
|
||||
fields
|
||||
.unnamed
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| format_ident!("val{}", i, span = field.span()))
|
||||
}
|
||||
|
||||
pub fn named_idents(fields: &FieldsNamed) -> impl Iterator<Item = &Ident> + '_ {
|
||||
fields
|
||||
.named
|
||||
.iter()
|
||||
.map(|field| field.ident.as_ref().unwrap())
|
||||
}
|
||||
57
dbg-pls/debug-derive/src/predicate.rs
Normal file
57
dbg-pls/debug-derive/src/predicate.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
use quote::format_ident;
|
||||
use syn::{
|
||||
punctuated::Punctuated, token, Data, DeriveInput, Field, Fields, Path, PredicateType,
|
||||
TraitBound, TypeParamBound, WhereClause, WherePredicate,
|
||||
};
|
||||
|
||||
pub fn predicate(input: &mut DeriveInput, path: Path) {
|
||||
let mut pred = Pred {
|
||||
wc: input.generics.make_where_clause(),
|
||||
path,
|
||||
};
|
||||
|
||||
match &input.data {
|
||||
Data::Struct(s) => pred.fields(&s.fields),
|
||||
Data::Enum(e) => e.variants.iter().for_each(|var| pred.fields(&var.fields)),
|
||||
Data::Union(_) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
struct Pred<'a> {
|
||||
wc: &'a mut WhereClause,
|
||||
path: Path,
|
||||
}
|
||||
|
||||
impl<'a> Pred<'a> {
|
||||
fn dbg_pls(&mut self, field: &Field) {
|
||||
let mut bounds = Punctuated::new();
|
||||
|
||||
let mut path = self.path.clone();
|
||||
path.segments.push(syn::PathSegment {
|
||||
ident: format_ident!("DebugPls"),
|
||||
arguments: syn::PathArguments::None,
|
||||
});
|
||||
|
||||
bounds.push(TypeParamBound::Trait(TraitBound {
|
||||
paren_token: None,
|
||||
modifier: syn::TraitBoundModifier::None,
|
||||
lifetimes: None,
|
||||
path,
|
||||
}));
|
||||
|
||||
self.wc.predicates.push(WherePredicate::Type(PredicateType {
|
||||
lifetimes: None,
|
||||
bounded_ty: field.ty.clone(),
|
||||
colon_token: token::Colon::default(),
|
||||
bounds,
|
||||
}))
|
||||
}
|
||||
|
||||
fn fields(&mut self, fields: &Fields) {
|
||||
match fields {
|
||||
syn::Fields::Named(named) => named.named.iter().for_each(|f| self.dbg_pls(f)),
|
||||
syn::Fields::Unnamed(unnamed) => unnamed.unnamed.iter().for_each(|f| self.dbg_pls(f)),
|
||||
syn::Fields::Unit => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue