use std::any::TypeId; use std::io; use std::io::BufRead; use either::Either; use serde::de::DeserializeOwned; use thiserror::Error; use deckster_shared::handler_communication::HandlerInitializationResultMessage; pub use deckster_shared::handler_communication::{HandlerEvent, HandlerInitializationError, InitialHandlerMessage}; pub use deckster_shared::path::*; pub use deckster_shared::state::{KeyStyleByStateMap, KnobStyleByStateMap}; #[derive(Debug, Error)] pub enum RunError { #[error("A stdin line could not be read.")] LineIo(#[from] io::Error), #[error("A stdin line could not be deserialized: {description}")] LineDeserialization { line: String, description: String }, } pub trait DecksterHandler { fn handle(&mut self, event: HandlerEvent); } pub fn run< KeyConfig: Clone + DeserializeOwned + 'static, KnobConfig: Clone + DeserializeOwned + 'static, H: DecksterHandler, I: FnOnce(InitialHandlerMessage) -> Result, >( init_handler: I, ) -> Result<(), RunError> { let mut handler: Either = Either::Right(init_handler); let supports_keys = TypeId::of::() != TypeId::of::<()>(); let supports_knobs = TypeId::of::() != TypeId::of::<()>(); let handle = io::stdin().lock(); for line in handle.lines() { let line = line?; match handler { Either::Left(mut h) => { let event: HandlerEvent = serde_json::from_str(&line).map_err(|e| RunError::LineDeserialization { line, description: e.to_string(), })?; h.handle(event); handler = Either::Left(h); } Either::Right(init_handler) => { let initial_message = serde_json::from_str::>(&line); match initial_message { Ok(initial_message) => match init_handler(initial_message) { Ok(h) => { println!("{}", serde_json::to_string(&HandlerInitializationResultMessage::Ready).unwrap()); handler = Either::Left(h) } Err(error) => { println!("{}", serde_json::to_string(&HandlerInitializationResultMessage::Error { error }).unwrap()); return Ok(()); } }, Err(err) => { println!( "{}", serde_json::to_string(&HandlerInitializationResultMessage::Error { error: HandlerInitializationError::InvalidConfig { supports_keys, supports_knobs, message: err.to_string().into_boxed_str(), } }) .unwrap() ); return Ok(()); } } } } } Ok(()) }