diff options
Diffstat (limited to 'crates/web-time-compat')
| -rw-r--r-- | crates/web-time-compat/Cargo.toml | 26 | ||||
| -rw-r--r-- | crates/web-time-compat/README.md | 37 | ||||
| -rw-r--r-- | crates/web-time-compat/src/lib.rs | 112 | ||||
| -rw-r--r-- | crates/web-time-compat/src/stdlib.rs | 21 | ||||
| -rw-r--r-- | crates/web-time-compat/src/wasm.rs | 20 |
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() + } +} |
