/* Copyright 2024, Savanni D'Gerinel This file is part of On the Grid. On the Grid 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. On the Grid 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 On the Grid. If not, see . */ pub mod components; mod app_window; pub use app_window::AppWindow; mod views; use async_std::task::{spawn, yield_now}; use otg_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(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 { join_handle: glib::JoinHandle<()>, handler: Rc, } impl LocalObserver { /// 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, 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 Drop for LocalObserver { fn drop(&mut self) { // Abort the task when the observer goes out of scope. self.join_handle.abort(); } }