|
|
@ -11,154 +11,246 @@ impl CommandId for u64 { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub trait WithCommandData { |
|
|
|
pub trait WithCommandInfo { |
|
|
|
fn command_data(&self) -> &CommandData; |
|
|
|
fn command_info(&self) -> &CommandInfo; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub trait CommandInfo: CommandId { |
|
|
|
pub trait GetCommandInfo: CommandId { |
|
|
|
fn name(&self) -> &str; |
|
|
|
fn name(&self) -> &str; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub struct CommandData { |
|
|
|
pub struct CommandInfo { |
|
|
|
command_id: u64, |
|
|
|
command_id: u64, |
|
|
|
name: String, |
|
|
|
name: String, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl CommandData { |
|
|
|
impl CommandInfo { |
|
|
|
pub fn new<TName: Into<String>>(command_id: u64, name: TName) -> Self { |
|
|
|
pub fn new<TName: Into<String>>(command_id: u64, name: TName) -> Self { |
|
|
|
CommandData { |
|
|
|
Self { |
|
|
|
command_id, |
|
|
|
command_id, |
|
|
|
name: name.into(), |
|
|
|
name: name.into(), |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl CommandId for CommandData { |
|
|
|
impl CommandId for CommandInfo { |
|
|
|
fn command_id(&self) -> u64 { |
|
|
|
fn command_id(&self) -> u64 { |
|
|
|
self.command_id |
|
|
|
self.command_id |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl CommandInfo for CommandData { |
|
|
|
impl GetCommandInfo for CommandInfo { |
|
|
|
fn name(&self) -> &str { |
|
|
|
fn name(&self) -> &str { |
|
|
|
&self.name |
|
|
|
&self.name |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl<T: WithCommandData> CommandId for T { |
|
|
|
impl<T: WithCommandInfo> CommandId for T { |
|
|
|
fn command_id(&self) -> u64 { |
|
|
|
fn command_id(&self) -> u64 { |
|
|
|
self.command_data().command_id |
|
|
|
self.command_info().command_id |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl<T: WithCommandData> CommandInfo for T { |
|
|
|
impl<T: WithCommandInfo> GetCommandInfo for T { |
|
|
|
fn name(&self) -> &str { |
|
|
|
fn name(&self) -> &str { |
|
|
|
&self.command_data().name |
|
|
|
&self.command_info().name |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Clone, Copy)] |
|
|
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)] |
|
|
|
pub enum CommandResult { |
|
|
|
pub enum CommandResult { |
|
|
|
Continue, |
|
|
|
Continue, |
|
|
|
Done, |
|
|
|
Done, |
|
|
|
Cancel, |
|
|
|
Cancel, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub trait Command: WithCommandData { |
|
|
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)] |
|
|
|
fn init(&mut self); |
|
|
|
pub enum CommandStatus { |
|
|
|
fn step(&mut self) -> CommandResult; |
|
|
|
Stopped, |
|
|
|
fn finish(&mut self, result: CommandResult); |
|
|
|
Running, |
|
|
|
} |
|
|
|
Ended, |
|
|
|
|
|
|
|
Cancelling, |
|
|
|
pub struct GenericCommand<TConfig, TState> { |
|
|
|
Cancelled, |
|
|
|
command_data: CommandData, |
|
|
|
|
|
|
|
pub config: TConfig, |
|
|
|
|
|
|
|
pub state: TState, |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl<TConfig, TState> GenericCommand<TConfig, TState> |
|
|
|
pub struct CommandContext<T> |
|
|
|
where |
|
|
|
where |
|
|
|
TConfig: 'static, |
|
|
|
T: CommandImp, |
|
|
|
GenericCommand<TConfig, TState>: Command, |
|
|
|
|
|
|
|
TState: Default + 'static, |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
pub fn new(command_data: CommandData, config: TConfig) -> Self { |
|
|
|
info: CommandInfo, |
|
|
|
|
|
|
|
status: CommandStatus, |
|
|
|
|
|
|
|
state: <T as CommandImp>::State, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<T: CommandImp> CommandContext<T> { |
|
|
|
|
|
|
|
pub fn status(&self) -> CommandStatus { |
|
|
|
|
|
|
|
self.status |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn state(&mut self) -> &mut T::State { |
|
|
|
|
|
|
|
&mut self.state |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<T: CommandImp> WithCommandInfo for CommandContext<T> { |
|
|
|
|
|
|
|
fn command_info(&self) -> &CommandInfo { |
|
|
|
|
|
|
|
&self.info |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub trait CommandImp { |
|
|
|
|
|
|
|
type State: Default; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn init(&self, ctx: &mut CommandContext<Self>) |
|
|
|
|
|
|
|
where |
|
|
|
|
|
|
|
Self: Sized; |
|
|
|
|
|
|
|
fn step(&self, ctx: &mut CommandContext<Self>) -> CommandResult |
|
|
|
|
|
|
|
where |
|
|
|
|
|
|
|
Self: Sized; |
|
|
|
|
|
|
|
fn finish(&self, ctx: &mut CommandContext<Self>) |
|
|
|
|
|
|
|
where |
|
|
|
|
|
|
|
Self: Sized; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub trait Command: WithCommandInfo { |
|
|
|
|
|
|
|
fn reset(&mut self); |
|
|
|
|
|
|
|
fn status(&self) -> CommandStatus; |
|
|
|
|
|
|
|
fn execute(&mut self) -> CommandStatus; |
|
|
|
|
|
|
|
fn cancel(&mut self); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub struct GenericCommand<T: CommandImp> { |
|
|
|
|
|
|
|
context: CommandContext<T>, |
|
|
|
|
|
|
|
imp: T, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<T: CommandImp + 'static> GenericCommand<T> { |
|
|
|
|
|
|
|
pub fn new(info: CommandInfo, imp: T) -> Self { |
|
|
|
Self { |
|
|
|
Self { |
|
|
|
command_data, |
|
|
|
context: CommandContext { |
|
|
|
config, |
|
|
|
info, |
|
|
|
state: TState::default(), |
|
|
|
status: CommandStatus::Stopped, |
|
|
|
|
|
|
|
state: T::State::default(), |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
imp, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn new_ref(command_data: CommandData, config: TConfig) -> CommandRef { |
|
|
|
pub fn new_ref(info: CommandInfo, imp: T) -> CommandRef { |
|
|
|
Rc::new(RefCell::new(Self::new(command_data, config))) |
|
|
|
Rc::new(RefCell::new(Self::new(info, imp))) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<T: CommandImp> WithCommandInfo for GenericCommand<T> { |
|
|
|
|
|
|
|
fn command_info(&self) -> &CommandInfo { |
|
|
|
|
|
|
|
&self.context.info |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl<TConfig, TState> WithCommandData for GenericCommand<TConfig, TState> { |
|
|
|
impl<T: CommandImp> Command for GenericCommand<T> { |
|
|
|
fn command_data(&self) -> &CommandData { |
|
|
|
fn status(&self) -> CommandStatus { |
|
|
|
&self.command_data |
|
|
|
self.context.status |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn execute(&mut self) -> CommandStatus { |
|
|
|
|
|
|
|
use self::CommandResult::*; |
|
|
|
|
|
|
|
use self::CommandStatus::*; |
|
|
|
|
|
|
|
let do_cancel = |me: &mut Self| { |
|
|
|
|
|
|
|
me.context.status = Cancelling; |
|
|
|
|
|
|
|
me.imp.finish(&mut me.context); |
|
|
|
|
|
|
|
Cancelled |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
let do_step = |me: &mut Self| { |
|
|
|
|
|
|
|
let result = me.imp.step(&mut me.context); |
|
|
|
|
|
|
|
match result { |
|
|
|
|
|
|
|
Continue => Running, |
|
|
|
|
|
|
|
Done => { |
|
|
|
|
|
|
|
me.imp.finish(&mut me.context); |
|
|
|
|
|
|
|
Ended |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Cancel => do_cancel(me), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
let new_status = match self.status() { |
|
|
|
|
|
|
|
Stopped => { |
|
|
|
|
|
|
|
self.imp.init(&mut self.context); |
|
|
|
|
|
|
|
do_step(self) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Running => do_step(self), |
|
|
|
|
|
|
|
Ended => Ended, |
|
|
|
|
|
|
|
Cancelling => do_cancel(self), |
|
|
|
|
|
|
|
Cancelled => Cancelled, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
self.context.status = new_status; |
|
|
|
|
|
|
|
new_status |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn reset(&mut self) { |
|
|
|
|
|
|
|
self.context.status = CommandStatus::Stopped; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
fn cancel(&mut self) { |
|
|
|
|
|
|
|
self.context.status = CommandStatus::Cancelling; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
macro_rules! command_impl { |
|
|
|
macro_rules! command_impl { |
|
|
|
( |
|
|
|
( |
|
|
|
$command:ident<$tconfig:ty,$tstate:ty>; |
|
|
|
$command:ident<$tconfig:ty,$tstate:ty>; |
|
|
|
$init_self:ident => $init:block; |
|
|
|
$slf:ident, $ctx:ident => $init:block; |
|
|
|
$step_self:ident => $step:block; |
|
|
|
$step:block; |
|
|
|
$finish_self:ident, $finish_result:ident => $finish:block |
|
|
|
$finish:block |
|
|
|
) => { |
|
|
|
) => { |
|
|
|
pub type $command = GenericCommand<$tconfig, $tstate>; |
|
|
|
impl $crate::command::CommandImp for $tconfig { |
|
|
|
|
|
|
|
type State = $tstate; |
|
|
|
|
|
|
|
|
|
|
|
impl $crate::command::Command for $command { |
|
|
|
fn init(&$slf, $ctx: &mut $crate::command::CommandContext<Self>) { |
|
|
|
fn init(&mut $init_self) { |
|
|
|
use $crate::command::GetCommandInfo; |
|
|
|
use $crate::command::CommandInfo; |
|
|
|
|
|
|
|
debug!( |
|
|
|
debug!( |
|
|
|
"{}({}) init", |
|
|
|
"{}({}) init", |
|
|
|
stringify!($command_st), |
|
|
|
stringify!($command), |
|
|
|
$init_self.name() |
|
|
|
$ctx.name() |
|
|
|
); |
|
|
|
); |
|
|
|
$init; |
|
|
|
$init; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn step(&mut $step_self) -> $crate::command::CommandResult { |
|
|
|
fn step(&$slf, $ctx: &mut $crate::command::CommandContext<Self>) -> $crate::command::CommandResult { |
|
|
|
use $crate::command::CommandInfo; |
|
|
|
use $crate::command::GetCommandInfo; |
|
|
|
debug!( |
|
|
|
debug!( |
|
|
|
"{}({}) step", |
|
|
|
"{}({}) step", |
|
|
|
stringify!($command_st), |
|
|
|
stringify!($command), |
|
|
|
$step_self.name() |
|
|
|
$ctx.name() |
|
|
|
); |
|
|
|
); |
|
|
|
$step |
|
|
|
$step |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn finish(&mut $finish_self, $finish_result: $crate::command::CommandResult) { |
|
|
|
fn finish(&$slf, $ctx: &mut $crate::command::CommandContext<Self>) { |
|
|
|
use $crate::command::CommandInfo; |
|
|
|
use $crate::command::GetCommandInfo; |
|
|
|
debug!( |
|
|
|
debug!( |
|
|
|
"{}({}) finish({:?}", |
|
|
|
"{}({}) finish({:?})", |
|
|
|
stringify!($command_st), |
|
|
|
stringify!($command), |
|
|
|
$finish_self.name(), |
|
|
|
$ctx.name(), |
|
|
|
$finish_result, |
|
|
|
$ctx.status(), |
|
|
|
); |
|
|
|
); |
|
|
|
$finish; |
|
|
|
$finish; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
pub type $command = $crate::command::GenericCommand<$tconfig>; |
|
|
|
}; |
|
|
|
}; |
|
|
|
( |
|
|
|
( |
|
|
|
$command:ident<$tconfig:ty,$tstate:ty>; |
|
|
|
$command:ident<$tconfig:ty,$tstate:ty>; |
|
|
|
$init_self:ident => $init:block; |
|
|
|
$slf:ident => $init:block; |
|
|
|
$step_self:ident => $step:block; |
|
|
|
$step:block; |
|
|
|
$finish_self:ident => $finish:block |
|
|
|
$finish:block |
|
|
|
) => { |
|
|
|
) => { |
|
|
|
command_impl! { $command<$tconfig,$tstate>; |
|
|
|
command_impl! { $command<$tconfig,$tstate>; |
|
|
|
$init_self => $init; $step_self => $step; $finish_self, res => {} } |
|
|
|
$init_self, cts => $init; $step; $finish } |
|
|
|
}; |
|
|
|
}; |
|
|
|
( |
|
|
|
( |
|
|
|
$command:ident<$tconfig:ty>; |
|
|
|
$command:ident<$tconfig:ty>; |
|
|
|
$init_self:ident => $init:block |
|
|
|
$slf:ident => $init:block |
|
|
|
) => { |
|
|
|
) => { |
|
|
|
command_impl! { $command<$tconfig,()>; |
|
|
|
command_impl! { $command<$tconfig,()>; |
|
|
|
$init_self => $init; self => { $crate::command::CommandResult::Done }; self => {} } |
|
|
|
$slf, ctx => $init; { $crate::command::CommandResult::Done }; {} } |
|
|
|
}; |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -175,134 +267,84 @@ impl CommandGroupConfig { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub struct CommandGroupState { |
|
|
|
pub struct CommandGroupState { |
|
|
|
current_idx: Option<usize>, |
|
|
|
current_idx: usize, |
|
|
|
has_initialized: bool, |
|
|
|
|
|
|
|
has_cancelled: bool, |
|
|
|
has_cancelled: bool, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl Default for CommandGroupState { |
|
|
|
impl Default for CommandGroupState { |
|
|
|
fn default() -> Self { |
|
|
|
fn default() -> Self { |
|
|
|
CommandGroupState { |
|
|
|
CommandGroupState { |
|
|
|
current_idx: None, |
|
|
|
current_idx: 0, |
|
|
|
has_initialized: false, |
|
|
|
|
|
|
|
has_cancelled: false, |
|
|
|
has_cancelled: false, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub type CommandGroup = GenericCommand<CommandGroupConfig, CommandGroupState>; |
|
|
|
pub type CommandGroup = GenericCommand<CommandGroupConfig>; |
|
|
|
|
|
|
|
|
|
|
|
impl Command for CommandGroup { |
|
|
|
impl CommandImp for CommandGroupConfig { |
|
|
|
fn init(&mut self) { |
|
|
|
type State = CommandGroupState; |
|
|
|
if self.state.current_idx.is_some() { |
|
|
|
|
|
|
|
error!("CommandGroup init called twice"); |
|
|
|
fn init(&self, ctx: &mut CommandContext<Self>) { |
|
|
|
} |
|
|
|
*ctx.state() = Default::default(); |
|
|
|
self.state.current_idx = Some(0); |
|
|
|
debug!("CommandGroup {} init", ctx.name()); |
|
|
|
self.state.has_initialized = false; |
|
|
|
|
|
|
|
self.state.has_cancelled = false; |
|
|
|
|
|
|
|
debug!("CommandGroup {} init", self.command_data().name()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn step(&mut self) -> CommandResult { |
|
|
|
fn step(&self, ctx: &mut CommandContext<Self>) -> CommandResult { |
|
|
|
use self::CommandResult::*; |
|
|
|
use self::CommandResult::*; |
|
|
|
let state = &mut self.state; |
|
|
|
use self::CommandStatus::*; |
|
|
|
let commands = &self.config.commands; |
|
|
|
let state = ctx.state(); |
|
|
|
|
|
|
|
let commands = &self.commands; |
|
|
|
if state.has_cancelled { |
|
|
|
if state.has_cancelled { |
|
|
|
debug!("CommandGroup step called after cancelled"); |
|
|
|
debug!("CommandGroup step called after cancelled"); |
|
|
|
return CommandResult::Cancel; |
|
|
|
return CommandResult::Cancel; |
|
|
|
} |
|
|
|
} |
|
|
|
let mut current_idx = if let Some(c) = state.current_idx { |
|
|
|
let current_idx = &mut state.current_idx; |
|
|
|
c |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
error!("CommandGroup step called before init"); |
|
|
|
|
|
|
|
state.has_cancelled = true; |
|
|
|
|
|
|
|
return CommandResult::Cancel; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
let mut result: CommandResult; |
|
|
|
|
|
|
|
loop { |
|
|
|
loop { |
|
|
|
if current_idx >= commands.len() { |
|
|
|
if *current_idx >= commands.len() { |
|
|
|
debug!("CommandGroup out of commands"); |
|
|
|
debug!("CommandGroup out of commands"); |
|
|
|
return CommandResult::Done; |
|
|
|
return CommandResult::Done; |
|
|
|
} |
|
|
|
} |
|
|
|
let mut command = commands[current_idx].borrow_mut(); |
|
|
|
let mut command = commands[*current_idx].borrow_mut(); |
|
|
|
if !state.has_initialized { |
|
|
|
let status = command.execute(); |
|
|
|
debug!( |
|
|
|
match status { |
|
|
|
"CommandGroup init {0} ({1})", |
|
|
|
Ended => { |
|
|
|
current_idx, |
|
|
|
command.reset(); |
|
|
|
command.command_data().name() |
|
|
|
*current_idx += 1; |
|
|
|
); |
|
|
|
|
|
|
|
command.init(); |
|
|
|
|
|
|
|
state.has_initialized = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
result = command.step(); |
|
|
|
|
|
|
|
if result != Continue { |
|
|
|
|
|
|
|
debug!( |
|
|
|
|
|
|
|
"CommandGroup {2:?} {0} ({1}) ", |
|
|
|
|
|
|
|
current_idx, |
|
|
|
|
|
|
|
command.command_data().name(), |
|
|
|
|
|
|
|
result |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
command.finish(result) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
match result { |
|
|
|
|
|
|
|
Done => { |
|
|
|
|
|
|
|
current_idx += 1; |
|
|
|
|
|
|
|
state.has_initialized = false; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
Cancel => { |
|
|
|
Cancelled => { |
|
|
|
|
|
|
|
command.reset(); |
|
|
|
state.has_cancelled = true; |
|
|
|
state.has_cancelled = true; |
|
|
|
break; |
|
|
|
return Cancel; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Running => return Continue, |
|
|
|
|
|
|
|
other => { |
|
|
|
|
|
|
|
warn!("CommandGroup unhandled status {:?}", other); |
|
|
|
|
|
|
|
return Continue; |
|
|
|
} |
|
|
|
} |
|
|
|
_ => break, |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
state.current_idx = Some(current_idx); |
|
|
|
|
|
|
|
CommandResult::Continue |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn finish(&mut self, result: CommandResult) { |
|
|
|
fn finish(&self, ctx: &mut CommandContext<Self>) { |
|
|
|
let state = &mut self.state; |
|
|
|
let commands = &self.commands; |
|
|
|
let commands = &mut self.config.commands; |
|
|
|
if ctx.status() == CommandStatus::Cancelling { |
|
|
|
if result == CommandResult::Cancel { |
|
|
|
if let Some(command) = commands.get(ctx.state().current_idx) { |
|
|
|
if let Some(command) = state |
|
|
|
let mut command = command.borrow_mut(); |
|
|
|
.current_idx |
|
|
|
command.cancel(); |
|
|
|
.and_then(|current_idx| commands.get(current_idx)) |
|
|
|
command.execute(); |
|
|
|
{ |
|
|
|
|
|
|
|
command.borrow_mut().finish(result); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
state.current_idx = None; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub struct CommandRun { |
|
|
|
pub struct CommandRun { |
|
|
|
initialized: bool, |
|
|
|
|
|
|
|
cancelled: bool, |
|
|
|
|
|
|
|
command: CommandRef, |
|
|
|
command: CommandRef, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl CommandId for CommandRun { |
|
|
|
impl CommandId for CommandRun { |
|
|
|
fn command_id(&self) -> u64 { |
|
|
|
fn command_id(&self) -> u64 { |
|
|
|
self.command.borrow().command_data().command_id() |
|
|
|
self.command.borrow().command_info().command_id() |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl CommandRun { |
|
|
|
|
|
|
|
pub fn initialized(&self) -> bool { |
|
|
|
|
|
|
|
self.initialized |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn cancelled(&self) -> bool { |
|
|
|
|
|
|
|
self.cancelled |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn cancel(&mut self) -> bool { |
|
|
|
|
|
|
|
if self.cancelled { |
|
|
|
|
|
|
|
false |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
self.cancelled = true; |
|
|
|
|
|
|
|
true |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -346,50 +388,28 @@ impl CommandScheduler { |
|
|
|
* Returns true if the command was started, false if it was not started because it was already running |
|
|
|
* Returns true if the command was started, false if it was not started because it was already running |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
pub fn start(&mut self, command: CommandRef) -> bool { |
|
|
|
pub fn start(&mut self, command: CommandRef) -> bool { |
|
|
|
if self.is_running(command.borrow().command_data().command_id()) { |
|
|
|
if self.is_running(command.borrow().command_info().command_id()) { |
|
|
|
false |
|
|
|
false |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
self.running_commands.push(CommandRun { |
|
|
|
self.running_commands.push(CommandRun { command }); |
|
|
|
initialized: false, |
|
|
|
|
|
|
|
cancelled: false, |
|
|
|
|
|
|
|
command, |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
true |
|
|
|
true |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn cancel<T: CommandId>(&mut self, id: T) -> bool { |
|
|
|
pub fn cancel<T: CommandId>(&mut self, id: T) -> bool { |
|
|
|
self.get_command_run_mut(id).map_or(false, |command_run| { |
|
|
|
self.get_command_run_mut(id).map_or(false, |command_run| { |
|
|
|
command_run.cancelled = true; |
|
|
|
command_run.command.borrow_mut().cancel(); |
|
|
|
true |
|
|
|
true |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn execute(&mut self) { |
|
|
|
pub fn execute(&mut self) { |
|
|
|
|
|
|
|
use self::CommandStatus::*; |
|
|
|
self.running_commands.drain_filter(|command_run| { |
|
|
|
self.running_commands.drain_filter(|command_run| { |
|
|
|
let mut command = command_run.command.borrow_mut(); |
|
|
|
let mut command = command_run.command.borrow_mut(); |
|
|
|
if !command_run.initialized && !command_run.cancelled { |
|
|
|
match command.execute() { |
|
|
|
{ |
|
|
|
Ended | Cancelled => true, |
|
|
|
let command_data = command.command_data(); |
|
|
|
Stopped | Running | Cancelling => false, |
|
|
|
debug!( |
|
|
|
|
|
|
|
"initialzing command {} (id {})", |
|
|
|
|
|
|
|
command_data.name(), |
|
|
|
|
|
|
|
command_data.command_id() |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
command.init(); |
|
|
|
|
|
|
|
command_run.initialized = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
let result = if command_run.initialized { |
|
|
|
|
|
|
|
command.step() |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
CommandResult::Cancel |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
if result != CommandResult::Continue { |
|
|
|
|
|
|
|
command.finish(result); |
|
|
|
|
|
|
|
true |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
false |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|