Skip to content
16 changes: 15 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,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"
Expand Down Expand Up @@ -121,6 +122,7 @@ tracing = "0.1.40"
tracing-subscriber = "0.3"
url = "2.2"
uuid = { version = "1.17", features = ["v4"] }
wasm-bindgen-futures = "0.4"
zerofrom = "0.1.5"
zip = { version = "4.0.0", default-features = false, features = ["deflate"] }

Expand Down
3 changes: 3 additions & 0 deletions sdk/typespec/typespec_client_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -29,6 +30,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"] }
Expand Down Expand Up @@ -57,6 +59,7 @@ 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/fs", "tokio/sync", "tokio/time", "tokio/io-util"]
wasm-bindgen = ["dep:wasm-bindgen-futures", "gloo-timers/futures"]
xml = ["dep:quick-xml"]

[[example]]
Expand Down
13 changes: 10 additions & 3 deletions sdk/typespec/typespec_client_core/src/async_runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ mod standard_runtime;
#[cfg(feature = "tokio")]
mod tokio_runtime;

#[cfg(target_arch = "wasm32")]
mod web_runtime;

#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -107,7 +110,7 @@ pub trait AsyncRuntime: Send + Sync {
///
fn spawn(&self, f: TaskFuture) -> SpawnedTask;

fn sleep(&self, duration: Duration) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>>;
fn sleep(&self, duration: Duration) -> TaskFuture;
}

static ASYNC_RUNTIME_IMPLEMENTATION: OnceLock<Arc<dyn AsyncRuntime>> = OnceLock::new();
Expand Down Expand Up @@ -189,12 +192,16 @@ pub fn set_async_runtime(runtime: Arc<dyn AsyncRuntime>) -> crate::Result<()> {
}

fn create_async_runtime() -> Arc<dyn AsyncRuntime> {
#[cfg(not(feature = "tokio"))]
#[cfg(feature = "wasm-bindgen")]
{
Arc::new(standard_runtime::StdRuntime)
Arc::new(web_runtime::WasmBindgenRuntime) as Arc<dyn AsyncRuntime>
}
#[cfg(feature = "tokio")]
{
Arc::new(tokio_runtime::TokioRuntime) as Arc<dyn AsyncRuntime>
}
#[cfg(not(any(feature = "tokio", feature = "wasm-bindgen")))]
{
Arc::new(standard_runtime::StdRuntime)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -150,7 +151,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))]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems this line is no longer needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to do #2770 (comment), this is still needed to allow a user to select the StdRuntime even target to wasm32.

fn sleep(&self, duration: Duration) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>> {
fn sleep(&self, duration: Duration) -> TaskFuture {
#[cfg(target_arch = "wasm32")]
{
panic!("sleep is not supported on wasm32")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// 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 `tokio` based APIs.
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<dyn std::error::Error>)
})
}

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.
return;
}
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ pub fn get_retry_after(headers: &Headers, now: DateTimeFn) -> Option<Duration> {
///
/// `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.
///
Expand Down
Loading