infect/
effect.rs

1// SPDX-FileCopyrightText: The infect authors
2// SPDX-License-Identifier: MPL-2.0
3
4use crate::ModelChanged;
5
6/// Outcome of applying an effect to the model
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct EffectApplied<Effect, Task, ModelRenderHint> {
9    /// A hint for rendering the model
10    pub render_hint: ModelRenderHint,
11
12    /// A follow-up task for triggering side-effects
13    pub task: Option<Task>,
14
15    /// A follow-up effect that will be processed before any queued effects
16    ///
17    /// Useful for deferring the application of received effects while a
18    /// side-effect is pending. When the side-effect finished these deferred
19    /// effects could then be recalled one after another before continuing
20    /// with the regular message processing.
21    pub next_effect: Option<Effect>,
22}
23
24impl<Effect, Task, ModelRenderHint> Default for EffectApplied<Effect, Task, ModelRenderHint>
25where
26    ModelRenderHint: crate::ModelRenderHint,
27{
28    fn default() -> Self {
29        let render_hint = ModelRenderHint::default();
30        debug_assert!(!render_hint.should_render_model());
31        Self {
32            render_hint: Default::default(),
33            task: None,
34            next_effect: None,
35        }
36    }
37}
38
39impl<Effect, Task, ModelRenderHint> EffectApplied<Effect, Task, ModelRenderHint>
40where
41    ModelRenderHint: crate::ModelRenderHint,
42{
43    /// Mark the model as unchanged
44    #[must_use]
45    pub fn unchanged() -> Self {
46        Default::default()
47    }
48
49    /// Mark the model as unchanged and dispatch a task
50    #[must_use]
51    pub fn unchanged_task<T>(task: impl Into<Option<T>>) -> Self
52    where
53        T: Into<Task>,
54    {
55        Self {
56            task: task.into().map(Into::into),
57            ..Self::unchanged()
58        }
59    }
60
61    /// Mark the model as unchanged and apply a next effect
62    #[must_use]
63    pub fn unchanged_next<E>(next_effect: impl Into<Option<E>>) -> Self
64    where
65        E: Into<Effect>,
66    {
67        Self {
68            next_effect: next_effect.into().map(Into::into),
69            ..Self::unchanged()
70        }
71    }
72}
73
74impl<Effect, Task> EffectApplied<Effect, Task, ModelChanged> {
75    /// Mark the model as maybe changed
76    #[must_use]
77    pub const fn maybe_changed() -> Self {
78        Self {
79            render_hint: ModelChanged::MaybeChanged,
80            task: None,
81            next_effect: None,
82        }
83    }
84
85    /// Mark the model as maybe changed and dispatch a task
86    #[must_use]
87    pub fn maybe_changed_task<T>(task: impl Into<Option<T>>) -> Self
88    where
89        T: Into<Task>,
90    {
91        Self {
92            task: task.into().map(Into::into),
93            ..Self::maybe_changed()
94        }
95    }
96
97    /// Mark the model as maybe changed and apply a next effect
98    #[must_use]
99    pub fn maybe_changed_next<E>(next_effect: impl Into<Option<E>>) -> Self
100    where
101        E: Into<Effect>,
102    {
103        Self {
104            next_effect: next_effect.into().map(Into::into),
105            ..Self::maybe_changed()
106        }
107    }
108}
109
110impl<Effect, Task, ModelRenderHint> EffectApplied<Effect, Task, ModelRenderHint> {
111    /// Map from a differently parameterized type
112    pub fn map_from<E, T, M>(from: EffectApplied<E, T, M>) -> Self
113    where
114        E: Into<Effect>,
115        T: Into<Task>,
116        M: Into<ModelRenderHint>,
117    {
118        let EffectApplied {
119            render_hint,
120            task,
121            next_effect,
122        } = from;
123        let render_hint = render_hint.into();
124        let task = task.map(Into::into);
125        let next_effect = next_effect.map(Into::into);
126        Self {
127            render_hint,
128            task,
129            next_effect,
130        }
131    }
132
133    /// Map into a differently parameterized type
134    pub fn map_into<E, T, M>(self) -> EffectApplied<E, T, M>
135    where
136        E: From<Effect>,
137        T: From<Task>,
138        M: From<ModelRenderHint>,
139    {
140        EffectApplied::map_from(self)
141    }
142}