Skip to content

Add wasm32 support to the rust sdk #2704

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
Draft
100 changes: 95 additions & 5 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ spacetimedb-subscription = { path = "crates/subscription", version = "1.1.1" }
# from appearing in module dependency graphs.
ahash = { version = "0.8", default-features = false, features = ["std"] }
anyhow = "1.0.68"
anymap = "0.12"
anymap = { package = "anymap3", version = "1.0.1" }
arrayvec = "0.7.2"
async-stream = "0.3.6"
async-trait = "0.1.68"
Expand Down
43 changes: 41 additions & 2 deletions crates/codegen/src/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1210,6 +1210,7 @@ impl __sdk::InModule for RemoteTables {{
///
/// - [`DbConnection::frame_tick`].
/// - [`DbConnection::run_threaded`].
/// - [`DbConnection::run_background`].
/// - [`DbConnection::run_async`].
/// - [`DbConnection::advance_one_message`].
/// - [`DbConnection::advance_one_message_blocking`].
Expand Down Expand Up @@ -1309,8 +1310,19 @@ impl DbConnection {{
/// This is a low-level primitive exposed for power users who need significant control over scheduling.
/// Most applications should call [`Self::run_threaded`] to spawn a thread
/// which advances the connection automatically.
///
/// # Panics
/// At runtime if called on any `wasm32` target.
pub fn advance_one_message_blocking(&self) -> __sdk::Result<()> {{
self.imp.advance_one_message_blocking()
#[cfg(target_arch = \"wasm32\")]
{{
panic!(\"`DbConnection::advance_one_message_blocking` is not supported on WebAssembly (wasm32); \\
prefer using `advance_one_message` or `advance_one_message_async` instead\");
}}
#[cfg(not(target_arch = \"wasm32\"))]
{{
self.imp.advance_one_message_blocking()
}}
}}

/// Process one WebSocket message, `await`ing until one is received.
Expand All @@ -1334,8 +1346,35 @@ impl DbConnection {{
}}

/// Spawn a thread which processes WebSocket messages as they are received.
///
/// # Panics
/// At runtime if called on any `wasm32` target.
pub fn run_threaded(&self) -> std::thread::JoinHandle<()> {{
self.imp.run_threaded()
#[cfg(target_arch = \"wasm32\")]
{{
panic!(\"`DbConnection::run_threaded` is not supported on WebAssembly (wasm32); \\
prefer using `DbConnection::run_background` instead\");
}}
#[cfg(not(target_arch = \"wasm32\"))]
{{
self.imp.run_threaded()
}}
}}

/// Spawn a task which processes WebSocket messages as they are received.
///
/// # Panics
/// At runtime if called on any non-`wasm32` target.
pub fn run_background(&self) {{
#[cfg(not(target_arch = \"wasm32\"))]
{{
panic!(\"`DbConnection::run_background` is only supported on WebAssembly (wasm32); \\
prefer using `DbConnection::run_threaded` instead\");
}}
#[cfg(target_arch = \"wasm32\")]
{{
self.imp.run_background()
}}
}}

/// Run an `async` loop which processes WebSocket messages when polled.
Expand Down
43 changes: 41 additions & 2 deletions crates/codegen/tests/snapshots/codegen__codegen_rust.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1753,6 +1753,7 @@ impl __sdk::InModule for RemoteTables {
///
/// - [`DbConnection::frame_tick`].
/// - [`DbConnection::run_threaded`].
/// - [`DbConnection::run_background`].
/// - [`DbConnection::run_async`].
/// - [`DbConnection::advance_one_message`].
/// - [`DbConnection::advance_one_message_blocking`].
Expand Down Expand Up @@ -1852,8 +1853,19 @@ impl DbConnection {
/// This is a low-level primitive exposed for power users who need significant control over scheduling.
/// Most applications should call [`Self::run_threaded`] to spawn a thread
/// which advances the connection automatically.
///
/// # Panics
/// At runtime if called on any `wasm32` target.
pub fn advance_one_message_blocking(&self) -> __sdk::Result<()> {
self.imp.advance_one_message_blocking()
#[cfg(target_arch = "wasm32")]
{
panic!("`DbConnection::advance_one_message_blocking` is not supported on WebAssembly (wasm32); \
prefer using `advance_one_message` or `advance_one_message_async` instead");
}
#[cfg(not(target_arch = "wasm32"))]
{
self.imp.advance_one_message_blocking()
}
}

/// Process one WebSocket message, `await`ing until one is received.
Expand All @@ -1877,8 +1889,35 @@ impl DbConnection {
}

/// Spawn a thread which processes WebSocket messages as they are received.
///
/// # Panics
/// At runtime if called on any `wasm32` target.
pub fn run_threaded(&self) -> std::thread::JoinHandle<()> {
self.imp.run_threaded()
#[cfg(target_arch = "wasm32")]
{
panic!("`DbConnection::run_threaded` is not supported on WebAssembly (wasm32); \
prefer using `DbConnection::run_background` instead");
}
#[cfg(not(target_arch = "wasm32"))]
{
self.imp.run_threaded()
}
}

/// Spawn a task which processes WebSocket messages as they are received.
///
/// # Panics
/// At runtime if called on any non-`wasm32` target.
pub fn run_background(&self) {
#[cfg(not(target_arch = "wasm32"))]
{
panic!("`DbConnection::run_background` is only supported on WebAssembly (wasm32); \
prefer using `DbConnection::run_threaded` instead");
}
#[cfg(target_arch = "wasm32")]
{
self.imp.run_background()
}
}

/// Run an `async` loop which processes WebSocket messages when polled.
Expand Down
30 changes: 29 additions & 1 deletion crates/sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@ description = "A Rust SDK for clients to interface with SpacetimeDB"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
default = []
web = [
"dep:getrandom",
"dep:gloo-console",
"dep:gloo-net",
"dep:gloo-storage",
"dep:js-sys",
"dep:tokio-tungstenite-wasm",
"dep:wasm-bindgen",
"dep:wasm-bindgen-futures",
"dep:web-sys",
]

[dependencies]
spacetimedb-data-structures.workspace = true
spacetimedb-sats.workspace = true
Expand All @@ -21,12 +35,26 @@ brotli.workspace = true
bytes.workspace = true
futures.workspace = true
futures-channel.workspace = true
home.workspace = true
http.workspace = true
log.workspace = true
once_cell.workspace = true
prometheus.workspace = true
rand.workspace = true

getrandom = { version = "0.3.2", features = ["wasm_js"], optional = true }
gloo-console = { version = "0.3.0", optional = true }
gloo-net = { version = "0.6.0", optional = true }
gloo-storage = { version = "0.3.0", optional = true }
js-sys = { version = "0.3", optional = true }
tokio-tungstenite-wasm = { version = "0.6.0", optional = true }
wasm-bindgen = { version = "0.2.100", optional = true }
wasm-bindgen-futures = { version = "0.4.45", optional = true }
web-sys = { version = "0.3.77", features = [
"Document", "HtmlDocument", "Window"
], optional = true}

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
home.workspace = true
tokio.workspace = true
tokio-tungstenite.workspace = true

Expand Down
8 changes: 4 additions & 4 deletions crates/sdk/src/client_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use crate::callbacks::CallbackId;
use crate::db_connection::{PendingMutation, SharedCell};
use crate::spacetime_module::{InModule, SpacetimeModule, TableUpdate, WithBsatn};
use anymap::{any::Any, Map};
use anymap::Map;
use bytes::Bytes;
use core::any::type_name;
use core::hash::Hash;
Expand Down Expand Up @@ -282,7 +282,7 @@ impl<Row: Clone + Send + Sync + 'static> TableCache<Row> {
/// Called by the codegen when initializing the client cache during [`crate::DbConnectionBuilder::build`].
pub fn add_unique_constraint<Col>(&mut self, unique_index_name: &'static str, get_unique_col: fn(&Row) -> &Col)
where
Col: Any + Clone + std::hash::Hash + Eq + Send + Sync + std::fmt::Debug + 'static,
Col: std::any::Any + Clone + std::hash::Hash + Eq + Send + Sync + std::fmt::Debug + 'static,
{
assert!(self.entries.is_empty(), "Cannot add a unique constraint to a populated table; constraints should only be added during initialization, before subscribing to any rows.");
if self
Expand All @@ -306,7 +306,7 @@ pub struct ClientCache<M: SpacetimeModule + ?Sized> {
/// "keyed" on the type `HashMap<&'static str, TableCache<Row>`.
///
/// The strings are table names, since we may have multiple tables with the same row type.
tables: Map<dyn Any + Send + Sync>,
tables: Map<dyn std::any::Any + Send + Sync>,

_module: PhantomData<M>,
}
Expand Down Expand Up @@ -572,7 +572,7 @@ pub struct UniqueIndexImpl<Row, Col> {
impl<Row, Col> UniqueIndexDyn for UniqueIndexImpl<Row, Col>
where
Row: Clone + Send + Sync + 'static,
Col: Any + Clone + std::hash::Hash + Eq + Send + Sync + std::fmt::Debug + 'static,
Col: std::any::Any + Clone + std::hash::Hash + Eq + Send + Sync + std::fmt::Debug + 'static,
{
type Row = Row;
fn add_row(&mut self, row: Self::Row) {
Expand Down
Loading