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:
@@ -1,16 +1,14 @@
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use crossterm::event::{Event, KeyCode, KeyEventKind};
|
||||
use harmony::{score::Score, topology::Topology};
|
||||
use log::{info, warn};
|
||||
use ratatui::{
|
||||
Frame,
|
||||
layout::Rect,
|
||||
style::{Style, Stylize},
|
||||
widgets::{List, ListState, StatefulWidget, Widget},
|
||||
layout::Rect, style::{Style, Stylize}, widgets::{List, ListItem, ListState, StatefulWidget, Widget}, Frame
|
||||
};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::{HarmonyTuiEvent, ScoreItem};
|
||||
use crate::HarmonyTuiEvent;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ExecutionState {
|
||||
@@ -20,22 +18,22 @@ enum ExecutionState {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Execution {
|
||||
struct Execution<T: Topology> {
|
||||
state: ExecutionState,
|
||||
score: ScoreItem,
|
||||
score: Box<dyn Score<T>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ScoreListWidget {
|
||||
pub(crate) struct ScoreListWidget<T: Topology> {
|
||||
list_state: Arc<RwLock<ListState>>,
|
||||
scores: Vec<ScoreItem>,
|
||||
execution: Option<Execution>,
|
||||
execution_history: Vec<Execution>,
|
||||
sender: mpsc::Sender<HarmonyTuiEvent>,
|
||||
scores: Vec<Box<dyn Score<T>>>,
|
||||
execution: Option<Execution<T>>,
|
||||
execution_history: Vec<Execution<T>>,
|
||||
sender: mpsc::Sender<HarmonyTuiEvent<T>>,
|
||||
}
|
||||
|
||||
impl ScoreListWidget {
|
||||
pub(crate) fn new(scores: Vec<ScoreItem>, sender: mpsc::Sender<HarmonyTuiEvent>) -> Self {
|
||||
impl<T: Topology + std::fmt::Debug> ScoreListWidget<T> {
|
||||
pub(crate) fn new(scores: Vec<Box<dyn Score<T>>>, sender: mpsc::Sender<HarmonyTuiEvent<T>>) -> Self {
|
||||
let mut list_state = ListState::default();
|
||||
list_state.select_first();
|
||||
let list_state = Arc::new(RwLock::new(list_state));
|
||||
@@ -58,9 +56,9 @@ impl ScoreListWidget {
|
||||
|
||||
self.execution = Some(Execution {
|
||||
state: ExecutionState::INITIATED,
|
||||
score: score.clone(),
|
||||
score: score.clone_box(),
|
||||
});
|
||||
info!("{:#?}\n\nConfirm Execution (Press y/n)", score.0);
|
||||
info!("{:#?}\n\nConfirm Execution (Press y/n)", score);
|
||||
} else {
|
||||
warn!("No Score selected, nothing to launch");
|
||||
}
|
||||
@@ -94,7 +92,7 @@ impl ScoreListWidget {
|
||||
execution.state = ExecutionState::RUNNING;
|
||||
info!("Launch execution {:?}", execution);
|
||||
self.sender
|
||||
.send(HarmonyTuiEvent::LaunchScore(execution.score.clone()))
|
||||
.send(HarmonyTuiEvent::LaunchScore(execution.score.clone_box()))
|
||||
.await
|
||||
.expect("Should be able to send message");
|
||||
}
|
||||
@@ -123,16 +121,22 @@ impl ScoreListWidget {
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for &ScoreListWidget {
|
||||
impl<T: Topology> Widget for &ScoreListWidget<T> {
|
||||
fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let mut list_state = self.list_state.write().unwrap();
|
||||
let list = List::new(&self.scores)
|
||||
let scores_items: Vec<ListItem<'_>> = self.scores.iter().map(score_to_list_item).collect();
|
||||
let list = List::new(scores_items)
|
||||
.highlight_style(Style::new().bold().italic())
|
||||
.highlight_symbol("🠊 ");
|
||||
|
||||
StatefulWidget::render(list, area, buf, &mut list_state)
|
||||
}
|
||||
}
|
||||
|
||||
fn score_to_list_item<'a, T: Topology>(score: &'a Box<dyn Score<T>>) -> ListItem<'a> {
|
||||
ListItem::new(score.name())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user