implement more robust file watcher

This commit is contained in:
2022-01-29 15:22:14 +01:00
parent 381eaf970f
commit f21497dd2e
6 changed files with 93 additions and 104 deletions

1
Cargo.lock generated
View File

@@ -1524,6 +1524,7 @@ dependencies = [
"minifb", "minifb",
"notify", "notify",
"pico-args", "pico-args",
"same-file",
"uw8-tool", "uw8-tool",
"wasmtime", "wasmtime",
"wat", "wat",

View File

@@ -14,3 +14,4 @@ pico-args = "0.4"
curlywas = { git = "https://github.com/exoticorn/curlywas.git", rev = "196719b" } curlywas = { git = "https://github.com/exoticorn/curlywas.git", rev = "196719b" }
wat = "1" wat = "1"
uw8-tool = { path = "uw8-tool" } uw8-tool = { path = "uw8-tool" }
same-file = "1"

View File

@@ -1,102 +1,21 @@
import "env.memory" memory(4); import "env.memory" memory(4);
import "env.cls" fn cls(i32); import "env.cls" fn cls(i32);
import "env.setPixel" fn setPixel(i32, i32, i32);
import "env.time" fn time() -> f32; 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.sin" fn sin(f32) -> f32;
import "env.cos" fn cos(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() { export fn upd() {
cls(0); cls(0);
// line(0.0, 4.0, 7.0, -2.0, 15);
// return;
let i: i32; let i: i32;
loop lines { loop lines {
let angle = i as f32 * (3.1415 / 25.0) + time() * 0.1; let angle = i as f32 * (3.1415 / 25.0) + time() * 0.125;
line(160.0, 120.0, 160.0 + sin(angle) * 100.0, 120.0 + cos(angle) * 100.0, 47); 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; branch_if (i := i + 1) < 50: lines;
} }
} }

70
src/filewatcher.rs Normal file
View File

@@ -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<PathBuf>,
rx: mpsc::Receiver<DebouncedEvent>,
}
pub struct FileWatcherBuilder(BTreeSet<PathBuf>);
impl FileWatcher {
pub fn builder() -> FileWatcherBuilder {
FileWatcherBuilder(BTreeSet::new())
}
pub fn poll_changed_file(&self) -> Result<Option<PathBuf>> {
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<P: Into<PathBuf>>(&mut self, path: P) -> &mut Self {
self.0.insert(path.into());
self
}
pub fn build(self) -> Result<FileWatcher> {
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,
})
}
}

View File

@@ -10,6 +10,10 @@ use wasmtime::{
Engine, GlobalType, Memory, MemoryType, Module, Mutability, Store, TypedFunc, ValType, Engine, GlobalType, Memory, MemoryType, Module, Mutability, Store, TypedFunc, ValType,
}; };
mod filewatcher;
pub use filewatcher::FileWatcher;
static GAMEPAD_KEYS: &'static [Key] = &[ static GAMEPAD_KEYS: &'static [Key] = &[
Key::Up, Key::Up,
Key::Down, Key::Down,

View File

@@ -1,17 +1,14 @@
use std::fs::File; use std::fs::File;
use std::io::prelude::*; use std::io::prelude::*;
use std::process; use std::process;
use std::sync::mpsc;
use std::time::Duration;
use std::{ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
process::exit, process::exit,
}; };
use anyhow::{bail, Result}; use anyhow::Result;
use notify::{DebouncedEvent, Watcher};
use pico_args::Arguments; use pico_args::Arguments;
use uw8::MicroW8; use uw8::{FileWatcher, MicroW8};
fn main() -> Result<()> { fn main() -> Result<()> {
let mut args = Arguments::from_env(); let mut args = Arguments::from_env();
@@ -72,13 +69,14 @@ fn run(mut args: Arguments) -> Result<()> {
uw8.set_timeout(timeout); uw8.set_timeout(timeout);
} }
let (tx, rx) = mpsc::channel(); let mut watcher = FileWatcher::builder();
let mut watcher = notify::watcher(tx, Duration::from_millis(100))?;
if watch_mode { 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) { if let Err(err) = start_cart(&filename, &mut uw8, &config) {
eprintln!("Load error: {}", err); eprintln!("Load error: {}", err);
if !watch_mode { if !watch_mode {
@@ -87,15 +85,11 @@ fn run(mut args: Arguments) -> Result<()> {
} }
while uw8.is_open() { while uw8.is_open() {
match rx.try_recv() { if watcher.poll_changed_file()?.is_some() {
Ok(DebouncedEvent::Create(_) | DebouncedEvent::Write(_)) => {
if let Err(err) = start_cart(&filename, &mut uw8, &config) { if let Err(err) = start_cart(&filename, &mut uw8, &config) {
eprintln!("Load error: {}", err); eprintln!("Load error: {}", err);
} }
} }
Err(mpsc::TryRecvError::Disconnected) => bail!("File watcher disconnected"),
_ => (),
}
if let Err(err) = uw8.run_frame() { if let Err(err) = uw8.run_frame() {
eprintln!("Runtime error: {}", err); eprintln!("Runtime error: {}", err);