96 lines
3.2 KiB
Rust
96 lines
3.2 KiB
Rust
/*
|
|
Copyright 2024, Savanni D'Gerinel <savanni@luminescent-dreams.com>
|
|
|
|
This file is part of Kifu.
|
|
|
|
Kifu is free software: you can redistribute it and/or modify it under the terms of the GNU
|
|
General Public License as published by the Free Software Foundation, either version 3 of the
|
|
License, or (at your option) any later version.
|
|
|
|
Kifu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
|
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along with Kifu. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
pub mod components;
|
|
|
|
mod app_window;
|
|
pub use app_window::AppWindow;
|
|
|
|
mod view_models;
|
|
mod views;
|
|
|
|
use async_std::task::{spawn, yield_now};
|
|
use kifu_core::{Core, Observable, CoreRequest, CoreResponse};
|
|
use std::{rc::Rc, sync::Arc};
|
|
use tokio::runtime::Runtime;
|
|
|
|
#[derive(Clone)]
|
|
pub struct CoreApi {
|
|
pub core: Core,
|
|
}
|
|
|
|
impl CoreApi {
|
|
pub async fn dispatch(&self, request: CoreRequest) -> CoreResponse {
|
|
self.core.dispatch(request).await
|
|
}
|
|
}
|
|
|
|
pub fn perftrace<F, A>(trace_name: &str, f: F) -> A
|
|
where
|
|
F: FnOnce() -> A,
|
|
{
|
|
let start = std::time::Instant::now();
|
|
let result = f();
|
|
let end = std::time::Instant::now();
|
|
println!("[Trace: {}] {:?}", trace_name, end - start);
|
|
result
|
|
}
|
|
|
|
/// LocalObserver creates a task on the current thread which watches the specified observer for notifications and calls the handler function with each one.
|
|
///
|
|
/// The LocalObserver starts a task which listens for notifications during the constructor. When the observer goes out of scope, it will make a point of aborting the task. This combination means that anything which uses the observer can create it, hold on to a reference of it, and then drop it when done, and not have to do anything else with the observer object.
|
|
struct LocalObserver<T> {
|
|
join_handle: glib::JoinHandle<()>,
|
|
handler: Rc<dyn Fn(T)>,
|
|
}
|
|
|
|
impl<T: 'static> LocalObserver<T> {
|
|
/// Construct a new LocalObserver and start it running.
|
|
///
|
|
/// observable -- any object which emits events
|
|
/// handler -- a function which can process events
|
|
fn new(observable: &dyn Observable<T>, handler: impl Fn(T) + 'static) -> Self {
|
|
let listener = observable.subscribe();
|
|
let handler = Rc::new(handler);
|
|
let join_handle = glib::spawn_future_local({
|
|
let handler = handler.clone();
|
|
async move {
|
|
loop {
|
|
match listener.recv().await {
|
|
Ok(msg) => handler(msg),
|
|
Err(_) => {
|
|
// recv only fails if the channel has been closed and no other notifications are pending. This will break out of the loop and terminate the observer.
|
|
return;
|
|
}
|
|
}
|
|
yield_now().await;
|
|
}
|
|
}
|
|
});
|
|
Self {
|
|
join_handle,
|
|
handler,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T> Drop for LocalObserver<T> {
|
|
fn drop(&mut self) {
|
|
// Abort the task when the observer goes out of scope.
|
|
self.join_handle.abort();
|
|
}
|
|
}
|