aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Vander Stoep <jeffv@google.com>2020-10-22 10:53:59 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-10-22 10:53:59 +0000
commit9c26b2d925413b5184f590bebe051b5deb5288c5 (patch)
treef6274f90892c0f9baa931546dcbbe0e24b54c863
parent86e10ee1b176558f0bed700530de57a0d81645ee (diff)
parent4b585e4bbcd5fba362c1fd14449608c4c121a36c (diff)
downloadinstant-9c26b2d925413b5184f590bebe051b5deb5288c5.tar.gz
Initial import of Instant crate am: 6b6c8e627b am: 4b585e4bbc
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/instant/+/1470142 Change-Id: Ice96fbab880cb3320e4d79acdf02682fb72e3740
-rw-r--r--.cargo_vcs_info.json5
-rw-r--r--.circleci/config.yml33
-rw-r--r--.gitignore12
-rw-r--r--AUTHORS2
-rw-r--r--Android.bp15
-rw-r--r--Cargo.toml84
-rw-r--r--LICENSE27
-rw-r--r--METADATA19
-rw-r--r--MODULE_LICENSE_BSD_LIKE0
-rw-r--r--OWNERS1
-rw-r--r--README.md124
-rw-r--r--src/lib.rs22
-rw-r--r--src/native.rs7
-rw-r--r--src/wasm.rs129
-rw-r--r--tests/wasm.rs46
15 files changed, 526 insertions, 0 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..bb7745e
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,5 @@
+{
+ "git": {
+ "sha1": "96feb8a208a8a7cd3c2d09afba3ba236821ba57b"
+ }
+}
diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 0000000..878e288
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,33 @@
+version: 2.1
+
+executors:
+ rust-executor:
+ docker:
+ - image: rust:latest
+
+jobs:
+ build:
+ executor: rust-executor
+ steps:
+ - checkout
+ - run:
+ name: install cargo-web
+ command: cargo install -f cargo-web;
+ - run:
+ name: build
+ command: cargo build --verbose;
+ - run:
+ name: build --features stdweb
+ command: cargo web build --verbose --target wasm32-unknown-unknown --features "stdweb";
+ - run:
+ name: build --features wasm-bindgen
+ command: cargo build --verbose --target wasm32-unknown-unknown --features "wasm-bindgen";
+ - run:
+ name: build --features now
+ command: cargo build --verbose --features now;
+ - run:
+ name: build --features now stdweb
+ command: cargo web build --verbose --target wasm32-unknown-unknown --features "now stdweb";
+ - run:
+ name: build --features now wasm-bindgen
+ command: cargo build --verbose --target wasm32-unknown-unknown --features "now wasm-bindgen"; \ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3722785
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+*.swp
+*.swo
+*.so
+*.rlib
+*.dSYM
+*.dylib
+cargo.lock
+Cargo.lock
+target
+.idea
+wasm-pack.log
+bin
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..6f2ad5b
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,2 @@
+Main developer:
+ * Sébastien Crozet <developer@crozet.re> \ No newline at end of file
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..c75dd0b
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,15 @@
+// This file is generated by cargo2android.py --run --device --dependencies.
+
+rust_library {
+ name: "libinstant",
+ host_supported: true,
+ crate_name: "instant",
+ srcs: ["src/lib.rs"],
+ edition: "2018",
+ rustlibs: [
+ "libcfg_if",
+ ],
+}
+
+// dependent_library ["feature_list"]
+// cfg-if-0.1.10
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..1031381
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,84 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+edition = "2018"
+name = "instant"
+version = "0.1.7"
+authors = ["sebcrozet <developer@crozet.re>"]
+description = "A partial replacement for std::time::Instant that works on WASM too."
+readme = "README.md"
+keywords = ["time", "wasm"]
+license = "BSD-3-Clause"
+repository = "https://github.com/sebcrozet/instant"
+[dependencies.cfg-if]
+version = "0.1"
+[dev-dependencies.wasm-bindgen-test]
+version = "0.2"
+
+[features]
+now = ["time"]
+wasm-bindgen = ["js-sys", "wasm-bindgen_rs", "web-sys"]
+[target.asmjs-unknown-emscripten.dependencies.js-sys]
+version = "0.3"
+optional = true
+
+[target.asmjs-unknown-emscripten.dependencies.stdweb]
+version = "0.4"
+optional = true
+
+[target.asmjs-unknown-emscripten.dependencies.wasm-bindgen_rs]
+version = "0.2"
+optional = true
+package = "wasm-bindgen"
+
+[target.asmjs-unknown-emscripten.dependencies.web-sys]
+version = "0.3"
+features = ["Window", "Performance", "PerformanceTiming"]
+optional = true
+[target."cfg(not(any(feature = \"stdweb\", feature = \"wasm-bindgen\")))".dependencies.time]
+version = "0.1"
+optional = true
+[target.wasm32-unknown-emscripten.dependencies.js-sys]
+version = "0.3"
+optional = true
+
+[target.wasm32-unknown-emscripten.dependencies.stdweb]
+version = "0.4"
+optional = true
+
+[target.wasm32-unknown-emscripten.dependencies.wasm-bindgen_rs]
+version = "0.2"
+optional = true
+package = "wasm-bindgen"
+
+[target.wasm32-unknown-emscripten.dependencies.web-sys]
+version = "0.3"
+features = ["Window", "Performance", "PerformanceTiming"]
+optional = true
+[target.wasm32-unknown-unknown.dependencies.js-sys]
+version = "0.3"
+optional = true
+
+[target.wasm32-unknown-unknown.dependencies.stdweb]
+version = "0.4"
+optional = true
+
+[target.wasm32-unknown-unknown.dependencies.wasm-bindgen_rs]
+version = "0.2"
+optional = true
+package = "wasm-bindgen"
+
+[target.wasm32-unknown-unknown.dependencies.web-sys]
+version = "0.3"
+features = ["Window", "Performance", "PerformanceTiming"]
+optional = true
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..a301457
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2019, Sébastien Crozet
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the author nor the names of its contributors may be used
+ to endorse or promote products derived from this software without specific
+ prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..0b7ab54
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,19 @@
+name: "instant"
+description: "A partial replacement for std::time::Instant that works on WASM too."
+third_party {
+ url {
+ type: HOMEPAGE
+ value: "https://crates.io/crates/instant"
+ }
+ url {
+ type: ARCHIVE
+ value: "https://static.crates.io/crates/instant/instant-0.1.7.crate"
+ }
+ version: "0.1.7"
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2020
+ month: 10
+ day: 20
+ }
+}
diff --git a/MODULE_LICENSE_BSD_LIKE b/MODULE_LICENSE_BSD_LIKE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_BSD_LIKE
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..46fc303
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+include platform/prebuilts/rust:/OWNERS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..28f6bdd
--- /dev/null
+++ b/README.md
@@ -0,0 +1,124 @@
+# Instant
+
+If you call `std::time::Instant::now()` on a WASM platform, it will panic. This crate provides a partial
+replacement for `std::time::Instant` that works on WASM too. This defines the type `instant::Instant` which is:
+
+* A struct emulating the behavior of **std::time::Instant** if you are targeting `wasm32-unknown-unknown` or `wasm32-unknown-asmjs`
+**and** you enabled either the `stdweb` or the `wasm-bindgen` feature. This emulation is based on the javascript `performance.now()` function.
+* A type alias for `std::time::Instant` otherwise.
+
+
+
+Note that even if the **stdweb** or **wasm-bindgen** feature is enabled, this crate will continue to rely on `std::time::Instant`
+as long as you are not targeting wasm32. This allows for portable code that will work on both native and WASM platforms.
+
+### The feature `now`.
+By enabling the feature `now` the function `instant::now()` will be exported and will either:
+
+* Call `performance.now()` when compiling for a WASM platform with the features **stdweb** or **wasm-bindgen** enabled, or using a custom javascript function.
+* Call `time::precise_time_s() * 1000.0` otherwise.
+
+The result is expressed in milliseconds.
+
+## Examples
+### Using `instant` for a native platform.
+_Cargo.toml_:
+```toml
+[dependencies]
+instant = "0.1"
+```
+
+_main.rs_:
+```rust
+fn main() {
+ // Will be the same as `std::time::Instant`.
+ let now = instant::Instant::new();
+}
+```
+
+-----
+
+### Using `instant` for a WASM platform.
+This example shows the use of the `stdweb` feature. It would be similar with `wasm-bindgen`.
+
+_Cargo.toml_:
+```toml
+[dependencies]
+instant = { version = "0.1", features = [ "stdweb" ] }
+```
+
+_main.rs_:
+```rust
+fn main() {
+ // Will emulate `std::time::Instant` based on `performance.now()`.
+ let now = instant::Instant::new();
+}
+```
+
+-----
+
+### Using `instant` for any platform enabling a feature transitively.
+_Cargo.toml_:
+```toml
+[features]
+stdweb = [ "instant/stdweb" ]
+wasm-bindgen = [ "instant/wasm-bindgen" ]
+
+[dependencies]
+instant = "0.1"
+```
+
+_lib.rs_:
+```rust
+fn my_function() {
+ // Will select the proper implementation depending on the
+ // feature selected by the user.
+ let now = instant::Instant::new();
+}
+```
+
+-----
+
+### Using the feature `now`.
+_Cargo.toml_:
+```toml
+[features]
+stdweb = [ "instant/stdweb" ]
+wasm-bindgen = [ "instant/wasm-bindgen" ]
+
+[dependencies]
+instant = { version = "0.1", features = [ "now" ] }
+```
+
+_lib.rs_:
+```rust
+fn my_function() {
+ // Will select the proper implementation depending on the
+ // feature selected by the user.
+ let now_instant = instant::Instant::new();
+ let now_milliseconds = instant::now(); // In milliseconds.
+}
+```
+
+### Using the feature `now` without `stdweb` or `wasm-bindgen`.
+_Cargo.toml_:
+```toml
+[dependencies]
+instant = { version = "0.", features = [ "now" ] }
+```
+
+_lib.rs_:
+```rust
+fn my_function() {
+ // Will use the 'now' javascript implementation.
+ let now_instant = instant::Instant::new();
+ let now_milliseconds = instant::now(); // In milliseconds.
+}
+```
+
+_javascript WASM bindings file_:
+```js
+function now() {
+ return Date.now() / 1000.0;
+}
+```
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..077c9d4
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,22 @@
+cfg_if::cfg_if! {
+ if #[cfg(any(
+ all(target_arch = "wasm32", not(target_os = "wasi")),
+ target_arch = "asmjs"
+ ))] {
+ #[cfg(all(feature = "stdweb", not(feature = "wasm-bindgen")))]
+ #[macro_use]
+ extern crate stdweb;
+
+ mod wasm;
+ pub use wasm::Instant;
+ #[cfg(feature = "now")]
+ pub use crate::wasm::now;
+ } else {
+ mod native;
+ pub use native::Instant;
+ #[cfg(feature = "now")]
+ pub use native::now;
+ }
+}
+
+pub use std::time::Duration;
diff --git a/src/native.rs b/src/native.rs
new file mode 100644
index 0000000..37d5da4
--- /dev/null
+++ b/src/native.rs
@@ -0,0 +1,7 @@
+pub type Instant = std::time::Instant;
+
+/// The current time, in milliseconds.
+#[cfg(feature = "now")]
+pub fn now() -> f64 {
+ time::precise_time_s() * 1000.0
+}
diff --git a/src/wasm.rs b/src/wasm.rs
new file mode 100644
index 0000000..829ef3b
--- /dev/null
+++ b/src/wasm.rs
@@ -0,0 +1,129 @@
+use std::ops::{Add, AddAssign, Sub, SubAssign};
+use std::time::Duration;
+
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Hash)]
+pub struct Instant(Duration);
+
+impl Ord for Instant {
+ fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+ self.partial_cmp(other)
+ .expect("an instant should never be NaN or Inf.")
+ }
+}
+impl Eq for Instant {}
+
+impl Instant {
+ #[inline]
+ pub fn now() -> Self {
+ Instant(duration_from_f64(now()))
+ }
+
+ #[inline]
+ pub fn duration_since(&self, earlier: Instant) -> Duration {
+ assert!(
+ earlier.0 <= self.0,
+ "`earlier` cannot be later than `self`."
+ );
+ self.0 - earlier.0
+ }
+
+ #[inline]
+ pub fn elapsed(&self) -> Duration {
+ Self::now().duration_since(*self)
+ }
+
+ /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
+ /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
+ /// otherwise.
+ #[inline]
+ pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
+ self.0.checked_add(duration).map(Instant)
+ }
+
+ /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
+ /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
+ /// otherwise.
+ #[inline]
+ pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
+ self.0.checked_sub(duration).map(Instant)
+ }
+}
+
+impl Add<Duration> for Instant {
+ type Output = Self;
+
+ #[inline]
+ fn add(self, rhs: Duration) -> Self {
+ Instant(self.0 + rhs)
+ }
+}
+
+impl AddAssign<Duration> for Instant {
+ #[inline]
+ fn add_assign(&mut self, rhs: Duration) {
+ self.0 += rhs
+ }
+}
+
+impl Sub<Duration> for Instant {
+ type Output = Self;
+
+ #[inline]
+ fn sub(self, rhs: Duration) -> Self {
+ Instant(self.0 - rhs)
+ }
+}
+
+impl Sub<Instant> for Instant {
+ type Output = Duration;
+
+ #[inline]
+ fn sub(self, rhs: Instant) -> Duration {
+ self.duration_since(rhs)
+ }
+}
+
+impl SubAssign<Duration> for Instant {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Duration) {
+ self.0 -= rhs
+ }
+}
+
+fn duration_from_f64(millis: f64) -> Duration {
+ Duration::from_millis(millis.trunc() as u64)
+ + Duration::from_nanos((millis.fract() * 1.0e6) as u64)
+}
+
+#[cfg(all(feature = "stdweb", not(feature = "wasm-bindgen")))]
+#[allow(unused_results)] // Needed because the js macro triggers it.
+pub fn now() -> f64 {
+ use stdweb::unstable::TryInto;
+
+ // https://developer.mozilla.org/en-US/docs/Web/API/Performance/now
+ let v = js! { return performance.now(); };
+ v.try_into().unwrap()
+}
+
+#[cfg(feature = "wasm-bindgen")]
+pub fn now() -> f64 {
+ use wasm_bindgen_rs::prelude::*;
+ use wasm_bindgen_rs::JsCast;
+ js_sys::Reflect::get(&js_sys::global(), &JsValue::from_str("performance"))
+ .expect("failed to get performance from global object")
+ .unchecked_into::<web_sys::Performance>()
+ .now()
+}
+
+// The JS now function is in a module so it won't have to be renamed
+#[cfg(not(any(feature = "wasm-bindgen", feature = "stdweb")))]
+mod js {
+ extern "C" {
+ pub fn now() -> f64;
+ }
+}
+// Make the unsafe extern function "safe" so it can be called like the other 'now' functions
+#[cfg(not(any(feature = "wasm-bindgen", feature = "stdweb")))]
+pub fn now() -> f64 {
+ unsafe { js::now() }
+}
diff --git a/tests/wasm.rs b/tests/wasm.rs
new file mode 100644
index 0000000..b1577ad
--- /dev/null
+++ b/tests/wasm.rs
@@ -0,0 +1,46 @@
+extern crate wasm_bindgen_test;
+
+use instant::Instant;
+use std::time::Duration;
+use wasm_bindgen_test::*;
+
+wasm_bindgen_test_configure!(run_in_browser);
+// run these tests using: wasm-pack test --chrome --headless -- --features wasm-bindgen
+
+#[wasm_bindgen_test]
+fn test_instant_now() {
+ let now = Instant::now();
+ assert!(now.elapsed().as_nanos() > 0);
+}
+
+#[wasm_bindgen_test]
+fn test_duration() {
+ let now = Instant::now();
+ let one_sec = Duration::from_secs(1);
+ assert!(now.elapsed() < one_sec);
+}
+
+// Duration::new will overflow when you have u64::MAX seconds and one billion nanoseconds.
+// <https://doc.rust-lang.org/std/time/struct.Duration.html#method.new>
+const ONE_BILLION: u32 = 1_000_000_000;
+
+#[wasm_bindgen_test]
+fn test_checked_add() {
+ let now = Instant::now();
+
+ assert!(now.checked_add(Duration::from_millis(1)).is_some());
+ assert_eq!(
+ None,
+ now.checked_add(Duration::new(u64::MAX, ONE_BILLION - 1))
+ );
+}
+
+#[wasm_bindgen_test]
+fn test_checked_sub() {
+ let now = Instant::now();
+
+ assert!(now.checked_sub(Duration::from_millis(1)).is_some());
+ assert!(now
+ .checked_sub(Duration::new(u64::MAX, ONE_BILLION - 1))
+ .is_none());
+}