diff --git a/crates/spirv-builder/src/lib.rs b/crates/spirv-builder/src/lib.rs index 51cc8d8f2a..38a4d3ddcd 100644 --- a/crates/spirv-builder/src/lib.rs +++ b/crates/spirv-builder/src/lib.rs @@ -91,6 +91,9 @@ use thiserror::Error; pub use rustc_codegen_spirv_types::Capability; pub use rustc_codegen_spirv_types::{CompileResult, ModuleResult}; +#[cfg(feature = "watch")] +pub use self::watch::Watch; + #[cfg(feature = "include-target-specs")] pub use rustc_codegen_spirv_target_specs::TARGET_SPEC_DIR_PATH; diff --git a/crates/spirv-builder/src/watch.rs b/crates/spirv-builder/src/watch.rs index a1f68d62f3..5689393210 100644 --- a/crates/spirv-builder/src/watch.rs +++ b/crates/spirv-builder/src/watch.rs @@ -1,22 +1,27 @@ -use crate::{SpirvBuilder, SpirvBuilderError, leaf_deps}; -use notify::{Event, RecommendedWatcher, RecursiveMode, Watcher as _}; -use rustc_codegen_spirv_types::CompileResult; +use std::convert::Infallible; use std::path::{Path, PathBuf}; use std::sync::mpsc::Receiver; +use std::thread::JoinHandle; use std::{collections::HashSet, sync::mpsc::sync_channel}; +use notify::{Event, RecommendedWatcher, RecursiveMode, Watcher as _}; +use rustc_codegen_spirv_types::CompileResult; + +use crate::{SpirvBuilder, SpirvBuilderError, leaf_deps}; + impl SpirvBuilder { - /// Watches the module for changes using [`notify`](https://crates.io/crates/notify), - /// and rebuild it upon changes. Calls `on_compilation_finishes` after each - /// successful compilation. The second `Option>` - /// param allows you to return some `T` on the first compile, which is - /// then returned by this function (wrapped in Option). + /// Watches the module for changes using [`notify`], rebuilding it upon changes. + /// + /// Calls `on_compilation_finishes` after each successful compilation. + /// The second `Option>` param allows you to return some `T` + /// on the first compile, which is then returned by this function + /// in pair with [`JoinHandle`] to the watching thread. pub fn watch( &self, mut on_compilation_finishes: impl FnMut(CompileResult, Option>) + Send + 'static, - ) -> Result, SpirvBuilderError> { + ) -> Result, SpirvBuilderError> { let path_to_crate = self .path_to_crate .as_ref() @@ -46,11 +51,11 @@ impl SpirvBuilder { } }; let metadata = self.parse_metadata_file(&metadata_file)?; - let mut out = None; - on_compilation_finishes(metadata, Some(AcceptFirstCompile(&mut out))); + let mut first_compile = None; + on_compilation_finishes(metadata, Some(AcceptFirstCompile(&mut first_compile))); let builder = self.clone(); - let thread = std::thread::spawn(move || { + let watch_thread = std::thread::spawn(move || { let mut watcher = Watcher::new(); watcher.watch_leaf_deps(&metadata_file); @@ -66,8 +71,11 @@ impl SpirvBuilder { } } }); - drop(thread); - Ok(out) + + Ok(Watch { + first_compile, + watch_thread, + }) } } @@ -83,6 +91,19 @@ impl<'a, T> AcceptFirstCompile<'a, T> { } } +/// Result of [watching](SpirvBuilder::watch) a module for changes. +#[must_use] +#[non_exhaustive] +pub struct Watch { + /// Result of the first compile, if any. + pub first_compile: Option, + /// Join handle to the watching thread. + /// + /// You can drop it to detach the watching thread, + /// or [`join()`](JoinHandle::join) it to block the current thread until shutdown of the program. + pub watch_thread: JoinHandle, +} + struct Watcher { watcher: RecommendedWatcher, rx: Receiver<()>, diff --git a/examples/runners/wgpu/src/lib.rs b/examples/runners/wgpu/src/lib.rs index 280dd3510c..da3c705598 100644 --- a/examples/runners/wgpu/src/lib.rs +++ b/examples/runners/wgpu/src/lib.rs @@ -187,6 +187,7 @@ fn maybe_watch( } }) .expect("Configuration is correct for watching") + .first_compile .unwrap() } else { handle_compile_result(builder.build().unwrap())