Path: blob/main/crates/bevy_platform/src/time/fallback.rs
6849 views
//! Provides a fallback implementation of `Instant` from the standard library.12#![expect(3unsafe_code,4reason = "Instant fallback requires unsafe to allow users to update the internal value"5)]67use crate::sync::atomic::{AtomicPtr, Ordering};89use core::{10fmt,11ops::{Add, AddAssign, Sub, SubAssign},12time::Duration,13};1415static ELAPSED_GETTER: AtomicPtr<()> = AtomicPtr::new(unset_getter as *mut _);1617/// Fallback implementation of `Instant` suitable for a `no_std` environment.18///19/// If you are on any of the following target architectures, this is a drop-in replacement:20///21/// - `x86`22/// - `x86_64`23/// - `aarch64`24///25/// On any other architecture, you must call [`Instant::set_elapsed`], providing a method26/// which when called supplies a monotonically increasing count of elapsed nanoseconds relative27/// to some arbitrary point in time.28#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]29pub struct Instant(Duration);3031impl Instant {32/// Returns an instant corresponding to "now".33#[must_use]34pub fn now() -> Instant {35let getter = ELAPSED_GETTER.load(Ordering::Acquire);3637// SAFETY: Function pointer is always valid38let getter = unsafe { core::mem::transmute::<*mut (), fn() -> Duration>(getter) };3940Self((getter)())41}4243/// Provides a function returning the amount of time that has elapsed since execution began.44/// The getter provided to this method will be used by [`now`](Instant::now).45///46/// # Safety47///48/// - The function provided must accurately represent the elapsed time.49/// - The function must preserve all invariants of the [`Instant`] type.50/// - The pointer to the function must be valid whenever [`Instant::now`] is called.51pub unsafe fn set_elapsed(getter: fn() -> Duration) {52ELAPSED_GETTER.store(getter as *mut _, Ordering::Release);53}5455/// Returns the amount of time elapsed from another instant to this one,56/// or zero duration if that instant is later than this one.57#[must_use]58pub fn duration_since(&self, earlier: Instant) -> Duration {59self.saturating_duration_since(earlier)60}6162/// Returns the amount of time elapsed from another instant to this one,63/// or None if that instant is later than this one.64///65/// Due to monotonicity bugs, even under correct logical ordering of the passed `Instant`s,66/// this method can return `None`.67#[must_use]68pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {69self.0.checked_sub(earlier.0)70}7172/// Returns the amount of time elapsed from another instant to this one,73/// or zero duration if that instant is later than this one.74#[must_use]75pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {76self.0.saturating_sub(earlier.0)77}7879/// Returns the amount of time elapsed since this instant.80#[must_use]81pub fn elapsed(&self) -> Duration {82Instant::now().saturating_duration_since(*self)83}8485/// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as86/// `Instant` (which means it's inside the bounds of the underlying data structure), `None`87/// otherwise.88pub fn checked_add(&self, duration: Duration) -> Option<Instant> {89self.0.checked_add(duration).map(Instant)90}9192/// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as93/// `Instant` (which means it's inside the bounds of the underlying data structure), `None`94/// otherwise.95pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {96self.0.checked_sub(duration).map(Instant)97}98}99100impl Add<Duration> for Instant {101type Output = Instant;102103/// # Panics104///105/// This function may panic if the resulting point in time cannot be represented by the106/// underlying data structure. See [`Instant::checked_add`] for a version without panic.107fn add(self, other: Duration) -> Instant {108self.checked_add(other)109.expect("overflow when adding duration to instant")110}111}112113impl AddAssign<Duration> for Instant {114fn add_assign(&mut self, other: Duration) {115*self = *self + other;116}117}118119impl Sub<Duration> for Instant {120type Output = Instant;121122fn sub(self, other: Duration) -> Instant {123self.checked_sub(other)124.expect("overflow when subtracting duration from instant")125}126}127128impl SubAssign<Duration> for Instant {129fn sub_assign(&mut self, other: Duration) {130*self = *self - other;131}132}133134impl Sub<Instant> for Instant {135type Output = Duration;136137/// Returns the amount of time elapsed from another instant to this one,138/// or zero duration if that instant is later than this one.139fn sub(self, other: Instant) -> Duration {140self.duration_since(other)141}142}143144impl fmt::Debug for Instant {145fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {146self.0.fmt(f)147}148}149150fn unset_getter() -> Duration {151crate::cfg::switch! {152#[cfg(target_arch = "x86")] => {153// SAFETY: standard technique for getting a nanosecond counter on x86154let nanos = unsafe {155core::arch::x86::_rdtsc()156};157Duration::from_nanos(nanos)158}159#[cfg(target_arch = "x86_64")] => {160// SAFETY: standard technique for getting a nanosecond counter on x86_64161let nanos = unsafe {162core::arch::x86_64::_rdtsc()163};164Duration::from_nanos(nanos)165}166#[cfg(target_arch = "aarch64")] => {167// SAFETY: standard technique for getting a nanosecond counter of aarch64168let nanos = unsafe {169let mut ticks: u64;170core::arch::asm!("mrs {}, cntvct_el0", out(reg) ticks);171ticks172};173Duration::from_nanos(nanos)174}175_ => {176panic!("An elapsed time getter has not been provided to `Instant`. Please use `Instant::set_elapsed(...)` before calling `Instant::now()`")177}178}179}180181182