diff --git a/ldraw/src/library.rs b/ldraw/src/library.rs index f60489c..f7f97d5 100644 --- a/ldraw/src/library.rs +++ b/ldraw/src/library.rs @@ -27,7 +27,8 @@ pub enum FileLocation { Local, } -#[async_trait(?Send)] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] pub trait DocumentLoader { async fn load_document( &self, @@ -36,7 +37,8 @@ pub trait DocumentLoader { ) -> Result; } -#[async_trait(?Send)] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] pub trait LibraryLoader { async fn load_colors(&self) -> Result; diff --git a/ldraw/src/resolvers/http.rs b/ldraw/src/resolvers/http.rs index 33a9e97..c09067e 100644 --- a/ldraw/src/resolvers/http.rs +++ b/ldraw/src/resolvers/http.rs @@ -29,7 +29,21 @@ impl HttpLoader { } } -#[async_trait(?Send)] +/// Compile-time check that `HttpLoader::load_ref` and `load_colors` return +/// `Send` futures on non-wasm targets. See the parallel helper in +/// `resolvers::local` for context. +#[cfg(not(target_arch = "wasm32"))] +#[allow(dead_code)] +fn _assert_httploader_futures_are_send(loader: &HttpLoader, colors: &ColorCatalog) { + fn assert_send(_: &F) {} + let f1 = loader.load_ref(PartAlias::from("dummy".to_string()), false, colors); + assert_send(&f1); + let f2 = loader.load_colors(); + assert_send(&f2); +} + +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] impl DocumentLoader for HttpLoader { async fn load_document( &self, @@ -46,7 +60,8 @@ impl DocumentLoader for HttpLoader { } } -#[async_trait(?Send)] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] impl LibraryLoader for HttpLoader { async fn load_colors(&self) -> Result { let ldraw_url_base = self.ldraw_url_base.as_ref(); diff --git a/ldraw/src/resolvers/local.rs b/ldraw/src/resolvers/local.rs index b8512e0..0753083 100644 --- a/ldraw/src/resolvers/local.rs +++ b/ldraw/src/resolvers/local.rs @@ -26,7 +26,25 @@ impl LocalLoader { } } -#[async_trait(?Send)] +/// Compile-time check: on non-wasm targets, `LocalLoader::load_ref` and +/// `load_colors` must return `Send` futures so multi-threaded runtimes can +/// `.await` them on a worker thread. If the future is `!Send`, this function +/// fails to compile, which is the entire point. +/// +/// The function is never called; its body exists only to be type-checked by +/// the compiler. +#[cfg(not(target_arch = "wasm32"))] +#[allow(dead_code)] +fn _assert_localloader_futures_are_send(loader: &LocalLoader, colors: &ColorCatalog) { + fn assert_send(_: &F) {} + let f1 = loader.load_ref(PartAlias::from("dummy".to_string()), false, colors); + assert_send(&f1); + let f2 = loader.load_colors(); + assert_send(&f2); +} + +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] impl DocumentLoader for LocalLoader { async fn load_document( &self, @@ -44,7 +62,8 @@ impl DocumentLoader for LocalLoader { } } -#[async_trait(?Send)] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] impl LibraryLoader for LocalLoader { async fn load_colors(&self) -> Result { let ldrawdir = match self.ldrawdir.clone() {