From 6da4e2eca633f8487f22e67acee2317586f9fc03 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Tue, 18 Jun 2024 16:12:25 +0300 Subject: [PATCH] Replace stringify! in Debug impls with type checked macro Add identify! macro which expands to stringify! but also const type checks the value to prevent typos/wrong values. Signed-off-by: Manos Pitsidianakis --- meli/src/mail/compose/hooks.rs | 4 +-- meli/src/mail/view/filters.rs | 2 +- meli/src/mail/view/html.rs | 2 +- meli/src/notifications.rs | 4 +-- meli/src/terminal/cells.rs | 6 ++-- meli/src/types.rs | 2 +- meli/src/utilities/text.rs | 2 +- melib/src/backends.rs | 9 +++--- melib/src/email.rs | 2 +- melib/src/email/address.rs | 4 +-- melib/src/email/attachments.rs | 2 +- melib/src/email/headers/names.rs | 2 +- melib/src/email/parser.rs | 8 ++--- melib/src/gpgme/mod.rs | 2 +- melib/src/jmap/session.rs | 2 +- melib/src/jmap/submission.rs | 2 +- melib/src/utils/connections.rs | 8 ++--- melib/src/utils/logging.rs | 2 +- melib/src/utils/mod.rs | 55 ++++++++++++++++++++++++++++++++ 19 files changed, 88 insertions(+), 32 deletions(-) diff --git a/meli/src/mail/compose/hooks.rs b/meli/src/mail/compose/hooks.rs index 3ce04ec0..013b7917 100644 --- a/meli/src/mail/compose/hooks.rs +++ b/meli/src/mail/compose/hooks.rs @@ -36,8 +36,8 @@ pub enum HookFn { } impl std::fmt::Debug for HookFn { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_struct(stringify!(HookFn)) + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.debug_struct(melib::identify!(HookFn)) .field( "kind", &match self { diff --git a/meli/src/mail/view/filters.rs b/meli/src/mail/view/filters.rs index 2f3aa933..5485bfea 100644 --- a/meli/src/mail/view/filters.rs +++ b/meli/src/mail/view/filters.rs @@ -108,7 +108,7 @@ pub struct ViewFilter { impl std::fmt::Debug for ViewFilter { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - fmt.debug_struct(stringify!(ViewFilter)) + fmt.debug_struct(melib::identify!(ViewFilter)) .field("filter_invocation", &self.filter_invocation) .field("content_type", &self.content_type) .field("notice", &self.notice) diff --git a/meli/src/mail/view/html.rs b/meli/src/mail/view/html.rs index 03b3a842..50e777e6 100644 --- a/meli/src/mail/view/html.rs +++ b/meli/src/mail/view/html.rs @@ -37,7 +37,7 @@ pub struct HtmlView { impl std::fmt::Debug for HtmlView { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - fmt.debug_struct(stringify!(HtmlView)) + fmt.debug_struct(melib::identify!(HtmlView)) .field("pager", &self.pager) .field("bytes", &self.bytes.len()) .field("coordinates", &self.coordinates) diff --git a/meli/src/notifications.rs b/meli/src/notifications.rs index 53750c54..c15ca52c 100644 --- a/meli/src/notifications.rs +++ b/meli/src/notifications.rs @@ -233,7 +233,7 @@ impl Component for NotificationCommand { Ok(child) => { context .children - .entry(stringify!(NotificationCommand).into()) + .entry(melib::identify!(NotificationCommand).into()) .or_default() .push(child); } @@ -268,7 +268,7 @@ impl Component for NotificationCommand { Ok(child) => { context .children - .entry(stringify!(NotificationCommand).into()) + .entry(melib::identify!(NotificationCommand).into()) .or_default() .push(child); return false; diff --git a/meli/src/terminal/cells.rs b/meli/src/terminal/cells.rs index 53ab8117..b770b616 100644 --- a/meli/src/terminal/cells.rs +++ b/meli/src/terminal/cells.rs @@ -79,8 +79,8 @@ pub struct CellBuffer { } impl std::fmt::Debug for CellBuffer { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_struct(stringify!(CellBuffer)) + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.debug_struct(melib::identify!(CellBuffer)) .field("cols", &self.cols) .field("rows", &self.rows) .field("buf cells", &self.buf.len()) @@ -1425,7 +1425,7 @@ pub struct BoundsIterator { impl std::fmt::Debug for BoundsIterator { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_struct(stringify!(BoundsIterator)) + f.debug_struct(melib::identify!(BoundsIterator)) .field("rows", &self.rows) .field("cols", &self.cols) .field("width", &self.width) diff --git a/meli/src/types.rs b/meli/src/types.rs index c828652d..224c1c0c 100644 --- a/meli/src/types.rs +++ b/meli/src/types.rs @@ -188,7 +188,7 @@ pub struct CallbackFn(pub Box) impl std::fmt::Debug for CallbackFn { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(fmt, "CallbackFn") + fmt.debug_struct(melib::identify!(CallbackFn)).finish() } } diff --git a/meli/src/utilities/text.rs b/meli/src/utilities/text.rs index 8a6ac886..a3c344aa 100644 --- a/meli/src/utilities/text.rs +++ b/meli/src/utilities/text.rs @@ -30,7 +30,7 @@ pub struct TextField { impl std::fmt::Debug for TextField { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - fmt.debug_struct(stringify!(TextField)) + fmt.debug_struct(melib::identify!(TextField)) .field("id", &self.id) .field("inner", &self.inner) .field("has AutoComplete", &self.autocomplete.is_some()) diff --git a/melib/src/backends.rs b/melib/src/backends.rs index 35fb154c..9916aaab 100644 --- a/melib/src/backends.rs +++ b/melib/src/backends.rs @@ -324,8 +324,9 @@ impl BackendEventConsumer { } impl std::fmt::Debug for BackendEventConsumer { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, stringify!(BackendEventConsumer)) + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.debug_struct(crate::identify!(BackendEventConsumer)) + .finish() } } @@ -714,7 +715,7 @@ pub struct LazyCountSet { impl std::fmt::Debug for LazyCountSet { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_struct("LazyCountSet") + f.debug_struct(crate::identify!(LazyCountSet)) .field("not_yet_seen", &self.not_yet_seen) .field("set", &self.set.len()) .field("total_len", &self.len()) @@ -786,7 +787,7 @@ pub struct IsSubscribedFn(pub Box bool + Send + Sync>); impl std::fmt::Debug for IsSubscribedFn { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "IsSubscribedFn Box") + f.debug_struct(crate::identify!(IsSubscribedFn)).finish() } } diff --git a/melib/src/email.rs b/melib/src/email.rs index 43bf513a..5395a218 100644 --- a/melib/src/email.rs +++ b/melib/src/email.rs @@ -293,7 +293,7 @@ pub struct Envelope { impl std::fmt::Debug for Envelope { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_struct("Envelope") + f.debug_struct(crate::identify!(Envelope)) .field("Subject", &self.subject()) .field("Date", &self.date) .field("From", &self.from) diff --git a/melib/src/email/address.rs b/melib/src/email/address.rs index a26b4c38..950a13a6 100644 --- a/melib/src/email/address.rs +++ b/melib/src/email/address.rs @@ -444,7 +444,7 @@ impl std::fmt::Debug for Address { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::Mailbox(m) => f - .debug_struct("Address::Mailbox") + .debug_struct(stringify!(Address::Mailbox)) .field("display_name", &m.display_name.display(&m.raw)) .field("address_spec", &m.address_spec.display(&m.raw)) .finish(), @@ -452,7 +452,7 @@ impl std::fmt::Debug for Address { let attachment_strings: Vec = g.mailbox_list.iter().map(|a| format!("{}", a)).collect(); - f.debug_struct("Address::Group") + f.debug_struct(stringify!(Address::Group)) .field("display_name", &g.display_name.display(&g.raw)) .field("addresses", &attachment_strings.join(", ")) .finish() diff --git a/melib/src/email/attachments.rs b/melib/src/email/attachments.rs index 68a78da8..971f4dcc 100644 --- a/melib/src/email/attachments.rs +++ b/melib/src/email/attachments.rs @@ -408,7 +408,7 @@ impl std::fmt::Debug for Attachment { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let mut text = Vec::with_capacity(4096); self.get_text_recursive(&Text::Plain, &mut text); - f.debug_struct("Attachment") + f.debug_struct(crate::identify!(Attachment)) .field("Content-Type", &self.content_type) .field("Content-Transfer-Encoding", &self.content_transfer_encoding) .field("bytes", &self.raw.len()) diff --git a/melib/src/email/headers/names.rs b/melib/src/email/headers/names.rs index 3c1e2984..1c24c223 100644 --- a/melib/src/email/headers/names.rs +++ b/melib/src/email/headers/names.rs @@ -94,7 +94,7 @@ impl std::fmt::Debug for InvalidHeaderName { impl std::fmt::Display for InvalidHeaderName { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(fmt, "{}", stringify!(InvalidHeaderName)) + write!(fmt, "{}", crate::identify!(InvalidHeaderName)) } } diff --git a/melib/src/email/parser.rs b/melib/src/email/parser.rs index fccac28b..e05157d5 100644 --- a/melib/src/email/parser.rs +++ b/melib/src/email/parser.rs @@ -73,7 +73,7 @@ impl std::fmt::Debug for ParsingError<&'_ [u8]> { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { #[cfg(any(test, doc))] { - fmt.debug_struct("ParsingError") + fmt.debug_struct(stringify!(ParsingError)) .field("input", &to_str!(self.input)) .field("error", &self.error) .field("backtrace", &self.backtrace) @@ -81,7 +81,7 @@ impl std::fmt::Debug for ParsingError<&'_ [u8]> { } #[cfg(not(any(test, doc)))] { - fmt.debug_struct("ParsingError") + fmt.debug_struct(stringify!(ParsingError)) .field("input", &to_str!(self.input)) .field("error", &self.error) .finish() @@ -93,7 +93,7 @@ impl std::fmt::Debug for ParsingError<&'_ str> { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { #[cfg(any(test, doc))] { - fmt.debug_struct("ParsingError") + fmt.debug_struct(stringify!(ParsingError)) .field("input", &self.input) .field("error", &self.error) .field("backtrace", &self.backtrace) @@ -101,7 +101,7 @@ impl std::fmt::Debug for ParsingError<&'_ str> { } #[cfg(not(any(test, doc)))] { - fmt.debug_struct("ParsingError") + fmt.debug_struct(stringify!(ParsingError)) .field("input", &self.input) .field("error", &self.error) .finish() diff --git a/melib/src/gpgme/mod.rs b/melib/src/gpgme/mod.rs index d1a0ecce..c88ca6b0 100644 --- a/melib/src/gpgme/mod.rs +++ b/melib/src/gpgme/mod.rs @@ -1312,7 +1312,7 @@ impl Key { impl std::fmt::Debug for Key { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - fmt.debug_struct("Key") + fmt.debug_struct(crate::identify!(Key)) .field("fingerprint", &self.fingerprint()) .field("uid", &self.primary_uid()) .field("can_encrypt", &self.can_encrypt()) diff --git a/melib/src/jmap/session.rs b/melib/src/jmap/session.rs index ed212fdb..6901d647 100644 --- a/melib/src/jmap/session.rs +++ b/melib/src/jmap/session.rs @@ -51,7 +51,7 @@ pub struct Session { } impl Object for Session { - const NAME: &'static str = stringify!(Session); + const NAME: &'static str = crate::identify!(Session); } impl Session { diff --git a/melib/src/jmap/submission.rs b/melib/src/jmap/submission.rs index f246f1ca..457fda2a 100644 --- a/melib/src/jmap/submission.rs +++ b/melib/src/jmap/submission.rs @@ -276,7 +276,7 @@ impl Serialize for EmailSubmissionObject { where S: Serializer, { - let mut state = serializer.serialize_struct(stringify! {EmailSubmissionObject}, 4)?; + let mut state = serializer.serialize_struct(crate::identify!(EmailSubmissionObject), 4)?; state.serialize_field("identityId", &self.identity_id)?; state.serialize_field( if matches!(self.email_id, Argument::Value(_)) { diff --git a/melib/src/utils/connections.rs b/melib/src/utils/connections.rs index 66d2aeb5..36c93da4 100644 --- a/melib/src/utils/connections.rs +++ b/melib/src/utils/connections.rs @@ -74,7 +74,7 @@ impl std::fmt::Debug for Connection { ref inner, ref id, } => fmt - .debug_struct(stringify!(Connection)) + .debug_struct(crate::identify!(Connection)) .field("variant", &stringify!(Tcp)) .field(stringify!(trace), trace) .field(stringify!(id), id) @@ -86,7 +86,7 @@ impl std::fmt::Debug for Connection { ref inner, ref id, } => fmt - .debug_struct(stringify!(Connection)) + .debug_struct(crate::identify!(Connection)) .field("variant", &stringify!(Tls)) .field(stringify!(trace), trace) .field(stringify!(id), id) @@ -97,7 +97,7 @@ impl std::fmt::Debug for Connection { ref inner, ref id, } => fmt - .debug_struct(stringify!(Connection)) + .debug_struct(crate::identify!(Connection)) .field("variant", &stringify!(Fd)) .field(stringify!(trace), trace) .field(stringify!(id), id) @@ -108,7 +108,7 @@ impl std::fmt::Debug for Connection { ref inner, ref id, } => fmt - .debug_struct(stringify!(Connection)) + .debug_struct(crate::identify!(Connection)) .field("variant", &stringify!(Deflate)) .field(stringify!(trace), trace) .field(stringify!(id), id) diff --git a/melib/src/utils/logging.rs b/melib/src/utils/logging.rs index 419c5466..7aba5849 100644 --- a/melib/src/utils/logging.rs +++ b/melib/src/utils/logging.rs @@ -153,7 +153,7 @@ pub struct StderrLogger { impl std::fmt::Debug for StderrLogger { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - fmt.debug_struct(stringify!(StderrLogger)) + fmt.debug_struct(crate::identify!(StderrLogger)) .field("level", &LogLevel::from(self.level.load(Ordering::SeqCst))) .field("print_level", &self.print_level) .field("print_module_names", &self.print_module_names) diff --git a/melib/src/utils/mod.rs b/melib/src/utils/mod.rs index ba66a435..d92c7e2c 100644 --- a/melib/src/utils/mod.rs +++ b/melib/src/utils/mod.rs @@ -238,3 +238,58 @@ pub mod hostname { retval } } + +#[macro_export] +/// For use with `debug_struct` in `Debug` implementations to prevent stale type +/// names after renaming or typos during compilation. +/// +/// # Example +/// +/// ```no_run +/// # use melib::identify; +/// struct Envelope; +/// +/// impl std::fmt::Debug for Envelope { +/// fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { +/// f.debug_struct(identify!(Envelope)) +/// .field("Subject", &"foobar") +/// .finish() +/// } +/// } +/// ``` +/// +/// Using it with an invalid identifier will fail: +/// +/// ```no_run,compile_fail +/// # use melib::identify; +/// struct Envelope; +/// +/// impl std::fmt::Debug for Envelope { +/// fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { +/// f.debug_struct(identify!(Enzelope)) +/// .field("Subject", &"foobar") +/// .finish() +/// } +/// } +/// ``` +/// +/// This will fail with: +/// +/// ```text +/// error[E0412]: cannot find type `Enzelope` in this scope +/// | +/// ___ | struct Envelope; +/// | ------------------- similarly named struct `Envelope` defined here +/// ... +/// ___ | f.debug_struct(identify!(Enzelope)) +/// | ^^^^^^^^ help: a struct with a similar name exists: `Envelope` +/// ``` +macro_rules! identify { + ($f:tt$($t:tt)*) => {{ + const fn __debugify() -> ::core::marker::PhantomData<$f$($t)*> { + core::marker::PhantomData + } + let _: ::core::marker::PhantomData = __debugify(); + stringify!($f$($t)*) + }}; +}