1use crate::application::{Application, BootFn, ViewFn};
3use crate::program;
4use crate::theme;
5use crate::time::Instant;
6use crate::window;
7use crate::{Element, Program, Settings, Subscription, Task};
8
9use iced_debug as debug;
10
11pub fn timed<State, Message, Theme, Renderer>(
23 boot: impl BootFn<State, Message>,
24 update: impl UpdateFn<State, Message>,
25 subscription: impl Fn(&State) -> Subscription<Message>,
26 view: impl for<'a> ViewFn<'a, State, Message, Theme, Renderer>,
27) -> Application<impl Program<State = State, Message = (Message, Instant), Theme = Theme>>
28where
29 State: 'static,
30 Message: Send + 'static,
31 Theme: theme::Base + 'static,
32 Renderer: program::Renderer + 'static,
33{
34 use std::marker::PhantomData;
35
36 struct Instance<State, Message, Theme, Renderer, Boot, Update, Subscription, View> {
37 boot: Boot,
38 update: Update,
39 subscription: Subscription,
40 view: View,
41 _state: PhantomData<State>,
42 _message: PhantomData<Message>,
43 _theme: PhantomData<Theme>,
44 _renderer: PhantomData<Renderer>,
45 }
46
47 impl<State, Message, Theme, Renderer, Boot, Update, Subscription, View> Program
48 for Instance<State, Message, Theme, Renderer, Boot, Update, Subscription, View>
49 where
50 Message: Send + 'static,
51 Theme: theme::Base + 'static,
52 Renderer: program::Renderer + 'static,
53 Boot: self::BootFn<State, Message>,
54 Update: self::UpdateFn<State, Message>,
55 Subscription: Fn(&State) -> self::Subscription<Message>,
56 View: for<'a> self::ViewFn<'a, State, Message, Theme, Renderer>,
57 {
58 type State = State;
59 type Message = (Message, Instant);
60 type Theme = Theme;
61 type Renderer = Renderer;
62 type Executor = iced_futures::backend::default::Executor;
63
64 fn name() -> &'static str {
65 let name = std::any::type_name::<State>();
66
67 name.split("::").next().unwrap_or("a_cool_application")
68 }
69
70 fn settings(&self) -> Settings {
71 Settings::default()
72 }
73
74 fn window(&self) -> Option<iced_core::window::Settings> {
75 Some(window::Settings::default())
76 }
77
78 fn boot(&self) -> (State, Task<Self::Message>) {
79 let (state, task) = self.boot.boot();
80
81 (state, task.map(|message| (message, Instant::now())))
82 }
83
84 fn update(
85 &self,
86 state: &mut Self::State,
87 (message, now): Self::Message,
88 ) -> Task<Self::Message> {
89 debug::hot(move || {
90 self.update
91 .update(state, message, now)
92 .into()
93 .map(|message| (message, Instant::now()))
94 })
95 }
96
97 fn view<'a>(
98 &self,
99 state: &'a Self::State,
100 _window: window::Id,
101 ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
102 debug::hot(|| {
103 self.view
104 .view(state)
105 .map(|message| (message, Instant::now()))
106 })
107 }
108
109 fn subscription(&self, state: &Self::State) -> self::Subscription<Self::Message> {
110 debug::hot(|| (self.subscription)(state).map(|message| (message, Instant::now())))
111 }
112 }
113
114 Application {
115 raw: Instance {
116 boot,
117 update,
118 subscription,
119 view,
120 _state: PhantomData,
121 _message: PhantomData,
122 _theme: PhantomData,
123 _renderer: PhantomData,
124 },
125 settings: Settings::default(),
126 window: window::Settings::default(),
127 presets: Vec::new(),
128 }
129}
130
131pub trait UpdateFn<State, Message> {
136 fn update(&self, state: &mut State, message: Message, now: Instant)
138 -> impl Into<Task<Message>>;
139}
140
141impl<State, Message> UpdateFn<State, Message> for () {
142 fn update(
143 &self,
144 _state: &mut State,
145 _message: Message,
146 _now: Instant,
147 ) -> impl Into<Task<Message>> {
148 }
149}
150
151impl<T, State, Message, C> UpdateFn<State, Message> for T
152where
153 T: Fn(&mut State, Message, Instant) -> C,
154 C: Into<Task<Message>>,
155{
156 fn update(
157 &self,
158 state: &mut State,
159 message: Message,
160 now: Instant,
161 ) -> impl Into<Task<Message>> {
162 self(state, message, now)
163 }
164}