From 3e30a55fc91b5dcf5a22b1c5177c5244fdfd6dac Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Mon, 15 Dec 2025 16:52:22 +1100 Subject: [PATCH 1/3] Run rustfmt. In order to avoid diffs in later commits. --- src/lib.rs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1b5fa52..cbf8a25 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,4 @@ -#![forbid( - rust_2018_idioms, - future_incompatible, - elided_lifetimes_in_paths, - unsafe_code -)] +#![forbid(rust_2018_idioms, future_incompatible, elided_lifetimes_in_paths, unsafe_code)] #![warn( missing_debug_implementations, missing_docs, @@ -378,14 +373,8 @@ fn debug_impl(atomic_ident: &Ident) -> TokenStream2 { /// ``` pub fn atomic_enum(args: TokenStream, input: TokenStream) -> TokenStream { // Parse the input - let ItemEnum { - attrs, - vis, - ident, - generics, - variants, - .. - } = parse_macro_input!(input as ItemEnum); + let ItemEnum { attrs, vis, ident, generics, variants, .. } = + parse_macro_input!(input as ItemEnum); // We only support C-style enums: No generics, no fields if !generics.params.is_empty() { From 7194886406a7fd759c6a0b2d44cd9562957a2cc7 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Mon, 15 Dec 2025 17:43:24 +1100 Subject: [PATCH 2/3] Use a struct instead of a tuple struct. Give the inner field a name to prevent/discourage direct use, ensuring the invariant that it always has a valid value. This will be necessary for an upcoming commit that takes advantage of that invariant. I tried instead putting the enum into a module and controlling this with visibility, but I couldn't make it work correctly for enums defined within a function, as in the case of the doc tests. --- src/lib.rs | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cbf8a25..99ff52c 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -73,7 +73,9 @@ This type uses an `AtomicUsize` to store the enum value. quote! { #[doc = #atomic_ident_docs] - #vis struct #atomic_ident(core::sync::atomic::AtomicUsize); + #vis struct #atomic_ident { + inner_do_not_use_directly: core::sync::atomic::AtomicUsize, + } } } @@ -125,8 +127,10 @@ fn atomic_enum_new(ident: &Ident, atomic_ident: &Ident) -> TokenStream2 { quote! { #[doc = #atomic_ident_docs] - pub const fn new(v: #ident) -> #atomic_ident { - #atomic_ident(core::sync::atomic::AtomicUsize::new(Self::to_usize(v))) + pub const fn new(v: #ident) -> Self { + Self { + inner_do_not_use_directly: core::sync::atomic::AtomicUsize::new(Self::to_usize(v)), + } } } } @@ -137,7 +141,7 @@ fn atomic_enum_into_inner(ident: &Ident) -> TokenStream2 { /// /// This is safe because passing self by value guarantees that no other threads are concurrently accessing the atomic data. pub fn into_inner(self) -> #ident { - Self::from_usize(self.0.into_inner()) + Self::from_usize(self.inner_do_not_use_directly.into_inner()) } } } @@ -148,7 +152,7 @@ fn atomic_enum_set(ident: &Ident) -> TokenStream2 { /// /// This is safe because the mutable reference guarantees that no other threads are concurrently accessing the atomic data. pub fn set(&mut self, v: #ident) { - *self.0.get_mut() = Self::to_usize(v); + *self.inner_do_not_use_directly.get_mut() = Self::to_usize(v); } } } @@ -159,7 +163,7 @@ fn atomic_enum_get(ident: &Ident) -> TokenStream2 { /// /// This is safe because the mutable reference guarantees that no other threads are concurrently accessing the atomic data. pub fn get(&mut self) -> #ident { - Self::from_usize(*self.0.get_mut()) + Self::from_usize(*self.inner_do_not_use_directly.get_mut()) } } } @@ -187,7 +191,7 @@ fn atomic_enum_load(ident: &Ident) -> TokenStream2 { /// /// Panics if order is `Release` or `AcqRel`. pub fn load(&self, order: core::sync::atomic::Ordering) -> #ident { - Self::from_usize(self.0.load(order)) + Self::from_usize(self.inner_do_not_use_directly.load(order)) } } } @@ -202,7 +206,7 @@ fn atomic_enum_store(ident: &Ident) -> TokenStream2 { /// /// Panics if order is `Acquire` or `AcqRel`. pub fn store(&self, val: #ident, order: core::sync::atomic::Ordering) { - self.0.store(Self::to_usize(val), order) + self.inner_do_not_use_directly.store(Self::to_usize(val), order) } } } @@ -216,7 +220,7 @@ fn atomic_enum_swap(ident: &Ident) -> TokenStream2 { /// All ordering modes are possible. Note that using `Acquire` makes the store part of this operation `Relaxed`, /// and using `Release` makes the load part `Relaxed`. pub fn swap(&self, val: #ident, order: core::sync::atomic::Ordering) -> #ident { - Self::from_usize(self.0.swap(Self::to_usize(val), order)) + Self::from_usize(self.inner_do_not_use_directly.swap(Self::to_usize(val), order)) } } } @@ -240,7 +244,7 @@ fn atomic_enum_compare_and_swap(ident: &Ident) -> TokenStream2 { new: #ident, order: core::sync::atomic::Ordering ) -> #ident { - Self::from_usize(self.0.compare_and_swap( + Self::from_usize(self.inner_do_not_use_directly.compare_and_swap( Self::to_usize(current), Self::to_usize(new), order @@ -269,7 +273,7 @@ fn atomic_enum_compare_exchange(ident: &Ident) -> TokenStream2 { success: core::sync::atomic::Ordering, failure: core::sync::atomic::Ordering ) -> core::result::Result<#ident, #ident> { - self.0 + self.inner_do_not_use_directly .compare_exchange( Self::to_usize(current), Self::to_usize(new), @@ -303,7 +307,7 @@ fn atomic_enum_compare_exchange_weak(ident: &Ident) -> TokenStream2 { success: core::sync::atomic::Ordering, failure: core::sync::atomic::Ordering ) -> core::result::Result<#ident, #ident> { - self.0 + self.inner_do_not_use_directly .compare_exchange_weak( Self::to_usize(current), Self::to_usize(new), From 6edc40c5d38edec62a8e2a774f51c89d1618fa68 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Mon, 15 Dec 2025 17:46:16 +1100 Subject: [PATCH 3/3] Mark the invalid discriminant case as unreachable. In reality this value should never be invalid. Teaching this to the compiler improves benchmarks for some low-level task polling code I'm working on by 3-4% in practice. --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 99ff52c..abd00c5 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,13 +111,13 @@ fn enum_from_usize(ident: &Ident, variants: impl IntoIterator) - match val { #(#variants_back)* - _ => panic!("Invalid enum discriminant"), + _ => unsafe { core::hint::unreachable_unchecked() }, } } } } -fn atomic_enum_new(ident: &Ident, atomic_ident: &Ident) -> TokenStream2 { +fn atomic_enum_new(ident: &Ident) -> TokenStream2 { let atomic_ident_docs = format!( "Creates a new atomic [`{0}`]. @@ -407,7 +407,7 @@ pub fn atomic_enum(args: TokenStream, input: TokenStream) -> TokenStream { // Write the impl block for the atomic wrapper let enum_to_usize = enum_to_usize(&ident); let enum_from_usize = enum_from_usize(&ident, variants); - let atomic_enum_new = atomic_enum_new(&ident, &atomic_ident); + let atomic_enum_new = atomic_enum_new(&ident); let atomic_enum_into_inner = atomic_enum_into_inner(&ident); let atomic_enum_set = atomic_enum_set(&ident); let atomic_enum_get = atomic_enum_get(&ident);