From 368738bef44dbba1a178383d878a6d9423b1ccd9 Mon Sep 17 00:00:00 2001 From: Curly Date: Tue, 19 Aug 2025 22:30:53 -0700 Subject: [PATCH] chore: add more `Debug` impls to `embassy-sync`, particularly on `OnceLock` All tests green --- embassy-sync/CHANGELOG.md | 1 + embassy-sync/src/blocking_mutex/mod.rs | 1 + embassy-sync/src/blocking_mutex/raw.rs | 2 ++ embassy-sync/src/channel.rs | 7 +++++++ embassy-sync/src/lazy_lock.rs | 2 ++ embassy-sync/src/mutex.rs | 1 + embassy-sync/src/once_lock.rs | 10 ++++++++++ embassy-sync/src/pipe.rs | 8 ++++++++ embassy-sync/src/pubsub/mod.rs | 2 ++ embassy-sync/src/pubsub/publisher.rs | 6 ++++++ embassy-sync/src/pubsub/subscriber.rs | 3 +++ embassy-sync/src/ring_buffer.rs | 1 + embassy-sync/src/rwlock.rs | 1 + embassy-sync/src/semaphore.rs | 6 ++++++ embassy-sync/src/signal.rs | 1 + embassy-sync/src/waitqueue/atomic_waker_turbo.rs | 1 + embassy-sync/src/waitqueue/multi_waker.rs | 1 + embassy-sync/src/watch.rs | 6 ++++++ embassy-sync/src/zerocopy_channel.rs | 5 +++++ 19 files changed, 65 insertions(+) diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index c445e9ba1..fa0340c68 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - Add `get_mut` to `LazyLock` +- Add more `Debug` impls to `embassy-sync`, particularly on `OnceLock` ## 0.7.0 - 2025-05-28 diff --git a/embassy-sync/src/blocking_mutex/mod.rs b/embassy-sync/src/blocking_mutex/mod.rs index a41bc3569..11809c763 100644 --- a/embassy-sync/src/blocking_mutex/mod.rs +++ b/embassy-sync/src/blocking_mutex/mod.rs @@ -22,6 +22,7 @@ use self::raw::RawMutex; /// /// In all cases, the blocking mutex is intended to be short lived and not held across await points. /// Use the async [`Mutex`](crate::mutex::Mutex) if you need a lock that is held across await points. +#[derive(Debug)] pub struct Mutex { // NOTE: `raw` must be FIRST, so when using ThreadModeMutex the "can't drop in non-thread-mode" gets // to run BEFORE dropping `data`. diff --git a/embassy-sync/src/blocking_mutex/raw.rs b/embassy-sync/src/blocking_mutex/raw.rs index a8afcad34..50f965e00 100644 --- a/embassy-sync/src/blocking_mutex/raw.rs +++ b/embassy-sync/src/blocking_mutex/raw.rs @@ -37,6 +37,7 @@ pub unsafe trait RawMutex { /// # Safety /// /// This mutex is safe to share between different executors and interrupts. +#[derive(Debug)] pub struct CriticalSectionRawMutex { _phantom: PhantomData<()>, } @@ -65,6 +66,7 @@ unsafe impl RawMutex for CriticalSectionRawMutex { /// # Safety /// /// **This Mutex is only safe within a single executor.** +#[derive(Debug)] pub struct NoopRawMutex { _phantom: PhantomData<*mut ()>, } diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index 8e9fcc234..de437cc52 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs @@ -55,6 +55,7 @@ use crate::blocking_mutex::Mutex; use crate::waitqueue::WakerRegistration; /// Send-only access to a [`Channel`]. +#[derive(Debug)] pub struct Sender<'ch, M, T, const N: usize> where M: RawMutex, @@ -241,6 +242,7 @@ impl<'ch, T> SendDynamicSender<'ch, T> { } /// Receive-only access to a [`Channel`]. +#[derive(Debug)] pub struct Receiver<'ch, M, T, const N: usize> where M: RawMutex, @@ -486,6 +488,7 @@ where /// Future returned by [`Channel::receive`] and [`Receiver::receive`]. #[must_use = "futures do nothing unless you `.await` or poll them"] +#[derive(Debug)] pub struct ReceiveFuture<'ch, M, T, const N: usize> where M: RawMutex, @@ -506,6 +509,7 @@ where /// Future returned by [`Channel::ready_to_receive`] and [`Receiver::ready_to_receive`]. #[must_use = "futures do nothing unless you `.await` or poll them"] +#[derive(Debug)] pub struct ReceiveReadyFuture<'ch, M, T, const N: usize> where M: RawMutex, @@ -549,6 +553,7 @@ impl<'ch, M: RawMutex, T, const N: usize> From> for /// Future returned by [`Channel::send`] and [`Sender::send`]. #[must_use = "futures do nothing unless you `.await` or poll them"] +#[derive(Debug)] pub struct SendFuture<'ch, M, T, const N: usize> where M: RawMutex, @@ -646,6 +651,7 @@ pub enum TrySendError { Full(T), } +#[derive(Debug)] struct ChannelState { queue: Deque, receiver_waker: WakerRegistration, @@ -785,6 +791,7 @@ impl ChannelState { /// received from the channel. /// /// All data sent will become available in the same order as it was sent. +#[derive(Debug)] pub struct Channel where M: RawMutex, diff --git a/embassy-sync/src/lazy_lock.rs b/embassy-sync/src/lazy_lock.rs index a919f0037..945560a80 100644 --- a/embassy-sync/src/lazy_lock.rs +++ b/embassy-sync/src/lazy_lock.rs @@ -21,6 +21,7 @@ use core::sync::atomic::{AtomicBool, Ordering}; /// let reference = VALUE.get(); /// assert_eq!(reference, &20); /// ``` +#[derive(Debug)] pub struct LazyLock T> { init: AtomicBool, data: UnsafeCell>, @@ -144,6 +145,7 @@ mod tests { } static DROP_CHECKER: AtomicU32 = AtomicU32::new(0); + #[derive(Debug)] struct DropCheck; impl Drop for DropCheck { diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs index 8496f34bf..4ce6dd987 100644 --- a/embassy-sync/src/mutex.rs +++ b/embassy-sync/src/mutex.rs @@ -16,6 +16,7 @@ use crate::waitqueue::WakerRegistration; #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct TryLockError; +#[derive(Debug)] struct State { locked: bool, waker: WakerRegistration, diff --git a/embassy-sync/src/once_lock.rs b/embassy-sync/src/once_lock.rs index 1e848685a..73edfea9a 100644 --- a/embassy-sync/src/once_lock.rs +++ b/embassy-sync/src/once_lock.rs @@ -1,6 +1,7 @@ //! Synchronization primitive for initializing a value once, allowing others to await a reference to the value. use core::cell::Cell; +use core::fmt::{Debug, Formatter}; use core::future::{poll_fn, Future}; use core::mem::MaybeUninit; use core::sync::atomic::{AtomicBool, Ordering}; @@ -42,6 +43,15 @@ pub struct OnceLock { data: Cell>, } +impl Debug for OnceLock { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("OnceLock") + .field("init", &self.init) + .field("data", &"Cell>") + .finish() + } +} + unsafe impl Sync for OnceLock where T: Sync {} impl OnceLock { diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs index df3b28b45..6d624979a 100644 --- a/embassy-sync/src/pipe.rs +++ b/embassy-sync/src/pipe.rs @@ -13,6 +13,7 @@ use crate::ring_buffer::RingBuffer; use crate::waitqueue::WakerRegistration; /// Write-only access to a [`Pipe`]. +#[derive(Debug)] pub struct Writer<'p, M, const N: usize> where M: RawMutex, @@ -52,6 +53,7 @@ where /// Future returned by [`Pipe::write`] and [`Writer::write`]. #[must_use = "futures do nothing unless you `.await` or poll them"] +#[derive(Debug)] pub struct WriteFuture<'p, M, const N: usize> where M: RawMutex, @@ -77,6 +79,7 @@ where impl<'p, M, const N: usize> Unpin for WriteFuture<'p, M, N> where M: RawMutex {} /// Read-only access to a [`Pipe`]. +#[derive(Debug)] pub struct Reader<'p, M, const N: usize> where M: RawMutex, @@ -128,6 +131,7 @@ where /// Future returned by [`Pipe::read`] and [`Reader::read`]. #[must_use = "futures do nothing unless you `.await` or poll them"] +#[derive(Debug)] pub struct ReadFuture<'p, M, const N: usize> where M: RawMutex, @@ -154,6 +158,7 @@ impl<'p, M, const N: usize> Unpin for ReadFuture<'p, M, N> where M: RawMutex {} /// Future returned by [`Reader::fill_buf`]. #[must_use = "futures do nothing unless you `.await` or poll them"] +#[derive(Debug)] pub struct FillBufFuture<'p, M, const N: usize> where M: RawMutex, @@ -199,6 +204,7 @@ pub enum TryWriteError { Full, } +#[derive(Debug)] struct PipeState { buffer: RingBuffer, read_waker: WakerRegistration, @@ -206,6 +212,7 @@ struct PipeState { } #[repr(transparent)] +#[derive(Debug)] struct Buffer(UnsafeCell<[u8; N]>); impl Buffer { @@ -230,6 +237,7 @@ unsafe impl Sync for Buffer {} /// buffer is full, attempts to `write` new bytes will wait until buffer space is freed up. /// /// All data written will become available in the same order as it was written. +#[derive(Debug)] pub struct Pipe where M: RawMutex, diff --git a/embassy-sync/src/pubsub/mod.rs b/embassy-sync/src/pubsub/mod.rs index 9206b9383..ad9402f5a 100644 --- a/embassy-sync/src/pubsub/mod.rs +++ b/embassy-sync/src/pubsub/mod.rs @@ -71,6 +71,7 @@ pub use subscriber::{DynSubscriber, Subscriber}; /// # block_on(test); /// ``` /// +#[derive(Debug)] pub struct PubSubChannel { inner: Mutex>>, } @@ -297,6 +298,7 @@ impl { /// The queue contains the last messages that have been published and a countdown of how many subscribers are yet to read it queue: Deque<(T, usize), CAP>, diff --git a/embassy-sync/src/pubsub/publisher.rs b/embassy-sync/src/pubsub/publisher.rs index 52a52f926..2a67a0002 100644 --- a/embassy-sync/src/pubsub/publisher.rs +++ b/embassy-sync/src/pubsub/publisher.rs @@ -10,6 +10,7 @@ use super::{PubSubBehavior, PubSubChannel}; use crate::blocking_mutex::raw::RawMutex; /// A publisher to a channel +#[derive(Debug)] pub struct Pub<'a, PSB: PubSubBehavior + ?Sized, T: Clone> { /// The channel we are a publisher for channel: &'a PSB, @@ -106,6 +107,7 @@ impl<'a, T: Clone> DerefMut for DynPublisher<'a, T> { } /// A publisher that holds a generic reference to the channel +#[derive(Debug)] pub struct Publisher<'a, M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usize>( pub(super) Pub<'a, PubSubChannel, T>, ); @@ -130,6 +132,7 @@ impl<'a, M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: /// A publisher that can only use the `publish_immediate` function, but it doesn't have to be registered with the channel. /// (So an infinite amount is possible) +#[derive(Debug)] pub struct ImmediatePub<'a, PSB: PubSubBehavior + ?Sized, T: Clone> { /// The channel we are a publisher for channel: &'a PSB, @@ -205,6 +208,7 @@ impl<'a, T: Clone> DerefMut for DynImmediatePublisher<'a, T> { } /// An immediate publisher that holds a generic reference to the channel +#[derive(Debug)] pub struct ImmediatePublisher<'a, M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usize>( pub(super) ImmediatePub<'a, PubSubChannel, T>, ); @@ -229,6 +233,7 @@ impl<'a, M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: #[must_use = "Sinks do nothing unless polled"] /// [`futures_sink::Sink`] adapter for [`Pub`]. +#[derive(Debug)] pub struct PubSink<'a, 'p, PSB, T> where T: Clone, @@ -290,6 +295,7 @@ where /// Future for the publisher wait action #[must_use = "futures do nothing unless you `.await` or poll them"] +#[derive(Debug)] pub struct PublisherWaitFuture<'s, 'a, PSB: PubSubBehavior + ?Sized, T: Clone> { /// The message we need to publish message: Option, diff --git a/embassy-sync/src/pubsub/subscriber.rs b/embassy-sync/src/pubsub/subscriber.rs index 649382cf1..356de23f6 100644 --- a/embassy-sync/src/pubsub/subscriber.rs +++ b/embassy-sync/src/pubsub/subscriber.rs @@ -10,6 +10,7 @@ use super::{PubSubBehavior, PubSubChannel, WaitResult}; use crate::blocking_mutex::raw::RawMutex; /// A subscriber to a channel +#[derive(Debug)] pub struct Sub<'a, PSB: PubSubBehavior + ?Sized, T: Clone> { /// The message id of the next message we are yet to receive next_message_id: u64, @@ -151,6 +152,7 @@ impl<'a, T: Clone> DerefMut for DynSubscriber<'a, T> { } /// A subscriber that holds a generic reference to the channel +#[derive(Debug)] pub struct Subscriber<'a, M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usize>( pub(super) Sub<'a, PubSubChannel, T>, ); @@ -175,6 +177,7 @@ impl<'a, M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: /// Future for the subscriber wait action #[must_use = "futures do nothing unless you `.await` or poll them"] +#[derive(Debug)] pub struct SubscriberWaitFuture<'s, 'a, PSB: PubSubBehavior + ?Sized, T: Clone> { subscriber: &'s mut Sub<'a, PSB, T>, } diff --git a/embassy-sync/src/ring_buffer.rs b/embassy-sync/src/ring_buffer.rs index 81e60c42b..f03b7dd8f 100644 --- a/embassy-sync/src/ring_buffer.rs +++ b/embassy-sync/src/ring_buffer.rs @@ -1,5 +1,6 @@ use core::ops::Range; +#[derive(Debug)] pub struct RingBuffer { start: usize, end: usize, diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs index deeadd167..0d784a7dc 100644 --- a/embassy-sync/src/rwlock.rs +++ b/embassy-sync/src/rwlock.rs @@ -16,6 +16,7 @@ use crate::waitqueue::WakerRegistration; #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct TryLockError; +#[derive(Debug)] struct State { readers: usize, writer: bool, diff --git a/embassy-sync/src/semaphore.rs b/embassy-sync/src/semaphore.rs index d30eee30b..4e82b0fcd 100644 --- a/embassy-sync/src/semaphore.rs +++ b/embassy-sync/src/semaphore.rs @@ -46,6 +46,7 @@ pub trait Semaphore: Sized { /// A representation of a number of acquired permits. /// /// The acquired permits will be released back to the [`Semaphore`] when this is dropped. +#[derive(Debug)] pub struct SemaphoreReleaser<'a, S: Semaphore> { semaphore: &'a S, permits: usize, @@ -181,6 +182,7 @@ impl Semaphore for GreedySemaphore { } } +#[derive(Debug)] struct SemaphoreState { permits: usize, waker: WakerRegistration, @@ -221,6 +223,7 @@ impl SemaphoreState { /// /// Up to `N` tasks may attempt to acquire permits concurrently. If additional /// tasks attempt to acquire a permit, a [`WaitQueueFull`] error will be returned. +#[derive(Debug)] pub struct FairSemaphore where M: RawMutex, @@ -341,6 +344,7 @@ impl Semaphore for FairSemaphore { } } +#[derive(Debug)] struct FairAcquire<'a, M: RawMutex, const N: usize> { sema: &'a FairSemaphore, permits: usize, @@ -364,6 +368,7 @@ impl<'a, M: RawMutex, const N: usize> core::future::Future for FairAcquire<'a, M } } +#[derive(Debug)] struct FairAcquireAll<'a, M: RawMutex, const N: usize> { sema: &'a FairSemaphore, min: usize, @@ -387,6 +392,7 @@ impl<'a, M: RawMutex, const N: usize> core::future::Future for FairAcquireAll<'a } } +#[derive(Debug)] struct FairSemaphoreState { permits: usize, next_ticket: usize, diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs index e7095401e..d96e36245 100644 --- a/embassy-sync/src/signal.rs +++ b/embassy-sync/src/signal.rs @@ -39,6 +39,7 @@ where state: Mutex>>, } +#[derive(Debug)] enum State { None, Waiting(Waker), diff --git a/embassy-sync/src/waitqueue/atomic_waker_turbo.rs b/embassy-sync/src/waitqueue/atomic_waker_turbo.rs index c06b83056..a45adeab8 100644 --- a/embassy-sync/src/waitqueue/atomic_waker_turbo.rs +++ b/embassy-sync/src/waitqueue/atomic_waker_turbo.rs @@ -7,6 +7,7 @@ use core::task::Waker; /// If a waker is registered, registering another waker will replace the previous one without waking it. /// The intended use case is to wake tasks from interrupts. Therefore, it is generally not expected, /// that multiple tasks register try to register a waker simultaneously. +#[derive(Debug)] pub struct AtomicWaker { waker: AtomicPtr<()>, } diff --git a/embassy-sync/src/waitqueue/multi_waker.rs b/embassy-sync/src/waitqueue/multi_waker.rs index 1c05f8eaf..56c0cd1b2 100644 --- a/embassy-sync/src/waitqueue/multi_waker.rs +++ b/embassy-sync/src/waitqueue/multi_waker.rs @@ -5,6 +5,7 @@ use heapless::Vec; /// Utility struct to register and wake multiple wakers. /// Queue of wakers with a maximum length of `N`. /// Intended for waking multiple tasks. +#[derive(Debug)] pub struct MultiWakerRegistration { wakers: Vec, } diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index 08d6a833d..332ab5405 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -65,10 +65,12 @@ use crate::waitqueue::MultiWakerRegistration; /// }; /// block_on(f); /// ``` +#[derive(Debug)] pub struct Watch { mutex: Mutex>>, } +#[derive(Debug)] struct WatchState { data: Option, current_id: u64, @@ -392,6 +394,7 @@ impl Watch { } /// A receiver can `.await` a change in the `Watch` value. +#[derive(Debug)] pub struct Snd<'a, T: Clone, W: WatchBehavior + ?Sized> { watch: &'a W, _phantom: PhantomData, @@ -467,6 +470,7 @@ impl<'a, T: Clone, W: WatchBehavior + ?Sized> Snd<'a, T, W> { /// /// For a simpler type definition, consider [`DynSender`] at the expense of /// some runtime performance due to dynamic dispatch. +#[derive(Debug)] pub struct Sender<'a, M: RawMutex, T: Clone, const N: usize>(Snd<'a, T, Watch>); impl<'a, M: RawMutex, T: Clone, const N: usize> Clone for Sender<'a, M, T, N> { @@ -622,6 +626,7 @@ impl<'a, T: Clone, W: WatchBehavior + ?Sized> Drop for Rcv<'a, T, W> { } /// A anonymous receiver can NOT `.await` a change in the `Watch` value. +#[derive(Debug)] pub struct AnonRcv<'a, T: Clone, W: WatchBehavior + ?Sized> { watch: &'a W, at_id: u64, @@ -726,6 +731,7 @@ impl<'a, T: Clone> DerefMut for DynReceiver<'a, T> { } /// A receiver of a `Watch` channel that cannot `.await` values. +#[derive(Debug)] pub struct AnonReceiver<'a, M: RawMutex, T: Clone, const N: usize>(AnonRcv<'a, T, Watch>); impl<'a, M: RawMutex, T: Clone, const N: usize> AnonReceiver<'a, M, T, N> { diff --git a/embassy-sync/src/zerocopy_channel.rs b/embassy-sync/src/zerocopy_channel.rs index e3e5b2538..b3f7dbe8c 100644 --- a/embassy-sync/src/zerocopy_channel.rs +++ b/embassy-sync/src/zerocopy_channel.rs @@ -34,6 +34,7 @@ use crate::waitqueue::WakerRegistration; /// /// The channel requires a buffer of recyclable elements. Writing to the channel is done through /// an `&mut T`. +#[derive(Debug)] pub struct Channel<'a, M: RawMutex, T> { buf: BufferPtr, phantom: PhantomData<&'a mut T>, @@ -95,6 +96,7 @@ impl<'a, M: RawMutex, T> Channel<'a, M, T> { } #[repr(transparent)] +#[derive(Debug)] struct BufferPtr(*mut T); impl BufferPtr { @@ -107,6 +109,7 @@ unsafe impl Send for BufferPtr {} unsafe impl Sync for BufferPtr {} /// Send-only access to a [`Channel`]. +#[derive(Debug)] pub struct Sender<'a, M: RawMutex, T> { channel: &'a Channel<'a, M, T>, } @@ -190,6 +193,7 @@ impl<'a, M: RawMutex, T> Sender<'a, M, T> { } /// Receive-only access to a [`Channel`]. +#[derive(Debug)] pub struct Receiver<'a, M: RawMutex, T> { channel: &'a Channel<'a, M, T>, } @@ -272,6 +276,7 @@ impl<'a, M: RawMutex, T> Receiver<'a, M, T> { } } +#[derive(Debug)] struct State { /// Maximum number of elements the channel can hold. capacity: usize,