diff --git a/Cargo.lock b/Cargo.lock index 87415c9606..9923553da5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1275,6 +1275,18 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "half" version = "2.6.0" @@ -1705,6 +1717,16 @@ version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +[[package]] +name = "minicov" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" +dependencies = [ + "cc", + "walkdir", +] + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -3156,6 +3178,7 @@ dependencies = [ "dyn-clone", "futures", "getrandom 0.3.3", + "gloo-timers", "pin-project", "quick-xml", "rand 0.9.2", @@ -3171,6 +3194,8 @@ dependencies = [ "typespec_macros", "url", "uuid", + "wasm-bindgen-futures", + "wasm-bindgen-test", ] [[package]] @@ -3374,6 +3399,30 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-bindgen-test" +version = "0.3.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3" +dependencies = [ + "js-sys", + "minicov", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "wasm-streams" version = "0.4.2" diff --git a/Cargo.toml b/Cargo.toml index d5fae13115..f020025f09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,6 +101,7 @@ fe2o3-amqp-types = { version = "0.14" } flate2 = "1.1.0" futures = "0.3" getrandom = { version = "0.3" } +gloo-timers = { version = "0.3" } hmac = { version = "0.12" } litemap = "0.7.4" log = "0.4" @@ -143,6 +144,8 @@ tracing = "0.1.40" tracing-subscriber = "0.3" url = "2.2" uuid = { version = "1.18", features = ["v4"] } +wasm-bindgen-futures = "0.4" +wasm-bindgen-test = "0.3" zerofrom = "0.1.5" zip = { version = "4.0.0", default-features = false, features = ["deflate"] } diff --git a/eng/dict/crates.txt b/eng/dict/crates.txt index 01bc133f8a..6a2163073c 100644 --- a/eng/dict/crates.txt +++ b/eng/dict/crates.txt @@ -32,6 +32,7 @@ fe2o3-amqp-types flate2 futures getrandom +gloo hmac litemap log diff --git a/sdk/typespec/typespec_client_core/CHANGELOG.md b/sdk/typespec/typespec_client_core/CHANGELOG.md index c027894073..888b705ccc 100644 --- a/sdk/typespec/typespec_client_core/CHANGELOG.md +++ b/sdk/typespec/typespec_client_core/CHANGELOG.md @@ -4,6 +4,8 @@ ### Features Added +- Added support for WASM to the `async_runtime` module. + ### Breaking Changes - Removed the `fs` module including the `FileStream` and `FileStreamBuilder` types. Moved to `examples/` to copy if needed. diff --git a/sdk/typespec/typespec_client_core/Cargo.toml b/sdk/typespec/typespec_client_core/Cargo.toml index 90949fed84..a9a9dd5b20 100644 --- a/sdk/typespec/typespec_client_core/Cargo.toml +++ b/sdk/typespec/typespec_client_core/Cargo.toml @@ -16,6 +16,7 @@ base64.workspace = true bytes.workspace = true dyn-clone.workspace = true futures.workspace = true +gloo-timers = { workspace = true, optional = true } pin-project.workspace = true quick-xml = { workspace = true, optional = true } rand.workspace = true @@ -30,6 +31,7 @@ typespec = { workspace = true, default-features = false } typespec_macros = { workspace = true, optional = true } url.workspace = true uuid.workspace = true +wasm-bindgen-futures = { workspace = true, optional = true } [target.'cfg(not(target_family = "wasm"))'.dependencies] tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } @@ -39,11 +41,19 @@ getrandom.workspace = true tokio = { workspace = true, features = ["macros", "rt", "time"] } [dev-dependencies] -tokio = { workspace = true, features = ["fs"] } tracing.workspace = true tracing-subscriber.workspace = true typespec_macros.path = "../typespec_macros" +[target.'cfg(not(target_family = "wasm"))'.dev-dependencies] +tokio = { workspace = true, features = ["fs"] } + +[target.'cfg(target_family = "wasm")'.dev-dependencies] +tokio.workspace = true +getrandom = { workspace = true, features = ["wasm_js"] } +uuid = { workspace = true, features = ["v4", "js"] } +wasm-bindgen-test.workspace = true + [features] default = ["http", "json", "reqwest", "reqwest_deflate", "reqwest_gzip"] debug = ["typespec_macros?/debug"] @@ -59,8 +69,13 @@ reqwest_rustls = [ ] # Remove dependency on banned `ring` crate; requires manually configuring crypto provider. test = [] # Enables extra tracing including error bodies that may contain PII. tokio = ["tokio/sync", "tokio/time"] +wasm_bindgen = ["dep:wasm-bindgen-futures", "gloo-timers/futures"] xml = ["dep:quick-xml"] +[[example]] +name = "core_binary_data_request" +required-features = ["tokio"] + [[example]] name = "core_stream_response" required-features = ["derive"] @@ -76,6 +91,7 @@ features = [ "reqwest_gzip", "reqwest_rustls", "tokio", + "wasm_bindgen", "xml", ] diff --git a/sdk/typespec/typespec_client_core/src/async_runtime/mod.rs b/sdk/typespec/typespec_client_core/src/async_runtime/mod.rs index 17d9034ebc..65a58b2e8f 100644 --- a/sdk/typespec/typespec_client_core/src/async_runtime/mod.rs +++ b/sdk/typespec/typespec_client_core/src/async_runtime/mod.rs @@ -7,28 +7,22 @@ //! //! It abstracts away the underlying implementation details, allowing for different task execution strategies based on the target architecture and features enabled. //! -//! -//! Example usage: +//! # Examples //! //! ``` //! use typespec_client_core::async_runtime::get_async_runtime; -//! use futures::FutureExt; -//! -//! #[tokio::main] -//! async fn main() { -//! let async_runtime = get_async_runtime(); -//! let handle = async_runtime.spawn(async { -//! // Simulate some work -//! std::thread::sleep(std::time::Duration::from_secs(1)); -//! }.boxed()); //! -//! handle.await.expect("Task should complete successfully"); -//! -//! println!("Task completed"); -//! } +//! # #[tokio::main] +//! # async fn main() { +//! let async_runtime = get_async_runtime(); +//! let handle = async_runtime.spawn(Box::pin(async { +//! // Simulate some work +//! std::thread::sleep(std::time::Duration::from_secs(1)); +//! })); +//! handle.await.expect("Task should complete successfully"); +//! println!("Task completed"); +//! # } //! ``` -//! -//! use crate::time::Duration; use std::{ future::Future, @@ -36,12 +30,15 @@ use std::{ sync::{Arc, OnceLock}, }; -#[cfg_attr(feature = "tokio", allow(dead_code))] +#[cfg_attr(any(feature = "tokio", feature = "wasm_bindgen"), allow(dead_code))] mod standard_runtime; #[cfg(feature = "tokio")] mod tokio_runtime; +#[cfg(all(target_arch = "wasm32", feature = "wasm_bindgen"))] +mod web_runtime; + #[cfg(test)] mod tests; @@ -80,35 +77,35 @@ pub trait AsyncRuntime: Send + Sync { /// from its environment by reference, as it will be executed in a different thread or context. /// /// # Returns + /// /// A future which can be awaited to block until the task has completed. /// - /// # Example + /// # Examples + /// /// ``` /// use typespec_client_core::async_runtime::get_async_runtime; - /// use futures::FutureExt; /// - /// #[tokio::main] - /// async fn main() { - /// let async_runtime = get_async_runtime(); - /// let future = async_runtime.spawn(async { - /// // Simulate some work - /// std::thread::sleep(std::time::Duration::from_secs(1)); - /// }.boxed()); - /// future.await.expect("Task should complete successfully"); - /// } + /// # #[tokio::main] + /// # async fn main() { + /// let async_runtime = get_async_runtime(); + /// let handle = async_runtime.spawn(Box::pin(async { + /// // Simulate some work + /// std::thread::sleep(std::time::Duration::from_secs(1)); + /// })); + /// handle.await.expect("Task should complete successfully"); + /// # } /// ``` /// - /// # Note + /// # Notes /// /// This trait intentionally does not use the *`async_trait`* macro because when the /// `async_trait` attribute is applied to a trait implementation, the rewritten /// method cannot directly return a future, instead they wrap the return value /// in a future, and we want the `spawn` method to directly return a future /// that can be awaited. - /// fn spawn(&self, f: TaskFuture) -> SpawnedTask; - fn sleep(&self, duration: Duration) -> Pin + Send + 'static>>; + fn sleep(&self, duration: Duration) -> TaskFuture; } static ASYNC_RUNTIME_IMPLEMENTATION: OnceLock> = OnceLock::new(); @@ -124,22 +121,20 @@ static ASYNC_RUNTIME_IMPLEMENTATION: OnceLock> = OnceLock: /// # Returns /// An instance of a [`AsyncRuntime`] which can be used to spawn background tasks or perform other asynchronous operations. /// -/// # Example +/// # Examples /// /// ``` /// use typespec_client_core::async_runtime::get_async_runtime; -/// use futures::FutureExt; /// -/// #[tokio::main] -/// async fn main() { -/// let async_runtime = get_async_runtime(); -/// let handle = async_runtime.spawn(async { -/// // Simulate some work -/// std::thread::sleep(std::time::Duration::from_secs(1)); -/// }.boxed()); -/// } +/// # #[tokio::main] +/// # async fn main() { +/// let async_runtime = get_async_runtime(); +/// let handle = async_runtime.spawn(Box::pin(async { +/// // Simulate some work +/// std::thread::sleep(std::time::Duration::from_secs(1)); +/// })); +/// # } /// ``` -/// pub fn get_async_runtime() -> Arc { ASYNC_RUNTIME_IMPLEMENTATION .get_or_init(|| create_async_runtime()) @@ -155,7 +150,7 @@ pub fn get_async_runtime() -> Arc { /// # Returns /// Ok if the async runtime was set successfully, or an error if it has already been set. /// -/// # Example +/// # Examples /// /// ``` /// use typespec_client_core::async_runtime::{ @@ -190,12 +185,16 @@ pub fn set_async_runtime(runtime: Arc) -> crate::Result<()> { } fn create_async_runtime() -> Arc { - #[cfg(not(feature = "tokio"))] + #[cfg(all(target_arch = "wasm32", feature = "wasm_bindgen"))] { - Arc::new(standard_runtime::StdRuntime) + Arc::new(web_runtime::WasmBindgenRuntime) as Arc } #[cfg(feature = "tokio")] { Arc::new(tokio_runtime::TokioRuntime) as Arc } + #[cfg(not(any(feature = "tokio", feature = "wasm_bindgen")))] + { + Arc::new(standard_runtime::StdRuntime) as Arc + } } diff --git a/sdk/typespec/typespec_client_core/src/async_runtime/standard_runtime.rs b/sdk/typespec/typespec_client_core/src/async_runtime/standard_runtime.rs index 645af21766..2eaeb0fc6a 100644 --- a/sdk/typespec/typespec_client_core/src/async_runtime/standard_runtime.rs +++ b/sdk/typespec/typespec_client_core/src/async_runtime/standard_runtime.rs @@ -14,6 +14,7 @@ use std::{ task::{Context, Poll, Waker}, thread, }; +#[cfg(not(target_arch = "wasm32"))] use std::{future::Future, pin::Pin}; #[cfg(not(target_arch = "wasm32"))] use tracing::debug; @@ -149,7 +150,7 @@ impl AsyncRuntime for StdRuntime { /// Uses a simple thread based implementation for sleep. A more efficient /// implementation is available by using the `tokio` crate feature. #[cfg_attr(target_arch = "wasm32", allow(unused_variables))] - fn sleep(&self, duration: Duration) -> Pin + Send + 'static>> { + fn sleep(&self, duration: Duration) -> TaskFuture { #[cfg(target_arch = "wasm32")] { panic!("sleep is not supported on wasm32") diff --git a/sdk/typespec/typespec_client_core/src/async_runtime/tests.rs b/sdk/typespec/typespec_client_core/src/async_runtime/tests.rs index 4eb8e8c292..69e5bb6d01 100644 --- a/sdk/typespec/typespec_client_core/src/async_runtime/tests.rs +++ b/sdk/typespec/typespec_client_core/src/async_runtime/tests.rs @@ -3,24 +3,21 @@ use super::*; use crate::time::Duration; -use futures::FutureExt; use std::sync::{Arc, Mutex}; +#[cfg(not(any(feature = "tokio", feature = "wasm_bindgen")))] #[test] fn test_task_spawner_execution() { let runtime = get_async_runtime(); let result = Arc::new(Mutex::new(false)); let result_clone = Arc::clone(&result); - let handle = runtime.spawn( - async move { - // Simulate some work - crate::sleep::sleep(Duration::milliseconds(50)).await; - let mut value = result_clone.lock().unwrap(); - *value = true; - } - .boxed(), - ); + let handle = runtime.spawn(Box::pin(async move { + // Simulate some work + crate::sleep::sleep(Duration::milliseconds(50)).await; + let mut value = result_clone.lock().unwrap(); + *value = true; + })); futures::executor::block_on(handle).expect("Task should complete successfully"); @@ -35,15 +32,12 @@ async fn tokio_task_spawner_execution() { let result = Arc::new(Mutex::new(false)); let result_clone = Arc::clone(&result); - let handle = async_runtime.spawn( - async move { - // Simulate some work - crate::sleep::sleep(Duration::milliseconds(50)).await; - let mut value = result_clone.lock().unwrap(); - *value = true; - } - .boxed(), - ); + let handle = async_runtime.spawn(Box::pin(async move { + // Simulate some work + crate::sleep::sleep(Duration::milliseconds(50)).await; + let mut value = result_clone.lock().unwrap(); + *value = true; + })); handle.await.expect("Task should complete successfully"); @@ -58,12 +52,9 @@ async fn test_tokio_specific_handling() { let task_completed = Arc::new(Mutex::new(false)); let task_completed_clone = Arc::clone(&task_completed); - let handle = spawner.spawn( - async move { - *task_completed_clone.lock().unwrap() = true; - } - .boxed(), - ); + let handle = spawner.spawn(Box::pin(async move { + *task_completed_clone.lock().unwrap() = true; + })); handle.await.expect("Task should complete successfully"); assert!(*task_completed.lock().unwrap()); @@ -79,13 +70,10 @@ async fn tokio_multiple_tasks() { // Spawn multiple tasks for _ in 0..5 { let counter_clone = Arc::clone(&counter); - let handle = spawner.spawn( - async move { - let mut value = counter_clone.lock().unwrap(); - *value += 1; - } - .boxed(), - ); + let handle = spawner.spawn(Box::pin(async move { + let mut value = counter_clone.lock().unwrap(); + *value += 1; + })); handles.push(handle); } @@ -104,15 +92,12 @@ async fn tokio_task_execution() { let result = Arc::new(Mutex::new(false)); let result_clone = Arc::clone(&result); - let handle = spawner.spawn( - async move { - // Simulate some work - crate::sleep::sleep(Duration::milliseconds(50)).await; - let mut value = result_clone.lock().unwrap(); - *value = true; - } - .boxed(), - ); + let handle = spawner.spawn(Box::pin(async move { + // Simulate some work + crate::sleep::sleep(Duration::milliseconds(50)).await; + let mut value = result_clone.lock().unwrap(); + *value = true; + })); // Wait for task completion handle.await.expect("Task should complete successfully"); @@ -123,18 +108,16 @@ async fn tokio_task_execution() { // When the "tokio" feature is enabled, the azure_core::sleep::sleep function uses tokio::time::sleep which requires a tokio runtime. // When the "tokio" feature is not enabled, it uses std::thread::sleep which does not require a tokio runtime. +#[cfg(not(target_arch = "wasm32"))] #[test] fn std_specific_handling() { let spawner = Arc::new(standard_runtime::StdRuntime); let task_completed = Arc::new(Mutex::new(false)); let task_completed_clone = Arc::clone(&task_completed); - let handle = spawner.spawn( - async move { - *task_completed_clone.lock().unwrap() = true; - } - .boxed(), - ); + let handle = spawner.spawn(Box::pin(async move { + *task_completed_clone.lock().unwrap() = true; + })); // For std threads, we need to wait for the task to complete std::thread::sleep(Duration::milliseconds(100).try_into().unwrap()); @@ -143,6 +126,7 @@ fn std_specific_handling() { } #[test] +#[cfg(not(target_arch = "wasm32"))] fn std_multiple_tasks() { let spawner = Arc::new(standard_runtime::StdRuntime); let counter = Arc::new(Mutex::new(0)); @@ -151,13 +135,10 @@ fn std_multiple_tasks() { // Spawn multiple tasks for _ in 0..5 { let counter_clone = Arc::clone(&counter); - let handle = spawner.spawn( - async move { - let mut value = counter_clone.lock().unwrap(); - *value += 1; - } - .boxed(), - ); + let handle = spawner.spawn(Box::pin(async move { + let mut value = counter_clone.lock().unwrap(); + *value += 1; + })); handles.push(handle); } @@ -171,21 +152,19 @@ fn std_multiple_tasks() { // When the "tokio" feature is enabled, the azure_core::sleep::sleep function uses tokio::time::sleep which requires a tokio runtime. // When the "tokio" feature is not enabled, it uses std::thread::sleep which does not require a tokio runtime. +#[cfg(not(any(feature = "tokio", feature = "wasm_bindgen")))] #[test] fn std_task_execution() { let runtime = Arc::new(standard_runtime::StdRuntime); let result = Arc::new(Mutex::new(false)); let result_clone = Arc::clone(&result); - let handle = runtime.spawn( - async move { - // Simulate some work - crate::sleep::sleep(Duration::milliseconds(500)).await; - let mut value = result_clone.lock().unwrap(); - *value = true; - } - .boxed(), - ); + let handle = runtime.spawn(Box::pin(async move { + // Simulate some work + crate::sleep::sleep(Duration::milliseconds(500)).await; + let mut value = result_clone.lock().unwrap(); + *value = true; + })); // Wait for task completion futures::executor::block_on(handle).expect("Task should complete successfully"); @@ -197,6 +176,7 @@ fn std_task_execution() { // Basic test that launches 10k futures and waits for them to complete: // it has a high chance of failing if there is a race condition in the sleep method; // otherwise, it runs quickly. +#[cfg(not(any(feature = "tokio", feature = "wasm_bindgen")))] #[tokio::test] async fn test_timeout() { use super::*; @@ -223,6 +203,7 @@ async fn test_timeout() { } } +#[cfg(not(target_arch = "wasm32"))] #[tokio::test] async fn test_sleep() { let runtime = get_async_runtime(); @@ -232,6 +213,37 @@ async fn test_sleep() { assert!(elapsed >= Duration::milliseconds(100)); } +#[cfg(all(target_arch = "wasm32", feature = "wasm_bindgen"))] +use wasm_bindgen_test::*; + +#[cfg(all(target_arch = "wasm32", feature = "wasm_bindgen"))] +#[wasm_bindgen_test] +async fn wasm_bindgen_test_sleep() { + let runtime = get_async_runtime(); + runtime.sleep(Duration::milliseconds(100)).await; +} + +#[cfg(all(target_arch = "wasm32", feature = "wasm_bindgen"))] +#[wasm_bindgen_test] +async fn wasm_bindgen_task_execution() { + let spawner = Arc::new(web_runtime::WasmBindgenRuntime); + let result = Arc::new(Mutex::new(false)); + let result_clone = Arc::clone(&result); + + let handle = spawner.spawn(Box::pin(async move { + // Simulate some work + crate::sleep::sleep(Duration::milliseconds(50)).await; + let mut value = result_clone.lock().unwrap(); + *value = true; + })); + + // Wait for task completion + handle.await.expect("Task should complete successfully"); + + // Verify the task executed + assert!(*result.lock().unwrap()); +} + #[test] fn test_get_runtime() { // Ensure that the runtime can be retrieved without panicking @@ -245,7 +257,7 @@ impl AsyncRuntime for TestRuntime { unimplemented!("TestRuntime does not support spawning tasks"); } - fn sleep(&self, _duration: Duration) -> Pin + Send + 'static>> { + fn sleep(&self, _duration: Duration) -> TaskFuture { unimplemented!("TestRuntime does not support sleeping"); } } diff --git a/sdk/typespec/typespec_client_core/src/async_runtime/web_runtime.rs b/sdk/typespec/typespec_client_core/src/async_runtime/web_runtime.rs new file mode 100644 index 0000000000..7986be5d6a --- /dev/null +++ b/sdk/typespec/typespec_client_core/src/async_runtime/web_runtime.rs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +use super::{AsyncRuntime, SpawnedTask, TaskFuture}; +use crate::time::Duration; +use futures::channel::oneshot; + +/// An [`AsyncRuntime`] using `wasm-bindgen-futures` for task spawning and `gloo-timers` for sleep functionality. +pub(crate) struct WasmBindgenRuntime; + +impl AsyncRuntime for WasmBindgenRuntime { + fn spawn(&self, f: TaskFuture) -> SpawnedTask { + let (tx, rx) = oneshot::channel(); + + wasm_bindgen_futures::spawn_local(async move { + let result = f.await; + let _ = tx.send(result); + }); + + Box::pin(async { + rx.await + .map_err(|e| Box::new(e) as Box) + }) + } + + fn sleep(&self, duration: Duration) -> TaskFuture { + Box::pin(async move { + if let Ok(d) = duration.try_into() { + gloo_timers::future::sleep(d).await; + } else { + // This means the duration is negative, don't sleep at all. + } + }) + } +} diff --git a/sdk/typespec/typespec_client_core/src/fmt.rs b/sdk/typespec/typespec_client_core/src/fmt.rs index 2543fa1838..ea037b56a2 100644 --- a/sdk/typespec/typespec_client_core/src/fmt.rs +++ b/sdk/typespec/typespec_client_core/src/fmt.rs @@ -90,6 +90,7 @@ pub mod as_string { } } +#[cfg(feature = "json")] #[cfg(test)] mod tests { use crate::json::{from_json, to_json}; diff --git a/sdk/typespec/typespec_client_core/src/http/policies/retry/mod.rs b/sdk/typespec/typespec_client_core/src/http/policies/retry/mod.rs index f5fd890183..22ca584061 100644 --- a/sdk/typespec/typespec_client_core/src/http/policies/retry/mod.rs +++ b/sdk/typespec/typespec_client_core/src/http/policies/retry/mod.rs @@ -89,7 +89,8 @@ impl Deref for RetryPolicyCount { /// /// `wait` can be implemented in more complex cases where a simple test of time /// is not enough. -#[async_trait] +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] pub trait RetryPolicy: std::fmt::Debug + Send + Sync { /// Determine if no more retries should be performed. /// @@ -238,7 +239,8 @@ mod test { status: StatusCode, } - #[async_trait] + #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] + #[cfg_attr(not(target_arch = "wasm32"), async_trait)] impl Policy for StatusResponder { async fn send(&self, _: &Context, _: &mut Request, _: &[Arc]) -> PolicyResult { let mut count = self.request_count.lock().unwrap(); diff --git a/sdk/typespec/typespec_client_core/src/sleep.rs b/sdk/typespec/typespec_client_core/src/sleep.rs index 97fccfcd7d..661d16ad98 100644 --- a/sdk/typespec/typespec_client_core/src/sleep.rs +++ b/sdk/typespec/typespec_client_core/src/sleep.rs @@ -13,16 +13,17 @@ use crate::{async_runtime::get_async_runtime, time::Duration}; /// # Returns /// A future that resolves when the sleep duration has elapsed. /// -/// # Example -/// ``` +/// # Examples +/// +/// ``` no_run /// use typespec_client_core::{sleep, time::Duration}; /// -/// #[tokio::main] -/// async fn main() { -/// // Sleep for 1 second -/// sleep(Duration::seconds(1)).await; -/// println!("Slept for 1 second"); -/// } +/// # #[tokio::main] +/// # async fn main() { +/// // Sleep for 1 second +/// sleep(Duration::seconds(1)).await; +/// println!("Slept for 1 second"); +/// # } /// ``` pub async fn sleep(duration: Duration) { get_async_runtime().sleep(duration).await diff --git a/sdk/typespec/typespec_client_core/src/time/mod.rs b/sdk/typespec/typespec_client_core/src/time/mod.rs index ac13d62366..0afac7feea 100644 --- a/sdk/typespec/typespec_client_core/src/time/mod.rs +++ b/sdk/typespec/typespec_client_core/src/time/mod.rs @@ -138,6 +138,7 @@ pub fn diff(first: OffsetDateTime, second: OffsetDateTime) -> Duration { (first - second).abs() } +#[cfg(feature = "json")] #[cfg(test)] mod tests { use super::*; diff --git a/sdk/typespec/typespec_client_core/src/time/unix_time.rs b/sdk/typespec/typespec_client_core/src/time/unix_time.rs index 875afc6687..329c3bfb57 100644 --- a/sdk/typespec/typespec_client_core/src/time/unix_time.rs +++ b/sdk/typespec/typespec_client_core/src/time/unix_time.rs @@ -58,6 +58,7 @@ pub mod option { } } +#[cfg(feature = "json")] #[cfg(test)] mod tests { use crate::json::{from_json, to_json};