feat: Introduce Topology Trait for Compile-Time Safe Score Binding
Introduce the `Topology` trait to ensure that `Maestro` can compile-time safely bind compatible `Scores` and `Topologies`. This refactoring includes updating `HarmonyTuiEvent`, `ScoreListWidget`, and related structures to work with generic `Topology` types, enhancing type safety and modularity.
This commit is contained in:
@@ -10,12 +10,12 @@ use widget::{help::HelpWidget, score::ScoreListWidget};
|
||||
use std::{panic, sync::Arc, time::Duration};
|
||||
|
||||
use crossterm::event::{Event, EventStream, KeyCode, KeyEventKind};
|
||||
use harmony::{maestro::Maestro, score::Score};
|
||||
use harmony::{maestro::Maestro, score::Score, topology::Topology};
|
||||
use ratatui::{
|
||||
self, Frame,
|
||||
layout::{Constraint, Layout, Position},
|
||||
style::{Color, Style},
|
||||
widgets::{Block, Borders, ListItem},
|
||||
widgets::{Block, Borders},
|
||||
};
|
||||
|
||||
pub mod tui {
|
||||
@@ -43,23 +43,25 @@ pub mod tui {
|
||||
/// init(maestro).await.unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
pub async fn init(maestro: Maestro) -> Result<(), Box<dyn std::error::Error>> {
|
||||
pub async fn init<T: Topology + std::fmt::Debug + Send + Sync + 'static>(
|
||||
maestro: Maestro<T>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
HarmonyTUI::new(maestro).init().await
|
||||
}
|
||||
|
||||
pub struct HarmonyTUI {
|
||||
score: ScoreListWidget,
|
||||
pub struct HarmonyTUI<T: Topology> {
|
||||
score: ScoreListWidget<T>,
|
||||
should_quit: bool,
|
||||
tui_state: TuiWidgetState,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum HarmonyTuiEvent {
|
||||
LaunchScore(ScoreItem),
|
||||
enum HarmonyTuiEvent<T: Topology> {
|
||||
LaunchScore(Box<dyn Score<T>>),
|
||||
}
|
||||
|
||||
impl HarmonyTUI {
|
||||
pub fn new(maestro: Maestro) -> Self {
|
||||
impl<T: Topology + std::fmt::Debug + Send + Sync + 'static> HarmonyTUI<T> {
|
||||
pub fn new(maestro: Maestro<T>) -> Self {
|
||||
let maestro = Arc::new(maestro);
|
||||
let (_handle, sender) = Self::start_channel(maestro.clone());
|
||||
let score = ScoreListWidget::new(Self::scores_list(&maestro), sender);
|
||||
@@ -72,9 +74,12 @@ impl HarmonyTUI {
|
||||
}
|
||||
|
||||
fn start_channel(
|
||||
maestro: Arc<Maestro>,
|
||||
) -> (tokio::task::JoinHandle<()>, mpsc::Sender<HarmonyTuiEvent>) {
|
||||
let (sender, mut receiver) = mpsc::channel::<HarmonyTuiEvent>(32);
|
||||
maestro: Arc<Maestro<T>>,
|
||||
) -> (
|
||||
tokio::task::JoinHandle<()>,
|
||||
mpsc::Sender<HarmonyTuiEvent<T>>,
|
||||
) {
|
||||
let (sender, mut receiver) = mpsc::channel::<HarmonyTuiEvent<T>>(32);
|
||||
let handle = tokio::spawn(async move {
|
||||
info!("Starting message channel receiver loop");
|
||||
while let Some(event) = receiver.recv().await {
|
||||
@@ -84,8 +89,7 @@ impl HarmonyTUI {
|
||||
let maestro = maestro.clone();
|
||||
|
||||
let joinhandle_result =
|
||||
tokio::spawn(async move { maestro.interpret(score_item.0).await })
|
||||
.await;
|
||||
tokio::spawn(async move { maestro.interpret(score_item).await }).await;
|
||||
|
||||
match joinhandle_result {
|
||||
Ok(interpretation_result) => match interpretation_result {
|
||||
@@ -163,13 +167,10 @@ impl HarmonyTUI {
|
||||
frame.render_widget(tui_logger, output_area)
|
||||
}
|
||||
|
||||
fn scores_list(maestro: &Maestro) -> Vec<ScoreItem> {
|
||||
fn scores_list(maestro: &Maestro<T>) -> Vec<Box<dyn Score<T>>> {
|
||||
let scores = maestro.scores();
|
||||
let scores_read = scores.read().expect("Should be able to read scores");
|
||||
scores_read
|
||||
.iter()
|
||||
.map(|s| ScoreItem(s.clone_box()))
|
||||
.collect()
|
||||
scores_read.iter().map(|s| s.clone_box()).collect()
|
||||
}
|
||||
|
||||
async fn handle_event(&mut self, event: &Event) {
|
||||
@@ -189,18 +190,3 @@ impl HarmonyTUI {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ScoreItem(Box<dyn Score>);
|
||||
|
||||
impl ScoreItem {
|
||||
pub fn clone(&self) -> Self {
|
||||
Self(self.0.clone_box())
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<ListItem<'_>> for &ScoreItem {
|
||||
fn into(self) -> ListItem<'static> {
|
||||
ListItem::new(self.0.name())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user