-
Notifications
You must be signed in to change notification settings - Fork 310
Description
Hi! I'm working on integrating rmcp
into a project that requires WASM compatibility and noticed that rmcp currently doesn't compile for wasm32-unknown-unknown due to several WASM-specific blockers, mostly Send
requirements.
Current Issues:
-
Send trait bounds incompatibility
- traits like
SseClient
requireeSend + Sync + 'static
- Send is a no go in web:
- JavaScript interop types contain
PhantomData<*const u8>
making them intentionally !Send - reqwest's WASM implementation uses
JsValue
types that are !Send by design
- JavaScript interop types contain
- traits like
-
Transport trait architecture
- All transport implementations must return
impl Future + Send
- All transport implementations must return
-
Worker transport assumptions
- Worker trait expects thread spawning capabilities
- WASM is single-threaded, no
std::thread
support
-
Service layer threading
ServiceRole
,Service
traits all requireSend + Sync
- Future return types across the codebase assume
Send
bounds
Questions:
- Is WASM support planned for rmcp in the near future?
- Is anyone currently working on this?
Proposal:
I'm willing to work on this if there's interest (I might do either way in a fork, as I'd really like to avoid making my own rmcp). We've recently had to deal with similar issues making some cross-platform async Rust projects wasm-compatible, there are some patterns we've used that could work here:
- Platform-conditional trait abstractions:
cfg_if::cfg_if! {
if #[cfg(target_arch = "wasm32")] {
pub trait PlatformSend {}
impl<T> PlatformSend for T {}
} else {
pub trait PlatformSend: Send {}
impl<T> PlatformSend for T where T: Send {}
}
}
pub trait SseClient: Clone + PlatformSend + 'static { ... }
pub type BoxPlatformSendFuture<T> = Pin<Box<dyn Future<Output = T> + PlatformSend>>;
- ThreadToken pattern for WASM:
- If needed, use thread-local storage for non-Send types that need to cross Send boundaries
- ^ safe access to JavaScript objects in single-threaded WASM context
- Conditional spawn implementations:
#[cfg(not(target_arch = "wasm32"))]
fn spawn_worker(fut: impl Future + Send + 'static) { tokio::spawn(fut); }
#[cfg(target_arch = "wasm32")]
fn spawn_worker(fut: impl Future + 'static) { wasm_bindgen_futures::spawn_local(fut); }
I haven't dug in depth through rmcp (I've wrote this based on what I've seen from the client-side), but we've recently done similar things in other projects and have some experience in maintaining API compatibility while supporting both native threading and WASM.
Would love to hear your plans (if any) regarding WASM support, and if it's something you'd accept PRs on.