diff options
author | Andreu Botella <andreu@andreubotella.com> | 2022-02-15 12:17:30 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-15 12:17:30 +0100 |
commit | 760f4c9e2427e87815a8e59b0807693c8dcb623a (patch) | |
tree | cb04b2b42cfcf1fc46d74a3e4c7f86c73491d2b0 /ext/web/timers.rs | |
parent | 5e845442fade02cd12d13e74222b26e217c5971d (diff) |
chore(ext/timers): move ext/timers to ext/web (#13665)
Diffstat (limited to 'ext/web/timers.rs')
-rw-r--r-- | ext/web/timers.rs | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/ext/web/timers.rs b/ext/web/timers.rs new file mode 100644 index 000000000..7f17aa969 --- /dev/null +++ b/ext/web/timers.rs @@ -0,0 +1,103 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. + +//! This module helps deno implement timers and performance APIs. + +use deno_core::error::AnyError; +use deno_core::CancelFuture; +use deno_core::CancelHandle; +use deno_core::OpState; +use deno_core::Resource; +use deno_core::ResourceId; +use std::borrow::Cow; +use std::cell::RefCell; +use std::rc::Rc; +use std::time::Duration; +use std::time::Instant; + +pub trait TimersPermission { + fn allow_hrtime(&mut self) -> bool; + fn check_unstable(&self, state: &OpState, api_name: &'static str); +} + +pub type StartTime = Instant; + +// Returns a milliseconds and nanoseconds subsec +// since the start time of the deno runtime. +// If the High precision flag is not set, the +// nanoseconds are rounded on 2ms. +pub fn op_now<TP>( + state: &mut OpState, + _argument: (), + _: (), +) -> Result<f64, AnyError> +where + TP: TimersPermission + 'static, +{ + let start_time = state.borrow::<StartTime>(); + let seconds = start_time.elapsed().as_secs(); + let mut subsec_nanos = start_time.elapsed().subsec_nanos() as f64; + let reduced_time_precision = 2_000_000.0; // 2ms in nanoseconds + + // If the permission is not enabled + // Round the nano result on 2 milliseconds + // see: https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#Reduced_time_precision + if !state.borrow_mut::<TP>().allow_hrtime() { + subsec_nanos -= subsec_nanos % reduced_time_precision; + } + + let result = (seconds * 1_000) as f64 + (subsec_nanos / 1_000_000.0); + + Ok(result) +} + +pub struct TimerHandle(Rc<CancelHandle>); + +impl Resource for TimerHandle { + fn name(&self) -> Cow<str> { + "timer".into() + } + + fn close(self: Rc<Self>) { + self.0.cancel(); + } +} + +/// Creates a [`TimerHandle`] resource that can be used to cancel invocations of +/// [`op_sleep`]. +pub fn op_timer_handle( + state: &mut OpState, + _: (), + _: (), +) -> Result<ResourceId, AnyError> { + let rid = state + .resource_table + .add(TimerHandle(CancelHandle::new_rc())); + Ok(rid) +} + +/// Waits asynchronously until either `millis` milliseconds have passed or the +/// [`TimerHandle`] resource given by `rid` has been canceled. +pub async fn op_sleep( + state: Rc<RefCell<OpState>>, + millis: u64, + rid: ResourceId, +) -> Result<(), AnyError> { + let handle = state.borrow().resource_table.get::<TimerHandle>(rid)?; + tokio::time::sleep(Duration::from_millis(millis)) + .or_cancel(handle.0.clone()) + .await?; + Ok(()) +} + +pub fn op_sleep_sync<TP>( + state: &mut OpState, + millis: u64, + _: (), +) -> Result<(), AnyError> +where + TP: TimersPermission + 'static, +{ + state.borrow::<TP>().check_unstable(state, "Deno.sleepSync"); + std::thread::sleep(Duration::from_millis(millis)); + Ok(()) +} |