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
3 changes: 3 additions & 0 deletions crates/spirv-builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
49 changes: 35 additions & 14 deletions crates/spirv-builder/src/watch.rs
Original file line number Diff line number Diff line change
@@ -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<AcceptFirstCompile<T>>`
/// 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<AcceptFirstCompile<T>>` 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<T>(
&self,
mut on_compilation_finishes: impl FnMut(CompileResult, Option<AcceptFirstCompile<'_, T>>)
+ Send
+ 'static,
) -> Result<Option<T>, SpirvBuilderError> {
) -> Result<Watch<T>, SpirvBuilderError> {
let path_to_crate = self
.path_to_crate
.as_ref()
Expand Down Expand Up @@ -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);

Expand All @@ -66,8 +71,11 @@ impl SpirvBuilder {
}
}
});
drop(thread);
Ok(out)

Ok(Watch {
first_compile,
watch_thread,
})
}
}

Expand All @@ -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<T> {
/// Result of the first compile, if any.
pub first_compile: Option<T>,
/// 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<Infallible>,
}

struct Watcher {
watcher: RecommendedWatcher,
rx: Receiver<()>,
Expand Down
1 change: 1 addition & 0 deletions examples/runners/wgpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ fn maybe_watch(
}
})
.expect("Configuration is correct for watching")
.first_compile
.unwrap()
} else {
handle_compile_result(builder.build().unwrap())
Expand Down