Introduce Program::run_with to control the initial state

This commit is contained in:
Héctor Ramón Jiménez 2024-03-17 19:15:31 +01:00
parent 92f8dddc2c
commit 943b6c9657
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
2 changed files with 60 additions and 37 deletions

View file

@ -21,19 +21,13 @@ pub fn main() -> iced::Result {
.run() .run()
} }
#[derive(Default)]
pub struct Tour { pub struct Tour {
steps: Steps, steps: Steps,
debug: bool, debug: bool,
} }
impl Tour { impl Tour {
fn new() -> Self {
Self {
steps: Steps::new(),
debug: false,
}
}
fn title(&self) -> String { fn title(&self) -> String {
format!("{} - Iced", self.steps.title()) format!("{} - Iced", self.steps.title())
} }
@ -90,12 +84,6 @@ impl Tour {
} }
} }
impl Default for Tour {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Message { pub enum Message {
BackPressed, BackPressed,
@ -177,6 +165,12 @@ impl Steps {
} }
} }
impl Default for Steps {
fn default() -> Self {
Steps::new()
}
}
enum Step { enum Step {
Welcome, Welcome,
Slider { Slider {

View file

@ -70,7 +70,7 @@ pub fn program<State, Message, Theme>(
view: impl for<'a> self::View<'a, State, Message, Theme>, view: impl for<'a> self::View<'a, State, Message, Theme>,
) -> Program<impl Definition<State = State, Message = Message, Theme = Theme>> ) -> Program<impl Definition<State = State, Message = Message, Theme = Theme>>
where where
State: Default + 'static, State: 'static,
Message: Send + std::fmt::Debug, Message: Send + std::fmt::Debug,
Theme: Default + application::DefaultStyle, Theme: Default + application::DefaultStyle,
{ {
@ -87,7 +87,6 @@ where
impl<State, Message, Theme, Update, View> Definition impl<State, Message, Theme, Update, View> Definition
for Application<State, Message, Theme, Update, View> for Application<State, Message, Theme, Update, View>
where where
State: Default,
Message: Send + std::fmt::Debug, Message: Send + std::fmt::Debug,
Theme: Default + application::DefaultStyle, Theme: Default + application::DefaultStyle,
Update: self::Update<State, Message>, Update: self::Update<State, Message>,
@ -98,8 +97,8 @@ where
type Theme = Theme; type Theme = Theme;
type Executor = executor::Default; type Executor = executor::Default;
fn build(&self) -> (Self::State, Command<Self::Message>) { fn load(&self) -> Command<Self::Message> {
(Self::State::default(), Command::none()) Command::none()
} }
fn update( fn update(
@ -151,25 +150,57 @@ pub struct Program<P: Definition> {
impl<P: Definition> Program<P> { impl<P: Definition> Program<P> {
/// Runs the underlying [`Application`] of the [`Program`]. /// Runs the underlying [`Application`] of the [`Program`].
///
/// The state of the [`Program`] must implement [`Default`].
/// If your state does not implement [`Default`], use [`run_with`]
/// instead.
///
/// [`run_with`]: Self::run_with
pub fn run(self) -> Result pub fn run(self) -> Result
where where
Self: 'static, Self: 'static,
P::State: Default,
{ {
struct Instance<P: Definition> { self.run_with(P::State::default)
}
/// Runs the underlying [`Application`] of the [`Program`] with a
/// closure that creates the initial state.
pub fn run_with(
self,
initialize: impl Fn() -> P::State + Clone + 'static,
) -> Result
where
Self: 'static,
{
use std::marker::PhantomData;
struct Instance<P: Definition, I> {
program: P, program: P,
state: P::State, state: P::State,
_initialize: PhantomData<I>,
} }
impl<P: Definition> Application for Instance<P> { impl<P: Definition, I: Fn() -> P::State> Application for Instance<P, I> {
type Message = P::Message; type Message = P::Message;
type Theme = P::Theme; type Theme = P::Theme;
type Flags = P; type Flags = (P, I);
type Executor = P::Executor; type Executor = P::Executor;
fn new(program: Self::Flags) -> (Self, Command<Self::Message>) { fn new(
let (state, command) = P::build(&program); (program, initialize): Self::Flags,
) -> (Self, Command<Self::Message>) {
let state = initialize();
let command = program.load();
(Self { program, state }, command) (
Self {
program,
state,
_initialize: PhantomData,
},
command,
)
} }
fn title(&self) -> String { fn title(&self) -> String {
@ -206,7 +237,7 @@ impl<P: Definition> Program<P> {
let Self { raw, settings } = self; let Self { raw, settings } = self;
Instance::run(Settings { Instance::run(Settings {
flags: raw, flags: (raw, initialize),
id: settings.id, id: settings.id,
window: settings.window, window: settings.window,
fonts: settings.fonts, fonts: settings.fonts,
@ -389,7 +420,7 @@ pub trait Definition: Sized {
/// The executor of the program. /// The executor of the program.
type Executor: Executor; type Executor: Executor;
fn build(&self) -> (Self::State, Command<Self::Message>); fn load(&self) -> Command<Self::Message>;
fn update( fn update(
&self, &self,
@ -445,8 +476,8 @@ fn with_title<P: Definition>(
type Theme = P::Theme; type Theme = P::Theme;
type Executor = P::Executor; type Executor = P::Executor;
fn build(&self) -> (Self::State, Command<Self::Message>) { fn load(&self) -> Command<Self::Message> {
self.program.build() self.program.load()
} }
fn title(&self, state: &Self::State) -> String { fn title(&self, state: &Self::State) -> String {
@ -509,10 +540,8 @@ fn with_load<P: Definition>(
type Theme = P::Theme; type Theme = P::Theme;
type Executor = executor::Default; type Executor = executor::Default;
fn build(&self) -> (Self::State, Command<Self::Message>) { fn load(&self) -> Command<Self::Message> {
let (state, command) = self.program.build(); Command::batch([self.program.load(), (self.load)()])
(state, Command::batch([command, (self.load)()]))
} }
fn update( fn update(
@ -582,8 +611,8 @@ fn with_subscription<P: Definition>(
(self.subscription)(state) (self.subscription)(state)
} }
fn build(&self) -> (Self::State, Command<Self::Message>) { fn load(&self) -> Command<Self::Message> {
self.program.build() self.program.load()
} }
fn update( fn update(
@ -646,8 +675,8 @@ fn with_theme<P: Definition>(
(self.theme)(state) (self.theme)(state)
} }
fn build(&self) -> (Self::State, Command<Self::Message>) { fn load(&self) -> Command<Self::Message> {
self.program.build() self.program.load()
} }
fn title(&self, state: &Self::State) -> String { fn title(&self, state: &Self::State) -> String {
@ -714,8 +743,8 @@ fn with_style<P: Definition>(
(self.style)(state, theme) (self.style)(state, theme)
} }
fn build(&self) -> (Self::State, Command<Self::Message>) { fn load(&self) -> Command<Self::Message> {
self.program.build() self.program.load()
} }
fn title(&self, state: &Self::State) -> String { fn title(&self, state: &Self::State) -> String {