From ca4e8f9e0266f59e4ac17e96216e2c5cc4e944c6 Mon Sep 17 00:00:00 2001 From: Wojciech Kozlowski Date: Tue, 27 Aug 2024 18:36:37 +0200 Subject: [PATCH] Use a trait object for IMusicHoard --- src/main.rs | 8 ++-- src/tui/app/machine/browse.rs | 27 ++++++------ src/tui/app/machine/critical.rs | 25 +++++------ src/tui/app/machine/error.rs | 25 +++++------ src/tui/app/machine/info.rs | 25 +++++------ src/tui/app/machine/matches.rs | 25 +++++------ src/tui/app/machine/mod.rs | 74 ++++++++++++++++----------------- src/tui/app/machine/reload.rs | 35 +++++++--------- src/tui/app/machine/search.rs | 29 ++++++------- src/tui/mod.rs | 10 ++--- 10 files changed, 132 insertions(+), 151 deletions(-) diff --git a/src/main.rs b/src/main.rs index 2672911..ffb82f6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -70,8 +70,10 @@ struct DbOpt { no_database: bool, } -fn with(builder: MusicHoardBuilder) { - let music_hoard = builder.build().expect("failed to initialise MusicHoard"); +fn with( + builder: MusicHoardBuilder, +) { + let music_hoard = Box::new(builder.build().expect("failed to initialise MusicHoard")); // Initialize the terminal user interface. let backend = CrosstermBackend::new(io::stdout()); @@ -92,7 +94,7 @@ fn with(builder: MusicHoardBuilder( +fn with_database( db_opt: DbOpt, builder: MusicHoardBuilder, ) { diff --git a/src/tui/app/machine/browse.rs b/src/tui/app/machine/browse.rs index d4fe3e6..e86ec9a 100644 --- a/src/tui/app/machine/browse.rs +++ b/src/tui/app/machine/browse.rs @@ -2,19 +2,16 @@ use std::{thread, time}; use musichoard::collection::musicbrainz::IMusicBrainzRef; -use crate::tui::{ - app::{ - machine::{matches::AppMatchesInfo, App, AppInner, AppMachine}, - selection::{Delta, ListSelection}, - AppPublic, AppState, IAppInteractBrowse, - }, - lib::IMusicHoard, +use crate::tui::app::{ + machine::{matches::AppMatchesInfo, App, AppInner, AppMachine}, + selection::{Delta, ListSelection}, + AppPublic, AppState, IAppInteractBrowse, }; pub struct AppBrowse; -impl AppMachine { - pub fn browse(inner: AppInner) -> Self { +impl AppMachine { + pub fn browse(inner: AppInner) -> Self { AppMachine { inner, state: AppBrowse, @@ -22,14 +19,14 @@ impl AppMachine { } } -impl From> for App { - fn from(machine: AppMachine) -> Self { +impl From> for App { + fn from(machine: AppMachine) -> Self { AppState::Browse(machine) } } -impl<'a, MH: IMusicHoard> From<&'a mut AppMachine> for AppPublic<'a> { - fn from(machine: &'a mut AppMachine) -> Self { +impl<'a> From<&'a mut AppMachine> for AppPublic<'a> { + fn from(machine: &'a mut AppMachine) -> Self { AppPublic { inner: (&mut machine.inner).into(), state: AppState::Browse(()), @@ -37,8 +34,8 @@ impl<'a, MH: IMusicHoard> From<&'a mut AppMachine> for AppPublic< } } -impl IAppInteractBrowse for AppMachine { - type APP = App; +impl IAppInteractBrowse for AppMachine { + type APP = App; fn quit(mut self) -> Self::APP { self.inner.running = false; diff --git a/src/tui/app/machine/critical.rs b/src/tui/app/machine/critical.rs index 5fe911d..476ba8a 100644 --- a/src/tui/app/machine/critical.rs +++ b/src/tui/app/machine/critical.rs @@ -1,17 +1,14 @@ -use crate::tui::{ - app::{ - machine::{App, AppInner, AppMachine}, - AppPublic, AppState, IAppInteractCritical, - }, - lib::IMusicHoard, +use crate::tui::app::{ + machine::{App, AppInner, AppMachine}, + AppPublic, AppState, IAppInteractCritical, }; pub struct AppCritical { string: String, } -impl AppMachine { - pub fn critical>(inner: AppInner, string: S) -> Self { +impl AppMachine { + pub fn critical>(inner: AppInner, string: S) -> Self { AppMachine { inner, state: AppCritical { @@ -21,14 +18,14 @@ impl AppMachine { } } -impl From> for App { - fn from(machine: AppMachine) -> Self { +impl From> for App { + fn from(machine: AppMachine) -> Self { AppState::Critical(machine) } } -impl<'a, MH: IMusicHoard> From<&'a mut AppMachine> for AppPublic<'a> { - fn from(machine: &'a mut AppMachine) -> Self { +impl<'a> From<&'a mut AppMachine> for AppPublic<'a> { + fn from(machine: &'a mut AppMachine) -> Self { AppPublic { inner: (&mut machine.inner).into(), state: AppState::Critical(&machine.state.string), @@ -36,8 +33,8 @@ impl<'a, MH: IMusicHoard> From<&'a mut AppMachine> for AppPubli } } -impl IAppInteractCritical for AppMachine { - type APP = App; +impl IAppInteractCritical for AppMachine { + type APP = App; fn no_op(self) -> Self::APP { self.into() diff --git a/src/tui/app/machine/error.rs b/src/tui/app/machine/error.rs index 63239d5..1f9b90f 100644 --- a/src/tui/app/machine/error.rs +++ b/src/tui/app/machine/error.rs @@ -1,17 +1,14 @@ -use crate::tui::{ - app::{ - machine::{App, AppInner, AppMachine}, - AppPublic, AppState, IAppInteractError, - }, - lib::IMusicHoard, +use crate::tui::app::{ + machine::{App, AppInner, AppMachine}, + AppPublic, AppState, IAppInteractError, }; pub struct AppError { string: String, } -impl AppMachine { - pub fn error>(inner: AppInner, string: S) -> Self { +impl AppMachine { + pub fn error>(inner: AppInner, string: S) -> Self { AppMachine { inner, state: AppError { @@ -21,14 +18,14 @@ impl AppMachine { } } -impl From> for App { - fn from(machine: AppMachine) -> Self { +impl From> for App { + fn from(machine: AppMachine) -> Self { AppState::Error(machine) } } -impl<'a, MH: IMusicHoard> From<&'a mut AppMachine> for AppPublic<'a> { - fn from(machine: &'a mut AppMachine) -> Self { +impl<'a> From<&'a mut AppMachine> for AppPublic<'a> { + fn from(machine: &'a mut AppMachine) -> Self { AppPublic { inner: (&mut machine.inner).into(), state: AppState::Error(&machine.state.string), @@ -36,8 +33,8 @@ impl<'a, MH: IMusicHoard> From<&'a mut AppMachine> for AppPublic<' } } -impl IAppInteractError for AppMachine { - type APP = App; +impl IAppInteractError for AppMachine { + type APP = App; fn dismiss_error(self) -> Self::APP { AppMachine::browse(self.inner).into() diff --git a/src/tui/app/machine/info.rs b/src/tui/app/machine/info.rs index e6e005d..6dd90b6 100644 --- a/src/tui/app/machine/info.rs +++ b/src/tui/app/machine/info.rs @@ -1,15 +1,12 @@ -use crate::tui::{ - app::{ - machine::{App, AppInner, AppMachine}, - AppPublic, AppState, IAppInteractInfo, - }, - lib::IMusicHoard, +use crate::tui::app::{ + machine::{App, AppInner, AppMachine}, + AppPublic, AppState, IAppInteractInfo, }; pub struct AppInfo; -impl AppMachine { - pub fn info(inner: AppInner) -> Self { +impl AppMachine { + pub fn info(inner: AppInner) -> Self { AppMachine { inner, state: AppInfo, @@ -17,14 +14,14 @@ impl AppMachine { } } -impl From> for App { - fn from(machine: AppMachine) -> Self { +impl From> for App { + fn from(machine: AppMachine) -> Self { AppState::Info(machine) } } -impl<'a, MH: IMusicHoard> From<&'a mut AppMachine> for AppPublic<'a> { - fn from(machine: &'a mut AppMachine) -> Self { +impl<'a> From<&'a mut AppMachine> for AppPublic<'a> { + fn from(machine: &'a mut AppMachine) -> Self { AppPublic { inner: (&mut machine.inner).into(), state: AppState::Info(()), @@ -32,8 +29,8 @@ impl<'a, MH: IMusicHoard> From<&'a mut AppMachine> for AppPublic<'a } } -impl IAppInteractInfo for AppMachine { - type APP = App; +impl IAppInteractInfo for AppMachine { + type APP = App; fn hide_info_overlay(self) -> Self::APP { AppMachine::browse(self.inner).into() diff --git a/src/tui/app/machine/matches.rs b/src/tui/app/machine/matches.rs index 575ef67..4c2eabf 100644 --- a/src/tui/app/machine/matches.rs +++ b/src/tui/app/machine/matches.rs @@ -2,12 +2,9 @@ use std::cmp; use musichoard::{collection::album::Album, interface::musicbrainz::Match}; -use crate::tui::{ - app::{ - machine::{App, AppInner, AppMachine}, - AppPublic, AppPublicMatches, AppState, IAppInteractMatches, WidgetState, - }, - lib::IMusicHoard, +use crate::tui::app::{ + machine::{App, AppInner, AppMachine}, + AppPublic, AppPublicMatches, AppState, IAppInteractMatches, WidgetState, }; #[derive(Clone, Debug, PartialEq, Eq)] @@ -22,8 +19,8 @@ pub struct AppMatches { state: WidgetState, } -impl AppMachine { - pub fn matches(inner: AppInner, matches_info_vec: Vec) -> Self { +impl AppMachine { + pub fn matches(inner: AppInner, matches_info_vec: Vec) -> Self { let mut index = None; let mut state = WidgetState::default(); if let Some(matches_info) = matches_info_vec.first() { @@ -44,14 +41,14 @@ impl AppMachine { } } -impl From> for App { - fn from(machine: AppMachine) -> Self { +impl From> for App { + fn from(machine: AppMachine) -> Self { AppState::Matches(machine) } } -impl<'a, MH: IMusicHoard> From<&'a mut AppMachine> for AppPublic<'a> { - fn from(machine: &'a mut AppMachine) -> Self { +impl<'a> From<&'a mut AppMachine> for AppPublic<'a> { + fn from(machine: &'a mut AppMachine) -> Self { let (matching, matches) = match machine.state.index { Some(index) => ( Some(&machine.state.matches_info_vec[index].matching), @@ -71,8 +68,8 @@ impl<'a, MH: IMusicHoard> From<&'a mut AppMachine> for AppPublic } } -impl IAppInteractMatches for AppMachine { - type APP = App; +impl IAppInteractMatches for AppMachine { + type APP = App; fn prev_match(mut self) -> Self::APP { if let Some(list_index) = self.state.state.list.selected() { diff --git a/src/tui/app/machine/mod.rs b/src/tui/app/machine/mod.rs index 3f07f72..c3a1185 100644 --- a/src/tui/app/machine/mod.rs +++ b/src/tui/app/machine/mod.rs @@ -19,30 +19,30 @@ use matches::AppMatches; use reload::AppReload; use search::AppSearch; -pub type App = AppState< - AppMachine, - AppMachine, - AppMachine, - AppMachine, - AppMachine, - AppMachine, - AppMachine, +pub type App = AppState< + AppMachine, + AppMachine, + AppMachine, + AppMachine, + AppMachine, + AppMachine, + AppMachine, >; -pub struct AppMachine { - inner: AppInner, +pub struct AppMachine { + inner: AppInner, state: STATE, } -pub struct AppInner { +pub struct AppInner { running: bool, - music_hoard: MH, + music_hoard: Box, mb_api: Box, selection: Selection, } -impl App { - pub fn new(mut music_hoard: MH, mb_api: Box) -> Self { +impl App { + pub fn new(mut music_hoard: Box, mb_api: Box) -> Self { let init_result = Self::init(&mut music_hoard); let inner = AppInner::new(music_hoard, mb_api); match init_result { @@ -51,12 +51,12 @@ impl App { } } - fn init(music_hoard: &mut MH) -> Result<(), musichoard::Error> { + fn init(music_hoard: &mut Box) -> Result<(), musichoard::Error> { music_hoard.rescan_library()?; Ok(()) } - fn inner_ref(&self) -> &AppInner { + fn inner_ref(&self) -> &AppInner { match self { AppState::Browse(browse) => &browse.inner, AppState::Info(info) => &info.inner, @@ -68,7 +68,7 @@ impl App { } } - fn inner_mut(&mut self) -> &mut AppInner { + fn inner_mut(&mut self) -> &mut AppInner { match self { AppState::Browse(browse) => &mut browse.inner, AppState::Info(info) => &mut info.inner, @@ -81,14 +81,14 @@ impl App { } } -impl IAppInteract for App { - type BS = AppMachine; - type IS = AppMachine; - type RS = AppMachine; - type SS = AppMachine; - type MS = AppMachine; - type ES = AppMachine; - type CS = AppMachine; +impl IAppInteract for App { + type BS = AppMachine; + type IS = AppMachine; + type RS = AppMachine; + type SS = AppMachine; + type MS = AppMachine; + type ES = AppMachine; + type CS = AppMachine; fn is_running(&self) -> bool { self.inner_ref().running @@ -106,7 +106,7 @@ impl IAppInteract for App { } } -impl IAppAccess for App { +impl IAppAccess for App { fn get(&mut self) -> AppPublic { match self { AppState::Browse(browse) => browse.into(), @@ -120,8 +120,8 @@ impl IAppAccess for App { } } -impl AppInner { - pub fn new(music_hoard: MH, mb_api: Box) -> Self { +impl AppInner { + pub fn new(music_hoard: Box, mb_api: Box) -> Self { let selection = Selection::new(music_hoard.get_collection()); AppInner { running: true, @@ -132,8 +132,8 @@ impl AppInner { } } -impl<'a, MH: IMusicHoard> From<&'a mut AppInner> for AppPublicInner<'a> { - fn from(inner: &'a mut AppInner) -> Self { +impl<'a> From<&'a mut AppInner> for AppPublicInner<'a> { + fn from(inner: &'a mut AppInner) -> Self { AppPublicInner { collection: inner.music_hoard.get_collection(), selection: &mut inner.selection, @@ -203,14 +203,14 @@ mod tests { } } - pub fn music_hoard(collection: Collection) -> MockIMusicHoard { - let mut music_hoard = MockIMusicHoard::new(); + pub fn music_hoard(collection: Collection) -> Box { + let mut music_hoard = Box::new(MockIMusicHoard::new()); music_hoard.expect_get_collection().return_const(collection); music_hoard } - fn music_hoard_init(collection: Collection) -> MockIMusicHoard { + fn music_hoard_init(collection: Collection) -> Box { let mut music_hoard = music_hoard(collection); music_hoard @@ -225,14 +225,14 @@ mod tests { Box::new(MockIMusicBrainz::new()) } - pub fn inner(music_hoard: MockIMusicHoard) -> AppInner { + pub fn inner(music_hoard: Box) -> AppInner { AppInner::new(music_hoard, mb_api()) } pub fn inner_with_mb( - music_hoard: MockIMusicHoard, + music_hoard: Box, mb_api: Box, - ) -> AppInner { + ) -> AppInner { AppInner::new(music_hoard, mb_api) } @@ -362,7 +362,7 @@ mod tests { #[test] fn init_error() { - let mut music_hoard = MockIMusicHoard::new(); + let mut music_hoard = Box::new(MockIMusicHoard::new()); music_hoard .expect_rescan_library() diff --git a/src/tui/app/machine/reload.rs b/src/tui/app/machine/reload.rs index cc1638e..6659434 100644 --- a/src/tui/app/machine/reload.rs +++ b/src/tui/app/machine/reload.rs @@ -1,16 +1,13 @@ -use crate::tui::{ - app::{ - machine::{App, AppInner, AppMachine}, - selection::KeySelection, - AppPublic, AppState, IAppInteractReload, - }, - lib::IMusicHoard, +use crate::tui::app::{ + machine::{App, AppInner, AppMachine}, + selection::KeySelection, + AppPublic, AppState, IAppInteractReload, }; pub struct AppReload; -impl AppMachine { - pub fn reload(inner: AppInner) -> Self { +impl AppMachine { + pub fn reload(inner: AppInner) -> Self { AppMachine { inner, state: AppReload, @@ -18,13 +15,13 @@ impl AppMachine { } } -impl From> for App { - fn from(machine: AppMachine) -> Self { +impl From> for App { + fn from(machine: AppMachine) -> Self { AppState::Reload(machine) } } -impl<'a, MH: IMusicHoard> From<&'a mut AppMachine> for AppPublic<'a> { - fn from(machine: &'a mut AppMachine) -> Self { +impl<'a> From<&'a mut AppMachine> for AppPublic<'a> { + fn from(machine: &'a mut AppMachine) -> Self { AppPublic { inner: (&mut machine.inner).into(), state: AppState::Reload(()), @@ -32,8 +29,8 @@ impl<'a, MH: IMusicHoard> From<&'a mut AppMachine> for AppPublic< } } -impl IAppInteractReload for AppMachine { - type APP = App; +impl IAppInteractReload for AppMachine { + type APP = App; fn reload_library(mut self) -> Self::APP { let previous = KeySelection::get( @@ -62,12 +59,12 @@ impl IAppInteractReload for AppMachine { } } -trait IAppInteractReloadPrivate { - fn refresh(self, previous: KeySelection, result: Result<(), musichoard::Error>) -> App; +trait IAppInteractReloadPrivate { + fn refresh(self, previous: KeySelection, result: Result<(), musichoard::Error>) -> App; } -impl IAppInteractReloadPrivate for AppMachine { - fn refresh(mut self, previous: KeySelection, result: Result<(), musichoard::Error>) -> App { +impl IAppInteractReloadPrivate for AppMachine { + fn refresh(mut self, previous: KeySelection, result: Result<(), musichoard::Error>) -> App { match result { Ok(()) => { self.inner diff --git a/src/tui/app/machine/search.rs b/src/tui/app/machine/search.rs index e8561ab..c13f6a5 100644 --- a/src/tui/app/machine/search.rs +++ b/src/tui/app/machine/search.rs @@ -3,13 +3,10 @@ use once_cell::sync::Lazy; use musichoard::collection::{album::Album, artist::Artist, track::Track}; -use crate::tui::{ - app::{ - machine::{App, AppInner, AppMachine}, - selection::{ListSelection, SelectionState}, - AppPublic, AppState, Category, IAppInteractSearch, - }, - lib::IMusicHoard, +use crate::tui::app::{ + machine::{App, AppInner, AppMachine}, + selection::{ListSelection, SelectionState}, + AppPublic, AppState, Category, IAppInteractSearch, }; // Unlikely that this covers all possible strings, but it should at least cover strings @@ -34,8 +31,8 @@ struct AppSearchMemo { char: bool, } -impl AppMachine { - pub fn search(inner: AppInner, orig: ListSelection) -> Self { +impl AppMachine { + pub fn search(inner: AppInner, orig: ListSelection) -> Self { AppMachine { inner, state: AppSearch { @@ -47,14 +44,14 @@ impl AppMachine { } } -impl From> for App { - fn from(machine: AppMachine) -> Self { +impl From> for App { + fn from(machine: AppMachine) -> Self { AppState::Search(machine) } } -impl<'a, MH: IMusicHoard> From<&'a mut AppMachine> for AppPublic<'a> { - fn from(machine: &'a mut AppMachine) -> Self { +impl<'a> From<&'a mut AppMachine> for AppPublic<'a> { + fn from(machine: &'a mut AppMachine) -> Self { AppPublic { inner: (&mut machine.inner).into(), state: AppState::Search(&machine.state.string), @@ -62,8 +59,8 @@ impl<'a, MH: IMusicHoard> From<&'a mut AppMachine> for AppPublic< } } -impl IAppInteractSearch for AppMachine { - type APP = App; +impl IAppInteractSearch for AppMachine { + type APP = App; fn append_character(mut self, ch: char) -> Self::APP { self.state.string.push(ch); @@ -127,7 +124,7 @@ trait IAppInteractSearchPrivate { fn normalize_search(search: &str, lowercase: bool, asciify: bool) -> String; } -impl IAppInteractSearchPrivate for AppMachine { +impl IAppInteractSearchPrivate for AppMachine { fn incremental_search(&mut self, next: bool) { let collection = self.inner.music_hoard.get_collection(); let search = &self.state.string; diff --git a/src/tui/mod.rs b/src/tui/mod.rs index 806053e..66557ca 100644 --- a/src/tui/mod.rs +++ b/src/tui/mod.rs @@ -191,8 +191,8 @@ mod tests { Terminal::new(backend).unwrap() } - fn music_hoard(collection: Collection) -> MockIMusicHoard { - let mut music_hoard = MockIMusicHoard::new(); + fn music_hoard(collection: Collection) -> Box { + let mut music_hoard = Box::new(MockIMusicHoard::new()); music_hoard.expect_reload_database().returning(|| Ok(())); music_hoard.expect_rescan_library().returning(|| Ok(())); @@ -201,7 +201,7 @@ mod tests { music_hoard } - fn app(collection: Collection) -> App { + fn app(collection: Collection) -> App { App::new(music_hoard(collection), Box::new(MockIMusicBrainz::new())) } @@ -216,11 +216,11 @@ mod tests { listener } - fn handler() -> MockIEventHandler> { + fn handler() -> MockIEventHandler { let mut handler = MockIEventHandler::new(); handler .expect_handle_next_event() - .return_once(|app: App| Ok(app.force_quit())); + .return_once(|app: App| Ok(app.force_quit())); handler }