Skip to content

Commit

Permalink
improve debug
Browse files Browse the repository at this point in the history
  • Loading branch information
ModProg committed Feb 2, 2025
1 parent 3b4683f commit 2ebbf3e
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 30 deletions.
2 changes: 1 addition & 1 deletion impl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ add = []
add_assign = []
as_ref = ["syn/extra-traits", "syn/visit"]
constructor = []
debug = ["syn/extra-traits", "dep:unicode-xid", "dep:convert_case"]
debug = ["syn/extra-traits", "dep:unicode-xid"]
deref = []
deref_mut = []
display = ["syn/extra-traits", "dep:unicode-xid", "dep:convert_case"]
Expand Down
8 changes: 5 additions & 3 deletions impl/src/fmt/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
//!
//! [`fmt::Debug`]: std::fmt::Debug
use std::convert::Infallible;

use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{ext::IdentExt as _, parse_quote, spanned::Spanned as _};
Expand Down Expand Up @@ -77,7 +79,7 @@ pub fn expand(input: &syn::DeriveInput, _: &str) -> syn::Result<TokenStream> {
///
/// [`fmt::Debug`]: std::fmt::Debug
fn expand_struct(
attrs: ContainerAttributes,
attrs: ContainerAttributes<Infallible>,
ident: &syn::Ident,
s: &syn::DataStruct,
type_params: &[&syn::Ident],
Expand Down Expand Up @@ -115,7 +117,7 @@ fn expand_struct(
///
/// [`fmt::Debug`]: std::fmt::Debug
fn expand_enum(
mut attrs: ContainerAttributes,
mut attrs: ContainerAttributes<Infallible>,
e: &syn::DataEnum,
type_params: &[&syn::Ident],
attr_name: &syn::Ident,
Expand Down Expand Up @@ -207,7 +209,7 @@ type FieldAttribute = Either<attr::Skip, FmtAttribute>;
/// [`Debug::fmt()`]: std::fmt::Debug::fmt()
#[derive(Debug)]
struct Expansion<'a> {
attr: &'a ContainerAttributes,
attr: &'a ContainerAttributes<Infallible>,

/// Struct or enum [`Ident`](struct@syn::Ident).
ident: &'a syn::Ident,
Expand Down
4 changes: 2 additions & 2 deletions impl/src/fmt/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ pub fn expand(input: &syn::DeriveInput, trait_name: &str) -> syn::Result<TokenSt
///
/// [`syn::Ident`]: struct@syn::Ident
type ExpansionCtx<'a> = (
&'a ContainerAttributes,
&'a ContainerAttributes<RenameAllAttribute>,
&'a [&'a syn::Ident],
&'a syn::Ident,
&'a syn::Ident,
Expand Down Expand Up @@ -250,7 +250,7 @@ struct Expansion<'a> {
rename_all: Option<RenameAllAttribute>,

/// Derive macro [`ContainerAttributes`].
attrs: &'a ContainerAttributes,
attrs: &'a ContainerAttributes<RenameAllAttribute>,

/// Struct or enum [`syn::Ident`].
///
Expand Down
87 changes: 64 additions & 23 deletions impl/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ pub(crate) mod debug;
pub(crate) mod display;
mod parsing;

use std::fmt::Display;

#[cfg(feature = "display")]
use convert_case::{Case, Casing as _};
use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens};
Expand All @@ -19,7 +18,7 @@ use syn::{
parse_quote,
punctuated::Punctuated,
spanned::Spanned as _,
token, LitStr, Token,
token,
};

use crate::{
Expand Down Expand Up @@ -106,15 +105,18 @@ impl BoundsAttribute {
/// - `SCREAMING_SNAKE_CASE`
/// - `kebab-case`
/// - `SCREAMING-KEBAB-CASE`
#[cfg(feature = "display")]
#[derive(Debug, Clone, Copy)]
struct RenameAllAttribute(Case);
struct RenameAllAttribute(#[allow(unused)] Case);

#[cfg(feature = "display")]
impl RenameAllAttribute {
fn convert_case(&self, ident: &syn::Ident) -> String {
ident.unraw().to_string().to_case(self.0)
}
}

#[cfg(feature = "display")]
impl Parse for RenameAllAttribute {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let _ = input.parse::<syn::Path>().and_then(|p| {
Expand All @@ -128,9 +130,9 @@ impl Parse for RenameAllAttribute {
}
})?;

input.parse::<Token![=]>()?;
input.parse::<syn::Token![=]>()?;

let value: LitStr = input.parse()?;
let value: syn::LitStr = input.parse()?;

// TODO should we really do a case insensitive comparision here?
Ok(Self(match value.value().replace(['-', '_'], "").to_lowercase().as_str() {
Expand Down Expand Up @@ -568,20 +570,34 @@ impl Placeholder {
/// are allowed.
///
/// [`fmt::Display`]: std::fmt::Display
#[derive(Debug, Default)]
struct ContainerAttributes {
#[derive(Debug)]
struct ContainerAttributes<T> {
/// Interpolation [`FmtAttribute`].
fmt: Option<FmtAttribute>,

/// Addition trait bounds.
bounds: BoundsAttribute,

/// Rename unit enum variants following a similar behavior as [`serde`](https://serde.rs/container-attrs.html#rename_all).
rename_all: Option<RenameAllAttribute>,
rename_all: Option<T>,
}

impl Spanning<ContainerAttributes> {
fn validate_for_struct(&self, attr_name: impl Display) -> syn::Result<()> {
impl<T> std::default::Default for ContainerAttributes<T> {
fn default() -> Self {
Self {
fmt: None,
bounds: BoundsAttribute::default(),
rename_all: None,
}
}
}

#[cfg(feature = "display")]
impl<T> Spanning<ContainerAttributes<T>> {
fn validate_for_struct(
&self,
attr_name: impl std::fmt::Display,
) -> syn::Result<()> {
if self.rename_all.is_some() {
Err(syn::Error::new(
self.span,
Expand All @@ -593,21 +609,43 @@ impl Spanning<ContainerAttributes> {
}
}

mod kw {
use syn::custom_keyword;

custom_keyword!(rename_all);
custom_keyword!(bounds);
custom_keyword!(bound);
#[cfg(feature = "debug")]
impl Parse for ContainerAttributes<std::convert::Infallible> {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
// We do check `FmtAttribute::check_legacy_fmt` eagerly here, because `Either` will swallow
// any error of the `Either::Left` if the `Either::Right` succeeds.
FmtAttribute::check_legacy_fmt(input)?;
<Either<FmtAttribute, BoundsAttribute>>::parse(input).map(|v| match v {
Either::Left(fmt) => Self {
bounds: BoundsAttribute::default(),
fmt: Some(fmt),
rename_all: None,
},
Either::Right(bounds) => Self {
bounds,
fmt: None,
rename_all: None,
},
})
}
}

impl Parse for ContainerAttributes {
#[cfg(feature = "display")]
impl Parse for ContainerAttributes<RenameAllAttribute> {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
mod kw {
use syn::custom_keyword;

custom_keyword!(rename_all);
custom_keyword!(bounds);
custom_keyword!(bound);
}

// We do check `FmtAttribute::check_legacy_fmt` eagerly here, because `Either` will swallow
// any error of the `Either::Left` if the `Either::Right` succeeds.
FmtAttribute::check_legacy_fmt(input)?;
let lookahead = input.lookahead1();
Ok(if lookahead.peek(LitStr) {
Ok(if lookahead.peek(syn::LitStr) {
Self {
fmt: Some(input.parse()?),
bounds: BoundsAttribute::default(),
Expand All @@ -616,7 +654,7 @@ impl Parse for ContainerAttributes {
} else if lookahead.peek(kw::rename_all)
|| lookahead.peek(kw::bounds)
|| lookahead.peek(kw::bound)
|| lookahead.peek(Token![where])
|| lookahead.peek(syn::Token![where])
{
let mut bounds = BoundsAttribute::default();
let mut rename_all = None;
Expand All @@ -633,14 +671,14 @@ impl Parse for ContainerAttributes {
}
} else if lookahead.peek(kw::bounds)
|| lookahead.peek(kw::bound)
|| lookahead.peek(Token![where])
|| lookahead.peek(syn::Token![where])
{
bounds.0.extend(input.parse::<BoundsAttribute>()?.0)
} else {
return Err(lookahead.error());
}
if !input.is_empty() {
input.parse::<Token![,]>()?;
input.parse::<syn::Token![,]>()?;
}
}
Self {
Expand All @@ -654,7 +692,10 @@ impl Parse for ContainerAttributes {
}
}

impl attr::ParseMultiple for ContainerAttributes {
impl<T: 'static> attr::ParseMultiple for ContainerAttributes<T>
where
ContainerAttributes<T>: Parse,
{
fn merge_attrs(
prev: Spanning<Self>,
new: Spanning<Self>,
Expand Down
2 changes: 1 addition & 1 deletion tests/compile_fail/debug/unknown_attribute.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: expected one of: string literal, `rename_all`, `bounds`, `bound`, `where`
error: unknown attribute argument, expected `bound(...)`
--> tests/compile_fail/debug/unknown_attribute.rs:2:9
|
2 | #[debug(unknown = "unknown")]
Expand Down

0 comments on commit 2ebbf3e

Please sign in to comment.