deckster/crates/deckster_mode/src/lib.rs
2024-01-31 01:23:56 +01:00

88 lines
3.2 KiB
Rust

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<KeyConfig, KnobConfig>) -> Result<H, HandlerInitializationError>,
>(
init_handler: I,
) -> Result<(), RunError> {
let mut handler: Either<H, I> = Either::Right(init_handler);
let supports_keys = TypeId::of::<KeyConfig>() != TypeId::of::<()>();
let supports_knobs = TypeId::of::<KnobConfig>() != 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::<InitialHandlerMessage<KeyConfig, KnobConfig>>(&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(())
}