mirror of
https://github.com/hannobraun/Fornjot
synced 2025-02-26 09:05:52 +00:00
Merge pull request #381 from hannobraun/host
Extract `fj-host` from `fj-app`
This commit is contained in:
commit
ff5564614b
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -631,12 +631,11 @@ dependencies = [
|
|||||||
"figment",
|
"figment",
|
||||||
"fj",
|
"fj",
|
||||||
"fj-debug",
|
"fj-debug",
|
||||||
|
"fj-host",
|
||||||
"fj-math",
|
"fj-math",
|
||||||
"fj-operations",
|
"fj-operations",
|
||||||
"futures",
|
"futures",
|
||||||
"libloading",
|
|
||||||
"nalgebra",
|
"nalgebra",
|
||||||
"notify",
|
|
||||||
"parry3d-f64",
|
"parry3d-f64",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@ -655,6 +654,16 @@ dependencies = [
|
|||||||
"parry3d-f64",
|
"parry3d-f64",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fj-host"
|
||||||
|
version = "0.5.0"
|
||||||
|
dependencies = [
|
||||||
|
"fj",
|
||||||
|
"libloading",
|
||||||
|
"notify",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fj-kernel"
|
name = "fj-kernel"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -4,6 +4,7 @@ members = [
|
|||||||
"fj",
|
"fj",
|
||||||
"fj-app",
|
"fj-app",
|
||||||
"fj-debug",
|
"fj-debug",
|
||||||
|
"fj-host",
|
||||||
"fj-kernel",
|
"fj-kernel",
|
||||||
"fj-math",
|
"fj-math",
|
||||||
"fj-operations",
|
"fj-operations",
|
||||||
@ -18,6 +19,7 @@ members = [
|
|||||||
default-members = [
|
default-members = [
|
||||||
"fj-app",
|
"fj-app",
|
||||||
"fj-debug",
|
"fj-debug",
|
||||||
|
"fj-host",
|
||||||
"fj-kernel",
|
"fj-kernel",
|
||||||
"fj-math",
|
"fj-math",
|
||||||
"fj-operations",
|
"fj-operations",
|
||||||
|
@ -15,9 +15,7 @@ categories = ["mathematics", "rendering"]
|
|||||||
anyhow = "1.0.56"
|
anyhow = "1.0.56"
|
||||||
bytemuck = "1.8.0"
|
bytemuck = "1.8.0"
|
||||||
futures = "0.3.21"
|
futures = "0.3.21"
|
||||||
libloading = "0.7.2"
|
|
||||||
nalgebra = "0.30.0"
|
nalgebra = "0.30.0"
|
||||||
notify = "5.0.0-pre.14"
|
|
||||||
parry3d-f64 = "0.8.0"
|
parry3d-f64 = "0.8.0"
|
||||||
thiserror = "1.0.30"
|
thiserror = "1.0.30"
|
||||||
threemf = "0.2.0"
|
threemf = "0.2.0"
|
||||||
@ -42,6 +40,10 @@ path = "../fj"
|
|||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
path = "../fj-debug"
|
path = "../fj-debug"
|
||||||
|
|
||||||
|
[dependencies.fj-host]
|
||||||
|
version = "0.5.0"
|
||||||
|
path = "../fj-host"
|
||||||
|
|
||||||
[dependencies.fj-math]
|
[dependencies.fj-math]
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
path = "../fj-math"
|
path = "../fj-math"
|
||||||
|
@ -4,13 +4,13 @@ mod config;
|
|||||||
mod graphics;
|
mod graphics;
|
||||||
mod input;
|
mod input;
|
||||||
mod mesh;
|
mod mesh;
|
||||||
mod model;
|
|
||||||
mod window;
|
mod window;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::{collections::HashMap, time::Instant};
|
use std::{collections::HashMap, time::Instant};
|
||||||
|
|
||||||
use fj_debug::DebugInfo;
|
use fj_debug::DebugInfo;
|
||||||
|
use fj_host::Model;
|
||||||
use fj_math::{Aabb, Scalar, Triangle};
|
use fj_math::{Aabb, Scalar, Triangle};
|
||||||
use fj_operations::ToShape as _;
|
use fj_operations::ToShape as _;
|
||||||
use futures::executor::block_on;
|
use futures::executor::block_on;
|
||||||
@ -28,7 +28,6 @@ use crate::{
|
|||||||
config::Config,
|
config::Config,
|
||||||
graphics::{DrawConfig, Renderer},
|
graphics::{DrawConfig, Renderer},
|
||||||
mesh::MeshMaker,
|
mesh::MeshMaker,
|
||||||
model::Model,
|
|
||||||
window::Window,
|
window::Window,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,235 +0,0 @@
|
|||||||
use std::{
|
|
||||||
collections::{HashMap, HashSet},
|
|
||||||
ffi::OsStr,
|
|
||||||
io,
|
|
||||||
path::PathBuf,
|
|
||||||
process::Command,
|
|
||||||
sync::mpsc,
|
|
||||||
thread,
|
|
||||||
};
|
|
||||||
|
|
||||||
use notify::Watcher as _;
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
pub struct Model {
|
|
||||||
src_path: PathBuf,
|
|
||||||
lib_path: PathBuf,
|
|
||||||
manifest_path: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Model {
|
|
||||||
pub fn from_path(
|
|
||||||
path: PathBuf,
|
|
||||||
target_dir: Option<PathBuf>,
|
|
||||||
) -> io::Result<Self> {
|
|
||||||
let name = {
|
|
||||||
// Can't panic. It only would, if the path ends with "..", and we
|
|
||||||
// are canonicalizing it here to prevent that.
|
|
||||||
let canonical = path.canonicalize()?;
|
|
||||||
let file_name = canonical.file_name().unwrap();
|
|
||||||
|
|
||||||
file_name.to_string_lossy().replace('-', "_")
|
|
||||||
};
|
|
||||||
|
|
||||||
let src_path = path.join("src");
|
|
||||||
|
|
||||||
let lib_path = {
|
|
||||||
let file = if cfg!(windows) {
|
|
||||||
format!("{}.dll", name)
|
|
||||||
} else if cfg!(target_os = "macos") {
|
|
||||||
format!("lib{}.dylib", name)
|
|
||||||
} else {
|
|
||||||
//Unix
|
|
||||||
format!("lib{}.so", name)
|
|
||||||
};
|
|
||||||
|
|
||||||
let target_dir = target_dir.unwrap_or_else(|| path.join("target"));
|
|
||||||
target_dir.join("debug").join(file)
|
|
||||||
};
|
|
||||||
|
|
||||||
let manifest_path = path.join("Cargo.toml");
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
src_path,
|
|
||||||
lib_path,
|
|
||||||
manifest_path,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_once(
|
|
||||||
&self,
|
|
||||||
arguments: &HashMap<String, String>,
|
|
||||||
) -> Result<fj::Shape, Error> {
|
|
||||||
let manifest_path = self.manifest_path.display().to_string();
|
|
||||||
|
|
||||||
let status = Command::new("cargo")
|
|
||||||
.arg("build")
|
|
||||||
.args(["--manifest-path", &manifest_path])
|
|
||||||
.status()?;
|
|
||||||
|
|
||||||
if !status.success() {
|
|
||||||
return Err(Error::Compile);
|
|
||||||
}
|
|
||||||
|
|
||||||
// So, strictly speaking this is all unsound:
|
|
||||||
// - `Library::new` requires us to abide by the arbitrary requirements
|
|
||||||
// of any library initialization or termination routines.
|
|
||||||
// - `Library::get` requires us to specify the correct type for the
|
|
||||||
// model function.
|
|
||||||
// - The model function itself is `unsafe`, because it is a function
|
|
||||||
// from across an FFI interface.
|
|
||||||
//
|
|
||||||
// Typical models won't have initialization or termination routines (I
|
|
||||||
// think), should abide by the `ModelFn` signature, and might not do
|
|
||||||
// anything unsafe. But we have no way to know that the library the user
|
|
||||||
// told us to load actually does (I think).
|
|
||||||
//
|
|
||||||
// I don't know of a way to fix this. We should take this as motivation
|
|
||||||
// to switch to a better technique:
|
|
||||||
// https://github.com/hannobraun/Fornjot/issues/71
|
|
||||||
let shape = unsafe {
|
|
||||||
let lib = libloading::Library::new(&self.lib_path)?;
|
|
||||||
let model: libloading::Symbol<ModelFn> = lib.get(b"model")?;
|
|
||||||
model(arguments)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(shape)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_and_watch(
|
|
||||||
self,
|
|
||||||
parameters: HashMap<String, String>,
|
|
||||||
) -> Result<Watcher, Error> {
|
|
||||||
let (tx, rx) = mpsc::sync_channel(0);
|
|
||||||
let tx2 = tx.clone();
|
|
||||||
|
|
||||||
let watch_path = self.src_path.clone();
|
|
||||||
|
|
||||||
let mut watcher = notify::recommended_watcher(
|
|
||||||
move |event: notify::Result<notify::Event>| {
|
|
||||||
// Unfortunately the `notify` documentation doesn't say when
|
|
||||||
// this might happen, so no idea if it needs to be handled.
|
|
||||||
let event = event.expect("Error handling watch event");
|
|
||||||
|
|
||||||
// Various acceptable ModifyKind kinds. Varies across platforms
|
|
||||||
// (e.g. MacOs vs. Windows10)
|
|
||||||
if let notify::EventKind::Modify(
|
|
||||||
notify::event::ModifyKind::Any,
|
|
||||||
)
|
|
||||||
| notify::EventKind::Modify(
|
|
||||||
notify::event::ModifyKind::Data(
|
|
||||||
notify::event::DataChange::Any,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
| notify::EventKind::Modify(
|
|
||||||
notify::event::ModifyKind::Data(
|
|
||||||
notify::event::DataChange::Content,
|
|
||||||
),
|
|
||||||
) = event.kind
|
|
||||||
{
|
|
||||||
let file_ext = event
|
|
||||||
.paths
|
|
||||||
.get(0)
|
|
||||||
.expect("File path missing in watch event")
|
|
||||||
.extension();
|
|
||||||
|
|
||||||
let black_list = HashSet::from([
|
|
||||||
OsStr::new("swp"),
|
|
||||||
OsStr::new("tmp"),
|
|
||||||
OsStr::new("swx"),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if let Some(ext) = file_ext {
|
|
||||||
if black_list.contains(ext) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This will panic, if the other end is disconnected, which
|
|
||||||
// is probably the result of a panic on that thread, or the
|
|
||||||
// application is being shut down.
|
|
||||||
//
|
|
||||||
// Either way, not much we can do about it here, except
|
|
||||||
// maybe to provide a better error message in the future.
|
|
||||||
tx.send(()).unwrap();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
watcher.watch(&watch_path, notify::RecursiveMode::Recursive)?;
|
|
||||||
|
|
||||||
// To prevent a race condition between the initial load and the start of
|
|
||||||
// watching, we'll trigger the initial load here, after having started
|
|
||||||
// watching.
|
|
||||||
//
|
|
||||||
// Will panic, if the receiving end has panicked. Not much we can do
|
|
||||||
// about that, if it happened.
|
|
||||||
thread::spawn(move || tx2.send(()).unwrap());
|
|
||||||
|
|
||||||
Ok(Watcher {
|
|
||||||
_watcher: Box::new(watcher),
|
|
||||||
channel: rx,
|
|
||||||
model: self,
|
|
||||||
parameters,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Watcher {
|
|
||||||
_watcher: Box<dyn notify::Watcher>,
|
|
||||||
channel: mpsc::Receiver<()>,
|
|
||||||
model: Model,
|
|
||||||
parameters: HashMap<String, String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Watcher {
|
|
||||||
pub fn receive(&self) -> Option<fj::Shape> {
|
|
||||||
match self.channel.try_recv() {
|
|
||||||
Ok(()) => {
|
|
||||||
let shape = match self.model.load_once(&self.parameters) {
|
|
||||||
Ok(shape) => shape,
|
|
||||||
Err(Error::Compile) => {
|
|
||||||
// It would be better to display an error in the UI,
|
|
||||||
// where the user can actually see it. Issue:
|
|
||||||
// https://github.com/hannobraun/fornjot/issues/30
|
|
||||||
println!("Error compiling model");
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
panic!("Error reloading model: {:?}", err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(shape)
|
|
||||||
}
|
|
||||||
Err(mpsc::TryRecvError::Empty) => {
|
|
||||||
// Nothing to receive from the channel.
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Err(mpsc::TryRecvError::Disconnected) => {
|
|
||||||
// The other end has disconnected. This is probably the result
|
|
||||||
// of a panic on the other thread, or a program shutdown in
|
|
||||||
// progress. In any case, not much we can do here.
|
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum Error {
|
|
||||||
#[error("Error compiling model")]
|
|
||||||
Compile,
|
|
||||||
|
|
||||||
#[error("I/O error while loading model")]
|
|
||||||
Io(#[from] io::Error),
|
|
||||||
|
|
||||||
#[error("Error loading model from dynamic library")]
|
|
||||||
LibLoading(#[from] libloading::Error),
|
|
||||||
|
|
||||||
#[error("Error watching model for changes")]
|
|
||||||
Notify(#[from] notify::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
type ModelFn =
|
|
||||||
unsafe extern "C" fn(args: &HashMap<String, String>) -> fj::Shape;
|
|
@ -4,6 +4,17 @@ version = "0.5.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
description = "The world needs another CAD program."
|
description = "The world needs another CAD program."
|
||||||
readme = "README.md"
|
readme = "../README.md"
|
||||||
repository = "https://github.com/hannobraun/fornjot"
|
repository = "https://github.com/hannobraun/fornjot"
|
||||||
license = "0BSD"
|
license = "0BSD"
|
||||||
|
keywords = ["cad", "programmatic", "code-cad"]
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libloading = "0.7.2"
|
||||||
|
notify = "5.0.0-pre.14"
|
||||||
|
thiserror = "1.0.30"
|
||||||
|
|
||||||
|
[dependencies.fj]
|
||||||
|
version = "0.5.0"
|
||||||
|
path = "../fj"
|
||||||
|
@ -1 +0,0 @@
|
|||||||
`fj-host` has been renamed to `fj-app`. Please refer to the [`fj-app` crate](https://crates.io/crates/fj-app).
|
|
@ -1,3 +1,235 @@
|
|||||||
compile_error!(
|
use std::{
|
||||||
"`fj-host has been renamed to `fj-app`: https://crates.io/crates/fj-app"
|
collections::{HashMap, HashSet},
|
||||||
);
|
ffi::OsStr,
|
||||||
|
io,
|
||||||
|
path::PathBuf,
|
||||||
|
process::Command,
|
||||||
|
sync::mpsc,
|
||||||
|
thread,
|
||||||
|
};
|
||||||
|
|
||||||
|
use notify::Watcher as _;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
pub struct Model {
|
||||||
|
src_path: PathBuf,
|
||||||
|
lib_path: PathBuf,
|
||||||
|
manifest_path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Model {
|
||||||
|
pub fn from_path(
|
||||||
|
path: PathBuf,
|
||||||
|
target_dir: Option<PathBuf>,
|
||||||
|
) -> io::Result<Self> {
|
||||||
|
let name = {
|
||||||
|
// Can't panic. It only would, if the path ends with "..", and we
|
||||||
|
// are canonicalizing it here to prevent that.
|
||||||
|
let canonical = path.canonicalize()?;
|
||||||
|
let file_name = canonical.file_name().unwrap();
|
||||||
|
|
||||||
|
file_name.to_string_lossy().replace('-', "_")
|
||||||
|
};
|
||||||
|
|
||||||
|
let src_path = path.join("src");
|
||||||
|
|
||||||
|
let lib_path = {
|
||||||
|
let file = if cfg!(windows) {
|
||||||
|
format!("{}.dll", name)
|
||||||
|
} else if cfg!(target_os = "macos") {
|
||||||
|
format!("lib{}.dylib", name)
|
||||||
|
} else {
|
||||||
|
//Unix
|
||||||
|
format!("lib{}.so", name)
|
||||||
|
};
|
||||||
|
|
||||||
|
let target_dir = target_dir.unwrap_or_else(|| path.join("target"));
|
||||||
|
target_dir.join("debug").join(file)
|
||||||
|
};
|
||||||
|
|
||||||
|
let manifest_path = path.join("Cargo.toml");
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
src_path,
|
||||||
|
lib_path,
|
||||||
|
manifest_path,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_once(
|
||||||
|
&self,
|
||||||
|
arguments: &HashMap<String, String>,
|
||||||
|
) -> Result<fj::Shape, Error> {
|
||||||
|
let manifest_path = self.manifest_path.display().to_string();
|
||||||
|
|
||||||
|
let status = Command::new("cargo")
|
||||||
|
.arg("build")
|
||||||
|
.args(["--manifest-path", &manifest_path])
|
||||||
|
.status()?;
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
return Err(Error::Compile);
|
||||||
|
}
|
||||||
|
|
||||||
|
// So, strictly speaking this is all unsound:
|
||||||
|
// - `Library::new` requires us to abide by the arbitrary requirements
|
||||||
|
// of any library initialization or termination routines.
|
||||||
|
// - `Library::get` requires us to specify the correct type for the
|
||||||
|
// model function.
|
||||||
|
// - The model function itself is `unsafe`, because it is a function
|
||||||
|
// from across an FFI interface.
|
||||||
|
//
|
||||||
|
// Typical models won't have initialization or termination routines (I
|
||||||
|
// think), should abide by the `ModelFn` signature, and might not do
|
||||||
|
// anything unsafe. But we have no way to know that the library the user
|
||||||
|
// told us to load actually does (I think).
|
||||||
|
//
|
||||||
|
// I don't know of a way to fix this. We should take this as motivation
|
||||||
|
// to switch to a better technique:
|
||||||
|
// https://github.com/hannobraun/Fornjot/issues/71
|
||||||
|
let shape = unsafe {
|
||||||
|
let lib = libloading::Library::new(&self.lib_path)?;
|
||||||
|
let model: libloading::Symbol<ModelFn> = lib.get(b"model")?;
|
||||||
|
model(arguments)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(shape)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_and_watch(
|
||||||
|
self,
|
||||||
|
parameters: HashMap<String, String>,
|
||||||
|
) -> Result<Watcher, Error> {
|
||||||
|
let (tx, rx) = mpsc::sync_channel(0);
|
||||||
|
let tx2 = tx.clone();
|
||||||
|
|
||||||
|
let watch_path = self.src_path.clone();
|
||||||
|
|
||||||
|
let mut watcher = notify::recommended_watcher(
|
||||||
|
move |event: notify::Result<notify::Event>| {
|
||||||
|
// Unfortunately the `notify` documentation doesn't say when
|
||||||
|
// this might happen, so no idea if it needs to be handled.
|
||||||
|
let event = event.expect("Error handling watch event");
|
||||||
|
|
||||||
|
// Various acceptable ModifyKind kinds. Varies across platforms
|
||||||
|
// (e.g. MacOs vs. Windows10)
|
||||||
|
if let notify::EventKind::Modify(
|
||||||
|
notify::event::ModifyKind::Any,
|
||||||
|
)
|
||||||
|
| notify::EventKind::Modify(
|
||||||
|
notify::event::ModifyKind::Data(
|
||||||
|
notify::event::DataChange::Any,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
| notify::EventKind::Modify(
|
||||||
|
notify::event::ModifyKind::Data(
|
||||||
|
notify::event::DataChange::Content,
|
||||||
|
),
|
||||||
|
) = event.kind
|
||||||
|
{
|
||||||
|
let file_ext = event
|
||||||
|
.paths
|
||||||
|
.get(0)
|
||||||
|
.expect("File path missing in watch event")
|
||||||
|
.extension();
|
||||||
|
|
||||||
|
let black_list = HashSet::from([
|
||||||
|
OsStr::new("swp"),
|
||||||
|
OsStr::new("tmp"),
|
||||||
|
OsStr::new("swx"),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if let Some(ext) = file_ext {
|
||||||
|
if black_list.contains(ext) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will panic, if the other end is disconnected, which
|
||||||
|
// is probably the result of a panic on that thread, or the
|
||||||
|
// application is being shut down.
|
||||||
|
//
|
||||||
|
// Either way, not much we can do about it here, except
|
||||||
|
// maybe to provide a better error message in the future.
|
||||||
|
tx.send(()).unwrap();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
watcher.watch(&watch_path, notify::RecursiveMode::Recursive)?;
|
||||||
|
|
||||||
|
// To prevent a race condition between the initial load and the start of
|
||||||
|
// watching, we'll trigger the initial load here, after having started
|
||||||
|
// watching.
|
||||||
|
//
|
||||||
|
// Will panic, if the receiving end has panicked. Not much we can do
|
||||||
|
// about that, if it happened.
|
||||||
|
thread::spawn(move || tx2.send(()).unwrap());
|
||||||
|
|
||||||
|
Ok(Watcher {
|
||||||
|
_watcher: Box::new(watcher),
|
||||||
|
channel: rx,
|
||||||
|
model: self,
|
||||||
|
parameters,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Watcher {
|
||||||
|
_watcher: Box<dyn notify::Watcher>,
|
||||||
|
channel: mpsc::Receiver<()>,
|
||||||
|
model: Model,
|
||||||
|
parameters: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Watcher {
|
||||||
|
pub fn receive(&self) -> Option<fj::Shape> {
|
||||||
|
match self.channel.try_recv() {
|
||||||
|
Ok(()) => {
|
||||||
|
let shape = match self.model.load_once(&self.parameters) {
|
||||||
|
Ok(shape) => shape,
|
||||||
|
Err(Error::Compile) => {
|
||||||
|
// It would be better to display an error in the UI,
|
||||||
|
// where the user can actually see it. Issue:
|
||||||
|
// https://github.com/hannobraun/fornjot/issues/30
|
||||||
|
println!("Error compiling model");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
panic!("Error reloading model: {:?}", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(shape)
|
||||||
|
}
|
||||||
|
Err(mpsc::TryRecvError::Empty) => {
|
||||||
|
// Nothing to receive from the channel.
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Err(mpsc::TryRecvError::Disconnected) => {
|
||||||
|
// The other end has disconnected. This is probably the result
|
||||||
|
// of a panic on the other thread, or a program shutdown in
|
||||||
|
// progress. In any case, not much we can do here.
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("Error compiling model")]
|
||||||
|
Compile,
|
||||||
|
|
||||||
|
#[error("I/O error while loading model")]
|
||||||
|
Io(#[from] io::Error),
|
||||||
|
|
||||||
|
#[error("Error loading model from dynamic library")]
|
||||||
|
LibLoading(#[from] libloading::Error),
|
||||||
|
|
||||||
|
#[error("Error watching model for changes")]
|
||||||
|
Notify(#[from] notify::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModelFn =
|
||||||
|
unsafe extern "C" fn(args: &HashMap<String, String>) -> fj::Shape;
|
||||||
|
Loading…
Reference in New Issue
Block a user