summaryrefslogtreecommitdiff
path: root/crates/web-time-compat
diff options
context:
space:
mode:
Diffstat (limited to 'crates/web-time-compat')
-rw-r--r--crates/web-time-compat/Cargo.toml26
-rw-r--r--crates/web-time-compat/README.md37
-rw-r--r--crates/web-time-compat/src/lib.rs112
-rw-r--r--crates/web-time-compat/src/stdlib.rs21
-rw-r--r--crates/web-time-compat/src/wasm.rs20
5 files changed, 216 insertions, 0 deletions
diff --git a/crates/web-time-compat/Cargo.toml b/crates/web-time-compat/Cargo.toml
new file mode 100644
index 000000000..3b4f4118a
--- /dev/null
+++ b/crates/web-time-compat/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "web-time-compat"
+version = "0.1.0"
+authors = ["The Tor Project, Inc.", "Nick Mathewson <[email protected]>"]
+edition = "2024"
+rust-version = "1.89"
+license = "MIT OR Apache-2.0"
+homepage = "https://gitlab.torproject.org/tpo/core/arti/-/wikis/home"
+description = "Compatibility layer for web-time"
+keywords = ["js", "wasm", "time"]
+# We must put *something* here and this will do
+categories = ["rust-patterns"]
+repository = "https://gitlab.torproject.org/tpo/core/arti.git/"
+[package.metadata.docs.rs]
+all-features = true
+
+[features]
+default = []
+full = []
+
+[dependencies]
+
+[dev-dependencies]
+
+[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
+web-time = "1.1.0"
diff --git a/crates/web-time-compat/README.md b/crates/web-time-compat/README.md
new file mode 100644
index 000000000..9acc3de82
--- /dev/null
+++ b/crates/web-time-compat/README.md
@@ -0,0 +1,37 @@
+# web-time-compat
+
+Small compatibility layer for [`web-time`].
+
+Unlike [`web-time`], this crate does not require you to stop using
+[`std::time::SystemTime`].
+Instead, it provides an extension trait to replace the `now`
+method of `SystemTime` types with a `get` method that works on
+wasm32-unknown-unknown.
+
+With `Instant`, it isn't possible to continue using `std::time::Instant`,
+since that type is not interconvertible with `web_time::Instant`. Instead,
+we provide an extension trait to make it easier for you to make sure that you
+are only using the version of Instant you want.
+
+## How to use this crate
+
+(This isn't the only way, but it's what we recommend.)
+
+- Replace all references to `std::time::Instant` with `web_time_compat::Instant`.
+- You may, if you like, also use `web_time_compat::{Duration, SystemTime}`.
+ They are just aliases for the standard Duration and SystemTimetypes.
+- Instead of `SystemTime::now()`, use `SystemTimeExt::get()`.
+- Instead of `Instant::now()`, use `Instant::get()`.
+- Add `std::time::SystemTime::now` and `std::time::Instant::now` to your
+ [`disallowed-methods`] list in your `clippy.toml` file,
+ to prevent them from being used accidentally.
+- If you use any other time libraries (such as `time` or `chrono`), you may
+ want to add their "now" methods to `disallowed-methods`, depending
+ on whether you have configured them for wasm compatibility.
+
+[`web-time`]: https://docs.rs/web-time/latest/web_time/
+[`disallowed-methods`]: https://doc.rust-lang.org/stable/clippy/lint_configuration.html#disallowed-methods
+
+----
+
+License: MIT OR Apache-2.0
diff --git a/crates/web-time-compat/src/lib.rs b/crates/web-time-compat/src/lib.rs
new file mode 100644
index 000000000..31abd17f5
--- /dev/null
+++ b/crates/web-time-compat/src/lib.rs
@@ -0,0 +1,112 @@
+#![cfg_attr(docsrs, feature(doc_cfg))]
+#![doc = include_str!("../README.md")]
+// @@ begin lint list maintained by maint/add_warning @@
+#![allow(renamed_and_removed_lints)] // @@REMOVE_WHEN(ci_arti_stable)
+#![allow(unknown_lints)] // @@REMOVE_WHEN(ci_arti_nightly)
+#![warn(missing_docs)]
+#![warn(noop_method_call)]
+#![warn(unreachable_pub)]
+#![warn(clippy::all)]
+#![deny(clippy::await_holding_lock)]
+#![deny(clippy::cargo_common_metadata)]
+#![deny(clippy::cast_lossless)]
+#![deny(clippy::checked_conversions)]
+#![warn(clippy::cognitive_complexity)]
+#![deny(clippy::debug_assert_with_mut_call)]
+#![deny(clippy::exhaustive_enums)]
+#![deny(clippy::exhaustive_structs)]
+#![deny(clippy::expl_impl_clone_on_copy)]
+#![deny(clippy::fallible_impl_from)]
+#![deny(clippy::implicit_clone)]
+#![deny(clippy::large_stack_arrays)]
+#![warn(clippy::manual_ok_or)]
+#![deny(clippy::missing_docs_in_private_items)]
+#![warn(clippy::needless_borrow)]
+#![warn(clippy::needless_pass_by_value)]
+#![warn(clippy::option_option)]
+#![deny(clippy::print_stderr)]
+#![deny(clippy::print_stdout)]
+#![warn(clippy::rc_buffer)]
+#![deny(clippy::ref_option_ref)]
+#![warn(clippy::semicolon_if_nothing_returned)]
+#![warn(clippy::trait_duplication_in_bounds)]
+#![deny(clippy::unchecked_time_subtraction)]
+#![deny(clippy::unnecessary_wraps)]
+#![warn(clippy::unseparated_literal_suffix)]
+#![deny(clippy::unwrap_used)]
+#![deny(clippy::mod_module_files)]
+#![allow(clippy::let_unit_value)] // This can reasonably be done for explicitness
+#![allow(clippy::uninlined_format_args)]
+#![allow(clippy::significant_drop_in_scrutinee)] // arti/-/merge_requests/588/#note_2812945
+#![allow(clippy::result_large_err)] // temporary workaround for arti#587
+#![allow(clippy::needless_raw_string_hashes)] // complained-about code is fine, often best
+#![allow(clippy::needless_lifetimes)] // See arti#1765
+#![allow(mismatched_lifetime_syntaxes)] // temporary workaround for arti#2060
+#![allow(clippy::collapsible_if)] // See arti#2342
+#![deny(clippy::unused_async)]
+//! <!-- @@ end lint list maintained by maint/add_warning @@ -->
+
+// We always use `SystemTime` for our data representation outside of this crate.
+//
+// The only time that we touch `SystemTime` is when we are constructing it with
+// `SystemTimeExt::get`.
+pub use std::time::SystemTime;
+
+// "Duration" is the same type in web_time as it is in stdlib.
+pub use std::time::Duration;
+
+#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
+mod stdlib;
+
+#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
+pub use stdlib::*;
+
+#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
+mod wasm;
+
+#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
+pub use wasm::*;
+
+/// Module to hide "Sealed"
+mod seal {
+ /// Trait used to prevent implementing InstantExt or SystemTimeExt outside of this crate.
+ #[allow(unreachable_pub)]
+ pub trait Sealed {}
+}
+
+/// Extension trait for [`std::time::SystemTime`]
+///
+/// This trait adds a `get` method which works like `now`,
+/// but also supports `wasm32-unknown-unknown` environments.
+pub trait SystemTimeExt: seal::Sealed {
+ /// Return the current time.
+ fn get() -> std::time::SystemTime;
+}
+
+/// Extension trait for [`Instant`].
+///
+/// This trait adds a `get` method which works like `now`,
+/// so we can make sure we aren't calling [`std::time::Instant::now`]
+/// on`wasm32-unknown-unknown` environments.
+///
+/// ## Design note
+///
+/// Since we already replace the `std::time::Instant` type with
+/// `web_time::Instant` in this crate, why do we also provide
+/// an extension trait to rename its "now" method?
+///
+/// We do so for two reasons:
+///
+/// 1. Consistency. With this approach, you don't have to remember
+/// which type uses `get` and which uses `now`.
+/// 2. Enforcement. This approach makes it possible to use Clippy
+/// to disallow `std::time::Instant::now()` unconditionally,
+/// to make sure that you don't forget to use
+/// the appropriate `web_time_compat::Instant` type instead.
+pub trait InstantExt: seal::Sealed {
+ /// Return the current time.
+ fn get() -> crate::Instant;
+}
+
+impl seal::Sealed for std::time::SystemTime {}
+impl seal::Sealed for crate::Instant {}
diff --git a/crates/web-time-compat/src/stdlib.rs b/crates/web-time-compat/src/stdlib.rs
new file mode 100644
index 000000000..891a0e0f7
--- /dev/null
+++ b/crates/web-time-compat/src/stdlib.rs
@@ -0,0 +1,21 @@
+//! Standard-library time functionality..
+
+// If we've forbidden `now` elsewhere in our project, we enable it here.
+// (And only here!)
+#![allow(clippy::disallowed_methods)]
+
+pub use std::time::Instant;
+
+use std::time::SystemTime;
+
+impl crate::SystemTimeExt for SystemTime {
+ fn get() -> SystemTime {
+ SystemTime::now()
+ }
+}
+
+impl crate::InstantExt for Instant {
+ fn get() -> crate::Instant {
+ Instant::now()
+ }
+}
diff --git a/crates/web-time-compat/src/wasm.rs b/crates/web-time-compat/src/wasm.rs
new file mode 100644
index 000000000..37d2198ce
--- /dev/null
+++ b/crates/web-time-compat/src/wasm.rs
@@ -0,0 +1,20 @@
+//! Wasm-specific time functionality.
+
+// If we've forbidden `now` elsewhere in our project, we enable it here.
+#![allow(clippy::disallowed_methods)]
+
+pub use web_time::Instant;
+
+impl crate::SystemTimeExt for std::time::SystemTime {
+ fn get() -> std::time::SystemTime {
+ use web_time::web::SystemTimeExt as _;
+ let now = web_time::SystemTime::now();
+ now.to_std()
+ }
+}
+
+impl crate::InstantExt for Instant {
+ fn get() -> crate::Instant {
+ Instant::now()
+ }
+}