Merge pull request #4570 from U007D/sync-debug

`embassy-sync` `Debug` impls
This commit is contained in:
Ulf Lilleengen 2025-08-20 06:54:29 +00:00 committed by GitHub
commit 63ade38930
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 65 additions and 0 deletions

View File

@ -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

View File

@ -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<R, T: ?Sized> {
// NOTE: `raw` must be FIRST, so when using ThreadModeMutex the "can't drop in non-thread-mode" gets
// to run BEFORE dropping `data`.

View File

@ -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 ()>,
}

View File

@ -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<ReceiveFuture<'ch, M, T, N>> 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<T> {
Full(T),
}
#[derive(Debug)]
struct ChannelState<T, const N: usize> {
queue: Deque<T, N>,
receiver_waker: WakerRegistration,
@ -785,6 +791,7 @@ impl<T, const N: usize> ChannelState<T, N> {
/// received from the channel.
///
/// All data sent will become available in the same order as it was sent.
#[derive(Debug)]
pub struct Channel<M, T, const N: usize>
where
M: RawMutex,

View File

@ -21,6 +21,7 @@ use core::sync::atomic::{AtomicBool, Ordering};
/// let reference = VALUE.get();
/// assert_eq!(reference, &20);
/// ```
#[derive(Debug)]
pub struct LazyLock<T, F = fn() -> T> {
init: AtomicBool,
data: UnsafeCell<Data<T, F>>,
@ -144,6 +145,7 @@ mod tests {
}
static DROP_CHECKER: AtomicU32 = AtomicU32::new(0);
#[derive(Debug)]
struct DropCheck;
impl Drop for DropCheck {

View File

@ -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,

View File

@ -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<T> {
data: Cell<MaybeUninit<T>>,
}
impl<T> Debug for OnceLock<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("OnceLock")
.field("init", &self.init)
.field("data", &"Cell<MaybeUninit<{unprintable}>>")
.finish()
}
}
unsafe impl<T> Sync for OnceLock<T> where T: Sync {}
impl<T> OnceLock<T> {

View File

@ -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<const N: usize> {
buffer: RingBuffer<N>,
read_waker: WakerRegistration,
@ -206,6 +212,7 @@ struct PipeState<const N: usize> {
}
#[repr(transparent)]
#[derive(Debug)]
struct Buffer<const N: usize>(UnsafeCell<[u8; N]>);
impl<const N: usize> Buffer<N> {
@ -230,6 +237,7 @@ unsafe impl<const N: usize> Sync for Buffer<N> {}
/// 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<M, const N: usize>
where
M: RawMutex,

View File

@ -71,6 +71,7 @@ pub use subscriber::{DynSubscriber, Subscriber};
/// # block_on(test);
/// ```
///
#[derive(Debug)]
pub struct PubSubChannel<M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usize> {
inner: Mutex<M, RefCell<PubSubState<T, CAP, SUBS, PUBS>>>,
}
@ -297,6 +298,7 @@ impl<M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usi
}
/// Internal state for the PubSub channel
#[derive(Debug)]
struct PubSubState<T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usize> {
/// 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>,

View File

@ -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<T> + ?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<M, T, CAP, SUBS, PUBS>, 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<T> + ?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<M, T, CAP, SUBS, PUBS>, 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<T> + ?Sized, T: Clone> {
/// The message we need to publish
message: Option<T>,

View File

@ -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<T> + ?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<M, T, CAP, SUBS, PUBS>, 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<T> + ?Sized, T: Clone> {
subscriber: &'s mut Sub<'a, PSB, T>,
}

View File

@ -1,5 +1,6 @@
use core::ops::Range;
#[derive(Debug)]
pub struct RingBuffer<const N: usize> {
start: usize,
end: usize,

View File

@ -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,

View File

@ -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<M: RawMutex> Semaphore for GreedySemaphore<M> {
}
}
#[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<M, const N: usize>
where
M: RawMutex,
@ -341,6 +344,7 @@ impl<M: RawMutex, const N: usize> Semaphore for FairSemaphore<M, N> {
}
}
#[derive(Debug)]
struct FairAcquire<'a, M: RawMutex, const N: usize> {
sema: &'a FairSemaphore<M, N>,
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<M, N>,
min: usize,
@ -387,6 +392,7 @@ impl<'a, M: RawMutex, const N: usize> core::future::Future for FairAcquireAll<'a
}
}
#[derive(Debug)]
struct FairSemaphoreState<const N: usize> {
permits: usize,
next_ticket: usize,

View File

@ -39,6 +39,7 @@ where
state: Mutex<M, Cell<State<T>>>,
}
#[derive(Debug)]
enum State<T> {
None,
Waiting(Waker),

View File

@ -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<()>,
}

View File

@ -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<const N: usize> {
wakers: Vec<Waker, N>,
}

View File

@ -65,10 +65,12 @@ use crate::waitqueue::MultiWakerRegistration;
/// };
/// block_on(f);
/// ```
#[derive(Debug)]
pub struct Watch<M: RawMutex, T: Clone, const N: usize> {
mutex: Mutex<M, RefCell<WatchState<T, N>>>,
}
#[derive(Debug)]
struct WatchState<T: Clone, const N: usize> {
data: Option<T>,
current_id: u64,
@ -392,6 +394,7 @@ impl<M: RawMutex, T: Clone, const N: usize> Watch<M, T, N> {
}
/// A receiver can `.await` a change in the `Watch` value.
#[derive(Debug)]
pub struct Snd<'a, T: Clone, W: WatchBehavior<T> + ?Sized> {
watch: &'a W,
_phantom: PhantomData<T>,
@ -467,6 +470,7 @@ impl<'a, T: Clone, W: WatchBehavior<T> + ?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<M, T, N>>);
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<T> + ?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<T> + ?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<M, T, N>>);
impl<'a, M: RawMutex, T: Clone, const N: usize> AnonReceiver<'a, M, T, N> {

View File

@ -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<T>,
phantom: PhantomData<&'a mut T>,
@ -95,6 +96,7 @@ impl<'a, M: RawMutex, T> Channel<'a, M, T> {
}
#[repr(transparent)]
#[derive(Debug)]
struct BufferPtr<T>(*mut T);
impl<T> BufferPtr<T> {
@ -107,6 +109,7 @@ unsafe impl<T> Send for BufferPtr<T> {}
unsafe impl<T> Sync for BufferPtr<T> {}
/// 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,