diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000000000000000000000000000000000000..f00a0f523aabfcafa08a8a003be6c1fb988fff7d --- /dev/null +++ b/src/error.rs @@ -0,0 +1,39 @@ +use tracing::error; + +/// Trait to instrument common error handling for Result & Option types +pub trait ErrInstrument { + type Inner; + + fn log_expect(self, msg: &str) -> Self::Inner; +} + +impl<T, E> ErrInstrument for Result<T, E> +where + E: std::fmt::Debug, +{ + type Inner = T; + + fn log_expect(self, msg: &str) -> Self::Inner { + match self { + Ok(t) => t, + Err(e) => { + error!("{}: {:?}", msg, e); + panic!("{}: {:?}", msg, e); + } + } + } +} + +impl<T> ErrInstrument for Option<T> { + type Inner = T; + + fn log_expect(self, msg: &str) -> Self::Inner { + match self { + Some(t) => t, + None => { + error!("{}", msg); + panic!("{}", msg); + } + } + } +} diff --git a/src/main.rs b/src/main.rs index b4b269e9b7b5275e1e928d20691a9cc313ccfe95..4c268010ecbb74a1660cc1b9584ef925a700ca20 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,6 @@ +#![warn(clippy::expect_used)] + +mod error; mod mavlink; mod ui; @@ -6,25 +9,30 @@ use std::{ sync::{LazyLock, OnceLock}, }; -use mavlink::{MessageBroker, ReflectionContext}; use parking_lot::Mutex; use tokio::runtime::Runtime; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer}; + +use error::ErrInstrument; +use mavlink::{MessageBroker, ReflectionContext}; use ui::ComposableView; +/// MessageBroker singleton, used to fetch & filter Mavlink messages collected static MSG_MANAGER: OnceLock<Mutex<MessageBroker>> = OnceLock::new(); +/// ReflectionContext singleton, used to get access to the Mavlink message definitions static MAVLINK_PROFILE: LazyLock<ReflectionContext> = LazyLock::new(ReflectionContext::new); static APP_NAME: &str = "segs"; fn main() -> Result<(), eframe::Error> { - // set up logging (USE RUST_LOG=debug to see logs) + // Set up logging (USE RUST_LOG=debug to see logs) let env_filter = EnvFilter::builder().from_env_lossy(); tracing_subscriber::registry() .with(tracing_subscriber::fmt::layer().with_filter(env_filter)) .init(); - let rt = Runtime::new().expect("Unable to create Runtime"); + // Start Tokio runtime (TODO: decide whether to use Tokio or a simpler thread-based approach) + let rt = Runtime::new().log_expect("Unable to create Tokio Runtime"); let _enter = rt.enter(); let native_options = eframe::NativeOptions { @@ -35,21 +43,20 @@ fn main() -> Result<(), eframe::Error> { ..Default::default() }; - // To create an app, eframe wants an `AppCreator`, which is a - // Box<dyn FnOnce(&CreationContext<'_>) -> Result<Box<dyn App + 'app>, ...> - // // CreationContext constains information useful to initilize our app, like storage. // Storage allows to store custom data in a way that persist whan you restart the app. eframe::run_native( APP_NAME, // This is the app id, used for example by Wayland native_options, Box::new(|ctx| { + // First we initialize the MSGManager, as a global singleton available to all the panes MSG_MANAGER .set(Mutex::new(MessageBroker::new( + // FIXME: Choose where to put the channel size of the MessageBroker NonZeroUsize::new(50).unwrap(), ctx.egui_ctx.clone(), ))) - .expect("Unable to set MessageManager"); + .log_expect("Unable to set MessageManager"); let app = ctx .storage .map(|storage| ComposableView::new(APP_NAME, storage))