Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"] }

Expand Down
1 change: 1 addition & 0 deletions eng/dict/crates.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ fe2o3-amqp-types
flate2
futures
getrandom
gloo
hmac
litemap
log
Expand Down
2 changes: 2 additions & 0 deletions sdk/typespec/typespec_client_core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
18 changes: 17 additions & 1 deletion 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 @@ -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"] }
Expand All @@ -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"]
Expand All @@ -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"]
Expand All @@ -76,6 +91,7 @@ features = [
"reqwest_gzip",
"reqwest_rustls",
"tokio",
"wasm_bindgen",
"xml",
]

Expand Down
91 changes: 45 additions & 46 deletions sdk/typespec/typespec_client_core/src/async_runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,38 @@
//!
//! 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,
pin::Pin,
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;

Expand Down Expand Up @@ -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<Box<dyn Future<Output = ()> + Send + 'static>>;
fn sleep(&self, duration: Duration) -> TaskFuture;
}

static ASYNC_RUNTIME_IMPLEMENTATION: OnceLock<Arc<dyn AsyncRuntime>> = OnceLock::new();
Expand All @@ -124,22 +121,20 @@ static ASYNC_RUNTIME_IMPLEMENTATION: OnceLock<Arc<dyn AsyncRuntime>> = 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<dyn AsyncRuntime> {
ASYNC_RUNTIME_IMPLEMENTATION
.get_or_init(|| create_async_runtime())
Expand All @@ -155,7 +150,7 @@ pub fn get_async_runtime() -> Arc<dyn AsyncRuntime> {
/// # 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::{
Expand Down Expand Up @@ -190,12 +185,16 @@ pub fn set_async_runtime(runtime: Arc<dyn AsyncRuntime>) -> crate::Result<()> {
}

fn create_async_runtime() -> Arc<dyn AsyncRuntime> {
#[cfg(not(feature = "tokio"))]
#[cfg(all(target_arch = "wasm32", 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) as Arc<dyn AsyncRuntime>
}
}
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 @@ -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<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
Loading
Loading