-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add unit-tests for domain core - extract domain core into own crate - make `[no_std]` on that crate conditional (not for testing) - add unit tests for all logic-bearing models - restructure app service in keret-controller, so it's not in a module `domain` but `application_service` (including ports / dependencies) * extract app service into own crate - new crate for app service and "port" traits (things the app service depend on) - remove free/Mutex handling from app service to make it testable - rework main to have whole app service in one mutex instead of the 3 individual mutexes * add unit-tests for app service
- Loading branch information
Showing
31 changed files
with
1,264 additions
and
457 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
[package] | ||
name = "keret-controller-appservice" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
snafu = { version = "0.8", default-features = false } | ||
keret-controller-domain = { path = "../keret-controller-domain" } | ||
keret-controller-transmit = { path = "../keret-controller-transmit", default-features = false } | ||
|
||
[dev-dependencies] | ||
mockall = "0.13.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
use crate::{ | ||
error::{DomainErrorOccurredSnafu, SendingMessageToOutsideFailedSnafu}, | ||
ports::{Display, OutsideMessaging, RunningTimeClock, UserInterface}, | ||
Error, | ||
}; | ||
use keret_controller_domain::{AppMode, StateUpdateResult}; | ||
use snafu::ResultExt; | ||
|
||
#[cfg(test)] | ||
mod test; | ||
|
||
/// application service to orchestrate the domain logic | ||
pub struct ApplicationService<TClock, TDisplay, TUserInterface, TSerialBus, TReportFunc> | ||
where | ||
TClock: RunningTimeClock, | ||
TDisplay: Display, | ||
TUserInterface: UserInterface, | ||
TSerialBus: OutsideMessaging, | ||
TReportFunc: FnMut(&Error<TSerialBus::Error>) + Send + Sync, | ||
{ | ||
pub running_timer: TClock, | ||
pub display: TDisplay, | ||
pub controls: TUserInterface, | ||
serial_bus: TSerialBus, | ||
report_error: TReportFunc, | ||
} | ||
|
||
impl<TClock, TDisplay, TUserInterface, TSerialBus, TReportFunc> | ||
ApplicationService<TClock, TDisplay, TUserInterface, TSerialBus, TReportFunc> | ||
where | ||
TClock: RunningTimeClock, | ||
TDisplay: Display, | ||
TUserInterface: UserInterface, | ||
TSerialBus: OutsideMessaging, | ||
TReportFunc: FnMut(&Error<TSerialBus::Error>) + Send + Sync, | ||
{ | ||
/// setup a new `ApplicationService` instance | ||
#[inline] | ||
pub fn new( | ||
running_timer: TClock, | ||
display: TDisplay, | ||
controls: TUserInterface, | ||
serial_bus: TSerialBus, | ||
report_error: TReportFunc, | ||
) -> Self { | ||
Self { | ||
running_timer, | ||
display, | ||
controls, | ||
serial_bus, | ||
report_error, | ||
} | ||
} | ||
|
||
/// run the next cycle of the main logic loop, returning the new state | ||
pub fn next_cycle(&mut self, mode: &AppMode) -> AppMode { | ||
let next = self | ||
.calculate_next_state(mode) | ||
.unwrap_or_else(|e| self.handle_runtime_error(e)); | ||
self.display.show_mode(&next); | ||
|
||
next | ||
} | ||
|
||
/// calculate the next state: | ||
/// check what the user requested to do (by clicking on buttons) and | ||
/// let domain layer calculate the next state based on this input | ||
fn calculate_next_state( | ||
&mut self, | ||
mode: &AppMode, | ||
) -> Result<AppMode, Error<TSerialBus::Error>> { | ||
let request = self.controls.requested_interaction(); | ||
let time = self.running_timer.now(); | ||
|
||
let StateUpdateResult { | ||
mode, | ||
result: message, | ||
} = mode | ||
.handle_interaction_request(request, time) | ||
.context(DomainErrorOccurredSnafu)?; | ||
|
||
if let Some(message) = message { | ||
self.serial_bus | ||
.send_result(message) | ||
.context(SendingMessageToOutsideFailedSnafu)?; | ||
} | ||
|
||
Ok(mode) | ||
} | ||
|
||
/// report an error that happened while executing the main loop | ||
/// and switch the AppMode appropriately to indicate it's in a failure state | ||
fn handle_runtime_error(&mut self, err: Error<TSerialBus::Error>) -> AppMode { | ||
(self.report_error)(&err); | ||
AppMode::Error | ||
} | ||
} |
Oops, something went wrong.