pub trait Complex: Core + Debug {
#[throws(ApiPieceOpError)]
- fn op_complex(&self, a: ApiPieceOpArgs) -> UpdateFromOpComplex;
+ fn op_complex(&self, a: ApiPieceOpArgs) -> OpOutcomeThunk;
}
impl<T> Complex for T where T: Core + Simple {
#[throws(ApiPieceOpError)]
- fn op_complex(&self, a: ApiPieceOpArgs) -> UpdateFromOpComplex {
- (self.op(a)?, None)
+ fn op_complex(&self, a: ApiPieceOpArgs) -> OpOutcomeThunk {
+ (self.op(a)?, None).into()
}
}
}
to_recalculate: &mut to_recalculate,
})?;
Ok::<_,ApiPieceOpError>((update, loose_conflict))
- })() {
+ })().and_then(|(thunk, loose_conflict)| Ok((
+ match thunk {
+ OpOutcomeThunk::Immediate(r) => r,
+ OpOutcomeThunk::Reborrow(f) => f(g, player, piece)?,
+ }, loose_conflict
+ ))) {
Err(APOE::Inapplicable(poe)) => {
PrepareUpdatesBuffer::piece_report_error(
&mut ig, poe,
n: MultigrabQty,
}
- as:
- #[throws(ApiPieceOpError)]
- fn op(&self, mut a: ApiPieceOpArgs) -> PieceUpdate {
- if ! a.ipc.special.multigrab { throw!(Ia::BadPieceStateForOperation) }
- let pri = a.pri()?;
- let y = pri.fully_visible().ok_or(Ia::Occultation)?;
- a.ipc.show(y).op_multigrab(a, pri, self.n)?
+ impl op::Core as { }
+ impl op::Complex as {
+ #[throws(ApiPieceOpError)]
+ fn op_complex(&self, mut a: ApiPieceOpArgs) -> OpOutcomeThunk {
+ if ! a.ipc.special.multigrab { throw!(Ia::BadPieceStateForOperation) }
+ let pri = a.pri()?;
+ let y = pri.fully_visible().ok_or(Ia::Occultation)?;
+ a.ipc.show(y).op_multigrab(a, pri, self.n)?
+ }
}
}
impl op::Core as { }
impl op::Complex as {
#[throws(ApiPieceOpError)]
- fn op_complex(&self, mut a: ApiPieceOpArgs) -> UpdateFromOpComplex {
+ fn op_complex(&self, mut a: ApiPieceOpArgs) -> OpOutcomeThunk {
let pri = a.pri()?;
let ApiPieceOpArgs { ioccults,player,piece,ipc, .. } = a;
let gs = &mut a.gs;
wrc,
PieceUpdateOp::Modify(()),
logents,
- ).into(), None)
+ ).into(), None).into()
},
_ => break,
#[throws(ApiPieceOpError)]
fn ui_operation(&self, _: ShowUnocculted, args: ApiPieceOpArgs<'_>,
opname: &str, _wrc: WhatResponseToClientOp)
- -> UpdateFromOpComplex {
+ -> OpOutcomeThunk {
let ApiPieceOpArgs { gs,piece,player,ioccults,ipc,ig,.. } = args;
let gpc = gs.pieces.byid_mut(piece)?;
let held = gpc.held;
);
r
}
- }
+ }.into()
}
#[throws(IE)]
fn ui_operation(&self, vis: ShowUnocculted,
a: ApiPieceOpArgs<'_>,
opname: &str, wrc: WhatResponseToClientOp)
- -> UpdateFromOpComplex {
+ -> OpOutcomeThunk {
let ApiPieceOpArgs { gs,player,piece,ipieces,ioccults,to_recalculate,.. } = a;
let gen = &mut gs.gen;
let gplayers = &mut gs.players;
(PieceUpdate {
wrc, log,
ops: puos.into(),
- }, xupdates.into_unprepared(None))
+ }, xupdates.into_unprepared(None)).into()
}
fn occultation_notify_hook(&self, piece: PieceId) -> UnpreparedUpdates {
#[throws(ApiPieceOpError)]
fn ui_operation(&self, _: ShowUnocculted, args: ApiPieceOpArgs<'_>,
opname: &str, wrc: WhatResponseToClientOp)
- -> UpdateFromOpComplex {
+ -> OpOutcomeThunk {
let ApiPieceOpArgs { gs,piece,player,ioccults,ipc,.. } = args;
let gpc = gs.pieces.byid_mut(piece)?;
let gpl = gs.players.byid(player)?;
wrc,
PieceUpdateOp::Modify(()),
logents,
- ).into(), None)
+ ).into(), None).into()
},
_ => throw!(Ia::BadUiOperation)
fn ui_operation(&self, _: ShowUnocculted, _a: ApiPieceOpArgs<'_>,
_opname: &str, _wrc: WhatResponseToClientOp)
- -> Result<UpdateFromOpComplex, ApiPieceOpError> {
+ -> Result<OpOutcomeThunk, ApiPieceOpError> {
throw!(Ia::BadUiOperation)
}
None
}
+ #[throws(ApiPieceOpError)]
fn op_multigrab(&self, _: ApiPieceOpArgs, _: PieceRenderInstructions,
- _: MultigrabQty) -> Result<PieceUpdate,ApiPieceOpError> {
+ _: MultigrabQty) -> OpOutcomeThunk {
Err(Ia::BadPieceStateForOperation)?
}
#[throws(ApiPieceOpError)]
fn ui_operation(&self, vis: ShowUnocculted, mut a: ApiPieceOpArgs<'_>,
opname: &str, wrc: WhatResponseToClientOp)
- -> UpdateFromOpComplex {
+ -> OpOutcomeThunk {
if let Some(r) = {
let gpc = a.gs.pieces.byid_mut(a.piece)?;
let rot_checked = gpc.occulter_check_unrotated(vis)?;
internal_error_bydebug(&(&gpc.pos, &self.shape)))?;
organise::ui_operation(&mut a, rot_checked, opname, wrc, &rect)?
} {
- return r;
+ return r.into();
}
let ApiPieceOpArgs { gs,player,piece,ipieces,ioccults,to_recalculate,.. } = a;
wrc, log,
ops: puos.into(),
}, xupdates.into_unprepared(None))
+ .into()
}
fn occultation_notify_hook(&self, piece: PieceId) -> UnpreparedUpdates {
SetZLevelQuiet(ZL),
}
+#[derive(From)]
+pub enum OpOutcomeThunk {
+ Immediate(UpdateFromOpComplex),
+ /// Allows a UI operation full mutable access to the whole Instance.
+ ///
+ /// Use with care! Eg, you might have to call save_game_and_aux_late.r
+ ///
+ /// Rules for adding and removing pieces:
+ ///
+ /// * Adding a piece: add it to both ipieces and pieces.
+ /// Call `save_game_and_aux_later`.
+ /// Aux is always saved first, so if the piece is in pieces,
+ /// it will be in ipieces on any reload.
+ ///
+ /// * Deleting a piece: if the deletion as not the result of
+ /// some kind of merge, and it doesn't matter if only the
+ /// deletion happens, and not other recent events: just delete it.
+ /// Call `save_game_and_aux_later`.
+ ///
+ /// * Deleting a piece, in some kind of more complicated situation
+ /// where the deletion must be atomic with other operations.
+ /// Delete the piece *only* from pieces. Leave it in ipieces.
+ /// A reload will always restore a `GameState` snapshot.
+ /// TODO: we should garbage-collect the slot in ipieces.
+ ///
+ /// TODO: Provide `&mut InstanceGuard` to the closure,
+ /// not `&umut Instance`, since the latter is not sufficient.
+ ///
+ /// TODO: Provide cooked methods for this (taking `ModifyingPieces`)
+ ///
+ /// TODO: Provide a `ModifyingPieces` to the closure.
+ Reborrow(Box<dyn FnOnce(&mut Instance, PlayerId, PieceId)
+ -> Result<UpdateFromOpComplex, ApiPieceOpError>>),
+}
+
pub type UpdateFromOpComplex = (
PieceUpdate,
UnpreparedUpdates,