cordyceps/
util.rs

1use core::fmt;
2
3#[cfg(target_has_atomic = "ptr")]
4pub(crate) use has_cas_atomics::*;
5
6#[cfg(target_has_atomic = "ptr")]
7mod has_cas_atomics {
8    use core::{
9        fmt,
10        ops::{Deref, DerefMut},
11    };
12
13    /// An exponential backoff for spin loops
14    #[derive(Debug, Clone)]
15    pub(crate) struct Backoff {
16        exp: u8,
17        max: u8,
18    }
19
20    pub(crate) use cache_pad::CachePadded;
21
22    /// When configured not to pad to cache alignment, just provide a no-op wrapper struct
23    /// This feature is useful for platforms with no data cache, such as many Cortex-M
24    /// targets.
25    #[cfg(feature = "no-cache-pad")]
26    mod cache_pad {
27        #[derive(Clone, Copy, Default, Hash, PartialEq, Eq)]
28        pub(crate) struct CachePadded<T>(pub(crate) T);
29    }
30
31    /// When not inhibited, determine cache alignment based on target architecture.
32    /// Align to 128 bytes on 64-bit x86/ARM targets, otherwise align to 64 bytes.
33    #[cfg(not(feature = "no-cache-pad"))]
34    mod cache_pad {
35        #[cfg_attr(any(target_arch = "x86_64", target_arch = "aarch64"), repr(align(128)))]
36        #[cfg_attr(
37            not(any(target_arch = "x86_64", target_arch = "aarch64")),
38            repr(align(64))
39        )]
40        #[derive(Clone, Copy, Default, Hash, PartialEq, Eq)]
41        pub(crate) struct CachePadded<T>(pub(crate) T);
42    }
43
44    // === impl Backoff ===
45
46    impl Backoff {
47        pub(crate) const DEFAULT_MAX_EXPONENT: u8 = 8;
48
49        pub(crate) const fn new() -> Self {
50            Self {
51                exp: 0,
52                max: Self::DEFAULT_MAX_EXPONENT,
53            }
54        }
55
56        /// Returns a new exponential backoff with the provided max exponent.
57        #[allow(dead_code)]
58        pub(crate) fn with_max_exponent(max: u8) -> Self {
59            assert!(max <= Self::DEFAULT_MAX_EXPONENT);
60            Self { exp: 0, max }
61        }
62
63        /// Perform one spin, squarin the backoff
64        #[inline(always)]
65        pub(crate) fn spin(&mut self) {
66            use crate::loom::hint;
67
68            // Issue 2^exp pause instructions.
69            for _ in 0..(1 << self.exp) {
70                hint::spin_loop();
71            }
72
73            if self.exp < self.max {
74                self.exp += 1
75            }
76        }
77    }
78
79    impl Default for Backoff {
80        fn default() -> Self {
81            Self::new()
82        }
83    }
84
85    // === impl CachePadded ===
86
87    impl<T> Deref for CachePadded<T> {
88        type Target = T;
89
90        #[inline]
91        fn deref(&self) -> &T {
92            &self.0
93        }
94    }
95
96    impl<T> DerefMut for CachePadded<T> {
97        #[inline]
98        fn deref_mut(&mut self) -> &mut T {
99            &mut self.0
100        }
101    }
102
103    impl<T: fmt::Debug> fmt::Debug for CachePadded<T> {
104        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105            self.0.fmt(f)
106        }
107    }
108}
109
110macro_rules! test_trace {
111    ($($tt:tt)*) => {
112        #[cfg(test)]
113        tracing::trace!($($tt)*)
114    }
115}
116
117pub(crate) struct FmtOption<'a, T> {
118    opt: Option<&'a T>,
119    or_else: &'a str,
120}
121
122// === impl FmtOption ===
123
124impl<'a, T> FmtOption<'a, T> {
125    pub(crate) fn new(opt: &'a Option<T>) -> Self {
126        Self {
127            opt: opt.as_ref(),
128            or_else: "None",
129        }
130    }
131}
132
133impl<T: fmt::Debug> fmt::Debug for FmtOption<'_, T> {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        match self.opt {
136            Some(val) => val.fmt(f),
137            None => f.write_str(self.or_else),
138        }
139    }
140}
141
142impl<T: fmt::Display> fmt::Display for FmtOption<'_, T> {
143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144        match self.opt {
145            Some(val) => val.fmt(f),
146            None => f.write_str(self.or_else),
147        }
148    }
149}
150
151#[cfg(test)]
152pub(crate) fn assert_send_sync<T: Send + Sync>() {}