event loop: Decouple event handler from concrete state

This commit is contained in:
Dorota Czaplejewicz
2022-11-28 14:57:06 +00:00
parent d51408a3e0
commit e7c2350c92
2 changed files with 17 additions and 11 deletions

View File

@ -38,12 +38,6 @@
pub mod driver;
// This module is tightly coupled to the shape of data passed around in this project.
// That's not a problem as long as there's only one loop.
// They can still be abstracted into Traits,
// and the loop parametrized over them.
use crate::main::Commands;
use crate::state;
use std::cmp;
use std::time::{ Duration, Instant };
@ -55,13 +49,22 @@ pub trait Event: Clone {
fn get_timeout_reached(&self) -> Option<Instant>;
}
/// Contains and updates the intenal state of the actor.
/// The externally observable state of the actor.
pub trait Outcome {
type Commands;
/// Returns the instructions to emit in order to change the current visible state to the desired one.
fn get_commands_to_reach(&self, desired: &Self) -> Self::Commands;
}
/// Contains and calculates the intenal state of the actor.
pub trait ActorState: Clone {
type Event: Event;
type Outcome: Outcome;
/// Returns the new internal state after the event gets processed.
fn apply_event(self, e: Self::Event, time: Instant) -> Self;
/// Returns the observable state of the actor given this internal state.
fn get_outcome(&self, time: Instant) -> state::Outcome;
fn get_outcome(&self, time: Instant) -> Self::Outcome;
/// Returns the next wake up to schedule if one is needed.
/// This may be called at any time, so should always return the correct value.
fn get_next_wake(&self, now: Instant) -> Option<Instant>;
@ -95,7 +98,7 @@ fn handle_event<S: ActorState>(
mut loop_state: State<S>,
event: S::Event,
now: Instant,
) -> (State<S>, Commands) {
) -> (State<S>, <S::Outcome as Outcome>::Commands) {
// Calculate changes to send to the consumer,
// based on publicly visible state.
// The internal state may change more often than the publicly visible one,
@ -170,6 +173,7 @@ mod test {
use crate::animation;
use crate::imservice::{ ContentHint, ContentPurpose };
use crate::panel;
use crate::state;
use crate::state::{ Application, InputMethod, InputMethodDetails, Presence, visibility };
use crate::state::test::application_with_fake_output;

View File

@ -130,13 +130,14 @@ pub struct Outcome {
pub im: InputMethod,
}
impl Outcome {
impl event_loop::Outcome for Outcome {
type Commands = Commands;
/// Returns the commands needed to apply changes as required by the new state.
/// This implementation doesn't actually take the old state into account,
/// instead issuing all the commands as needed to reach the new state.
/// The receivers of the commands bear the burden
/// of checking if the commands end up being no-ops.
pub fn get_commands_to_reach(&self, new_state: &Self) -> Commands {
fn get_commands_to_reach(&self, new_state: &Self) -> Commands {
// FIXME: handle switching outputs
let (dbus_visible_set, panel_visibility) = match new_state.panel {
animation::Outcome::Visible{output, height, ..}
@ -440,6 +441,7 @@ Outcome:
impl ActorState for Application {
type Event = Event;
type Outcome = Outcome;
fn apply_event(self, e: Self::Event, time: Instant) -> Self {
Self::apply_event(self, e, time)