diff --git a/Cargo.lock b/Cargo.lock index 7820202..0a9216e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1524,6 +1524,7 @@ dependencies = [ "minifb", "notify", "pico-args", + "same-file", "uw8-tool", "wasmtime", "wat", diff --git a/Cargo.toml b/Cargo.toml index 4a76da0..4b0710d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,5 @@ notify = "4" pico-args = "0.4" curlywas = { git = "https://github.com/exoticorn/curlywas.git", rev = "196719b" } wat = "1" -uw8-tool = { path = "uw8-tool" } \ No newline at end of file +uw8-tool = { path = "uw8-tool" } +same-file = "1" \ No newline at end of file diff --git a/examples/curlywas/line.cwa b/examples/curlywas/line.cwa index 96be84e..e1240d6 100644 --- a/examples/curlywas/line.cwa +++ b/examples/curlywas/line.cwa @@ -1,102 +1,21 @@ import "env.memory" memory(4); import "env.cls" fn cls(i32); -import "env.setPixel" fn setPixel(i32, i32, i32); import "env.time" fn time() -> f32; +import "env.line" fn line(f32, f32, f32, f32, i32); import "env.sin" fn sin(f32) -> f32; import "env.cos" fn cos(f32) -> f32; -fn line(x1: f32, y1: f32, x2: f32, y2: f32, col: i32) { - let swapTmp: f32; - if x1 > x2 { - swapTmp = x1; - x1 = x2; - x2 = swapTmp; - swapTmp = y1; - y1 = y2; - y2 = swapTmp; - } - if x1 < 0 as f32 & x2 >= 0 as f32 { - y1 = y1 + (y2 - y1) * -x1 / (x2 - x1); - x1 = 0 as f32; - } - if x1 < 320 as f32 & x2 >= 320 as f32 { - y2 = y2 + (y2 - y1) * (320 as f32 - x2) / (x2 - x1); - x2 = 320 as f32; - } - - if y1 > y2 { - swapTmp = x1; - x1 = x2; - x2 = swapTmp; - swapTmp = y1; - y1 = y2; - y2 = swapTmp; - } - if y1 < 0 as f32 & y2 >= 0 as f32 { - x1 = x1 + (x2 - x1) * -y1 / (y2 - y1); - y1 = 0 as f32; - } - if y1 < 240 as f32 & y2 >= 240 as f32 { - x2 = x2 + (x2 - x1) * (240 as f32 - y2) / (y2 - y1); - y2 = 240 as f32; - } - - let lazy dx = x2 - x1; - let lazy dy = y2 - y1; - let max_axis: f32; - let p: f32; - if abs(dx) >= dy { - max_axis = dx; - p = x1; - } else { - max_axis = dy; - p = y1; - } - - let steps = floor(p + max_axis) as i32 - floor(p) as i32; - p = floor(p) + 0.5 - p; - if max_axis < 0 as f32 { - steps = -steps; - p = -p; - max_axis = -max_axis; - } - dx = dx / max_axis; - dy = dy / max_axis; - - let f = min(max_axis, max(0 as f32, p)); - setPixel((x1 + f * dx) as i32, (y1 + f * dy) as i32, col); - - if !steps { - return; - } - - x1 = x1 + (1 as f32 + p) * dx; - y1 = y1 + (1 as f32 + p) * dy; - - p = p + steps as f32; - - loop pixels { - if steps := steps - 1 { - setPixel(x1 as i32, y1 as i32, col); - x1 = x1 + dx; - y1 = y1 + dy; - branch pixels; - } - } - - f = min(max_axis, p) - p; - setPixel((x1 + f * dx) as i32, (y1 + f * dy) as i32, col); -} - export fn upd() { cls(0); -// line(0.0, 4.0, 7.0, -2.0, 15); -// return; let i: i32; loop lines { - let angle = i as f32 * (3.1415 / 25.0) + time() * 0.1; - line(160.0, 120.0, 160.0 + sin(angle) * 100.0, 120.0 + cos(angle) * 100.0, 47); + let angle = i as f32 * (3.1415 / 25.0) + time() * 0.125; + line( + 160 as f32, 120 as f32, + 160 as f32 + sin(angle) * 100 as f32, + 120 as f32 + cos(angle) * 100 as f32, + 47); branch_if (i := i + 1) < 50: lines; } } diff --git a/src/filewatcher.rs b/src/filewatcher.rs new file mode 100644 index 0000000..afe8317 --- /dev/null +++ b/src/filewatcher.rs @@ -0,0 +1,70 @@ +use anyhow::{bail, Result}; +use notify::{DebouncedEvent, Watcher, RecommendedWatcher}; +use std::{ + collections::BTreeSet, + path::{Path, PathBuf}, + sync::mpsc, + time::Duration, +}; + +pub struct FileWatcher { + _watcher: RecommendedWatcher, + watched_files: BTreeSet, + rx: mpsc::Receiver, +} + +pub struct FileWatcherBuilder(BTreeSet); + +impl FileWatcher { + pub fn builder() -> FileWatcherBuilder { + FileWatcherBuilder(BTreeSet::new()) + } + + pub fn poll_changed_file(&self) -> Result> { + let event = self.rx.try_recv(); + match event { + Ok(DebouncedEvent::Create(path) | DebouncedEvent::Write(path)) => { + let handle = same_file::Handle::from_path(&path)?; + for file in &self.watched_files { + if handle == same_file::Handle::from_path(file)? { + return Ok(Some(path)); + } + } + } + Err(mpsc::TryRecvError::Disconnected) => bail!("File watcher disconnected"), + _ => (), + } + + Ok(None) + } +} + +impl FileWatcherBuilder { + pub fn add_file>(&mut self, path: P) -> &mut Self { + self.0.insert(path.into()); + self + } + + pub fn build(self) -> Result { + let mut directories: BTreeSet<&Path> = BTreeSet::new(); + + for file in &self.0 { + if let Some(directory) = file.parent() { + directories.insert(directory); + } + } + + let (tx, rx) = mpsc::channel(); + let mut watcher = notify::watcher(tx, Duration::from_millis(100))?; + + for directory in directories { + watcher.watch(directory, notify::RecursiveMode::NonRecursive)?; + } + + Ok(FileWatcher { + _watcher: watcher, + watched_files: self.0, + rx, + }) + } +} diff --git a/src/lib.rs b/src/lib.rs index 5d64f9f..6d6417f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,10 @@ use wasmtime::{ Engine, GlobalType, Memory, MemoryType, Module, Mutability, Store, TypedFunc, ValType, }; +mod filewatcher; + +pub use filewatcher::FileWatcher; + static GAMEPAD_KEYS: &'static [Key] = &[ Key::Up, Key::Down, diff --git a/src/main.rs b/src/main.rs index c686757..e620e17 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,14 @@ use std::fs::File; use std::io::prelude::*; use std::process; -use std::sync::mpsc; -use std::time::Duration; use std::{ path::{Path, PathBuf}, process::exit, }; -use anyhow::{bail, Result}; -use notify::{DebouncedEvent, Watcher}; +use anyhow::Result; use pico_args::Arguments; -use uw8::MicroW8; +use uw8::{FileWatcher, MicroW8}; fn main() -> Result<()> { let mut args = Arguments::from_env(); @@ -72,13 +69,14 @@ fn run(mut args: Arguments) -> Result<()> { uw8.set_timeout(timeout); } - let (tx, rx) = mpsc::channel(); - let mut watcher = notify::watcher(tx, Duration::from_millis(100))?; + let mut watcher = FileWatcher::builder(); if watch_mode { - watcher.watch(&filename, notify::RecursiveMode::NonRecursive)?; + watcher.add_file(&filename); } + let watcher = watcher.build()?; + if let Err(err) = start_cart(&filename, &mut uw8, &config) { eprintln!("Load error: {}", err); if !watch_mode { @@ -87,14 +85,10 @@ fn run(mut args: Arguments) -> Result<()> { } while uw8.is_open() { - match rx.try_recv() { - Ok(DebouncedEvent::Create(_) | DebouncedEvent::Write(_)) => { - if let Err(err) = start_cart(&filename, &mut uw8, &config) { - eprintln!("Load error: {}", err); - } + if watcher.poll_changed_file()?.is_some() { + if let Err(err) = start_cart(&filename, &mut uw8, &config) { + eprintln!("Load error: {}", err); } - Err(mpsc::TryRecvError::Disconnected) => bail!("File watcher disconnected"), - _ => (), } if let Err(err) = uw8.run_frame() {