Vendor dependencies

This commit is contained in:
2026-08-01 16:11:49 +03:00
parent 7f139a0241
commit 6b5e7f0f8b
29706 changed files with 9575646 additions and 0 deletions
@@ -0,0 +1,57 @@
use crate::common::time::Instant;
use portable_atomic::AtomicU64;
use std::sync::atomic::Ordering;
/// `AtomicInstant` is a wrapper around `AtomicU64` that provides thread-safe access
/// to an `Instant`.
///
/// `u64::MAX` is used to represent an unset `Instant`.
#[derive(Debug)]
pub(crate) struct AtomicInstant {
instant: AtomicU64,
}
impl Default for AtomicInstant {
/// Creates a new `AtomicInstant` with an unset `Instant`.
fn default() -> Self {
Self {
instant: AtomicU64::new(u64::MAX),
}
}
}
impl AtomicInstant {
/// Creates a new `AtomicInstant` with the given `Instant`.
pub(crate) fn new(instant: Instant) -> Self {
// Ensure the `Instant` is not `u64::MAX`, which means unset.
debug_assert!(instant.as_nanos() != u64::MAX);
Self {
instant: AtomicU64::new(instant.as_nanos()),
}
}
/// Returns `true` if the `Instant` is set.
pub(crate) fn is_set(&self) -> bool {
self.instant.load(Ordering::Acquire) != u64::MAX
}
/// Returns the `Instant` if it is set, otherwise `None`.
pub(crate) fn instant(&self) -> Option<Instant> {
let ts = self.instant.load(Ordering::Acquire);
if ts == u64::MAX {
None
} else {
Some(Instant::from_nanos(ts))
}
}
/// Sets the `Instant`.
pub(crate) fn set_instant(&self, instant: Instant) {
// Ensure the `Instant` is not `u64::MAX`, which means unset.
debug_assert!(instant.as_nanos() != u64::MAX);
self.instant.store(instant.as_nanos(), Ordering::Release);
}
}
+166
View File
@@ -0,0 +1,166 @@
use std::time::{Duration, Instant as StdInstant};
#[cfg(test)]
use std::sync::Arc;
#[cfg(test)]
use parking_lot::RwLock;
// This is `moka`'s `Instant` struct.
use super::Instant;
#[derive(Default, Clone)]
pub(crate) struct Clock {
ty: ClockType,
}
#[derive(Clone)]
enum ClockType {
/// A clock that uses `std::time::Instant` as the source of time.
Standard { origin: StdInstant },
#[cfg(feature = "quanta")]
/// A clock that uses both `std::time::Instant` and `quanta::Instant` as the
/// sources of time.
Hybrid {
std_origin: StdInstant,
quanta_origin: quanta::Instant,
},
#[cfg(test)]
/// A clock that uses a mocked source of time.
Mocked { mock: Arc<Mock> },
}
impl Default for ClockType {
/// Create a new `ClockType` with the current time as the origin.
///
/// If the `quanta` feature is enabled, `Hybrid` will be used. Otherwise,
/// `Standard` will be used.
fn default() -> Self {
#[cfg(feature = "quanta")]
{
return ClockType::Hybrid {
std_origin: StdInstant::now(),
quanta_origin: quanta::Instant::now(),
};
}
#[allow(unreachable_code)]
ClockType::Standard {
origin: StdInstant::now(),
}
}
}
impl Clock {
#[cfg(test)]
/// Creates a new `Clock` with a mocked source of time.
pub(crate) fn mock() -> (Clock, Arc<Mock>) {
let mock = Arc::new(Mock::default());
let clock = Clock {
ty: ClockType::Mocked {
mock: Arc::clone(&mock),
},
};
(clock, mock)
}
/// Returns the current time using a reliable source of time.
///
/// When the type is `Standard` or `Hybrid`, the time is based on
/// `std::time::Instant`. When the type is `Mocked`, the time is based on the
/// mocked source of time.
pub(crate) fn now(&self) -> Instant {
match &self.ty {
ClockType::Standard { origin } => {
Instant::from_duration_since_clock_start(origin.elapsed())
}
#[cfg(feature = "quanta")]
ClockType::Hybrid { std_origin, .. } => {
Instant::from_duration_since_clock_start(std_origin.elapsed())
}
#[cfg(test)]
ClockType::Mocked { mock } => Instant::from_duration_since_clock_start(mock.elapsed()),
}
}
/// Returns the current time _maybe_ using a fast but less reliable source of
/// time. The time may drift from the time returned by `now`, or not be
/// monotonically increasing.
///
/// This is useful for performance critical code that does not require the same
/// level of precision as `now`. (e.g. measuring the time between two events for
/// metrics)
///
/// When the type is `Standard` or `Mocked`, `now` is internally called. So there
/// is no performance benefit.
///
/// When the type is `Hybrid`, the time is based on `quanta::Instant`, which can
/// be faster than `std::time::Instant`, depending on the CPU architecture.
pub(crate) fn fast_now(&self) -> Instant {
match &self.ty {
#[cfg(feature = "quanta")]
ClockType::Hybrid { quanta_origin, .. } => {
Instant::from_duration_since_clock_start(quanta_origin.elapsed())
}
ClockType::Standard { .. } => self.now(),
#[cfg(test)]
ClockType::Mocked { .. } => self.now(),
}
}
/// Converts an `Instant` to a `std::time::Instant`.
///
/// **IMPORTANT**: The caller must ensure that the `Instant` was created by this
/// `Clock`, otherwise the resulting `std::time::Instant` will be incorrect.
pub(crate) fn to_std_instant(&self, instant: Instant) -> StdInstant {
match &self.ty {
ClockType::Standard { origin } => {
let duration = Duration::from_nanos(instant.as_nanos());
*origin + duration
}
#[cfg(feature = "quanta")]
ClockType::Hybrid { std_origin, .. } => {
let duration = Duration::from_nanos(instant.as_nanos());
*std_origin + duration
}
#[cfg(test)]
ClockType::Mocked { mock } => {
let duration = Duration::from_nanos(instant.as_nanos());
// https://github.com/moka-rs/moka/issues/487
//
// This `dbg!` will workaround an incorrect compilation by Rust
// 1.84.0 for the armv7-unknown-linux-musleabihf target in the
// release build of the tests.
dbg!(mock.origin + duration)
}
}
}
}
#[cfg(test)]
pub(crate) struct Mock {
origin: StdInstant,
now: RwLock<StdInstant>,
}
#[cfg(test)]
impl Default for Mock {
fn default() -> Self {
let origin = StdInstant::now();
Self {
origin,
now: RwLock::new(origin),
}
}
}
#[cfg(test)]
impl Mock {
pub(crate) fn increment(&self, amount: Duration) {
*self.now.write() += amount;
}
pub(crate) fn elapsed(&self) -> Duration {
self.now.read().duration_since(self.origin)
}
}
+80
View File
@@ -0,0 +1,80 @@
use std::time::Duration;
pub(crate) const MAX_NANOS: u64 = u64::MAX - 1;
/// `Instant` represents a point in time since the `Clock` was created. It has
/// nanosecond precision.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct Instant {
elapsed_ns: u64,
}
impl Instant {
pub(crate) fn from_nanos(nanos: u64) -> Instant {
debug_assert!(nanos <= MAX_NANOS);
Instant { elapsed_ns: nanos }
}
pub(crate) fn from_duration_since_clock_start(duration: Duration) -> Instant {
Instant::from_nanos(Self::duration_to_saturating_nanoseconds(duration))
}
pub(crate) fn as_nanos(&self) -> u64 {
self.elapsed_ns
}
/// Converts a `std::time::Duration` to nanoseconds, saturating to
/// `MAX_NANOSECONDS` (`u64::MAX - 1`) if the duration is too large.
/// (`Duration::as_nanos` returns `u128`)
///
/// Note that `u64::MAX - 1` is used here instead of `u64::MAX` because
/// `u64::MAX` is used by `moka`'s `AtomicTime` to indicate the time is unset.
pub(crate) fn duration_to_saturating_nanoseconds(duration: Duration) -> u64 {
u64::try_from(duration.as_nanos())
.map(|n| n.min(MAX_NANOS))
.unwrap_or(MAX_NANOS)
}
pub(crate) fn saturating_add(&self, duration: Duration) -> Instant {
let dur_ms = Self::duration_to_saturating_nanoseconds(duration);
Instant::from_nanos(self.elapsed_ns.saturating_add(dur_ms).min(MAX_NANOS))
}
pub(crate) fn saturating_duration_since(&self, earlier: Self) -> Duration
where
Self: Sized,
{
Duration::from_nanos(self.elapsed_ns.saturating_sub(earlier.elapsed_ns))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_saturating_add() {
let instant = Instant::from_nanos(100_000);
let duration = Duration::from_nanos(50_000);
let result = instant.saturating_add(duration);
assert_eq!(result, Instant::from_nanos(150_000));
let instant = Instant::from_nanos(u64::MAX - 10_000);
let duration = Duration::from_nanos(12_000);
let result = instant.saturating_add(duration);
assert_eq!(result, Instant::from_nanos(u64::MAX - 1));
}
#[test]
fn test_saturating_duration_since() {
let instant = Instant::from_nanos(100_000);
let earlier = Instant::from_nanos(60_000);
let result = instant.saturating_duration_since(earlier);
assert_eq!(result, Duration::from_nanos(40_000));
let instant = Instant::from_nanos(60_000);
let earlier = Instant::from_nanos(100_000);
let result = instant.saturating_duration_since(earlier);
assert_eq!(result, Duration::ZERO);
}
}