use crate::app_interface::{LearnedMove, Pokemon}; use crate::handling::Script; use alloc::boxed::Box; use alloc::rc::Rc; pub enum TurnChoice { Move(Box), Item(), Switch(), Flee, Pass, } impl TurnChoice { fn base(&self) -> BaseTurnChoiceData { match self { TurnChoice::Move(m) => m.base(), TurnChoice::Item() => unimplemented!(), TurnChoice::Switch() => unimplemented!(), TurnChoice::Flee => unimplemented!(), TurnChoice::Pass => unimplemented!(), } } pub fn user(&self) -> Pokemon { self.base().user() } pub fn speed(&self) -> PkmnResult { self.base().speed() } pub fn has_failed(&self) -> PkmnResult { self.base().has_failed() } pub fn fail(&self) -> PkmnResult<()> { self.base().fail() } } #[cfg_attr(feature = "mock_data", mockall::automock)] pub trait BaseTurnChoiceDataTrait { fn reference(&self) -> u32; fn user(&self) -> Pokemon; fn speed(&self) -> PkmnResult; fn has_failed(&self) -> PkmnResult; fn fail(&self) -> PkmnResult<()>; } pub type BaseTurnChoiceData = Rc; #[cfg(feature = "mock_data")] pub type MockBaseTurnChoiceData = MockBaseTurnChoiceDataTrait; #[cfg_attr(feature = "mock_data", mockall::automock)] pub trait MoveTurnChoiceDataTrait { fn base(&self) -> BaseTurnChoiceData; fn used_move(&self) -> LearnedMove; fn target_side(&self) -> u8; fn target_index(&self) -> u8; fn priority(&self) -> PkmnResult; fn move_script<'a>(&self) -> PkmnResult>>; } #[cfg(feature = "mock_data")] pub type MockMoveTurnChoiceData = MockMoveTurnChoiceDataTrait; #[cfg(not(feature = "mock_data"))] mod implementation { use super::*; use crate::app_interface::{LearnedMoveImpl, PokemonImpl}; use crate::handling::cached_value::CachedValue; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType}; use crate::handling::temporary::Temporary; use crate::handling::wasm_result::WasmResult; use crate::{cached_value, PkmnResult}; struct BaseTurnChoiceDataImpl { reference: ExternRef, user: CachedValue>, } impl BaseTurnChoiceDataTrait for BaseTurnChoiceDataImpl { fn reference(&self) -> u32 { self.reference.get_internal_index() } fn user(&self) -> Pokemon { self.user.value() } fn speed(&self) -> PkmnResult { unsafe { turn_choice_get_speed(self.reference).as_res() } } fn has_failed(&self) -> PkmnResult { unsafe { turn_choice_has_failed(self.reference).as_res() } } fn fail(&self) -> PkmnResult<()> { unsafe { turn_choice_fail(self.reference).as_res() } } } struct MoveTurnChoiceDataInner { base: BaseTurnChoiceData, used_move: CachedValue, target_side: CachedValue, target_index: CachedValue, } #[derive(Clone)] pub struct MoveTurnChoiceDataImpl { inner: Temporary, } #[cfg(not(feature = "mock_data"))] impl MoveTurnChoiceDataTrait for MoveTurnChoiceDataImpl { fn base(&self) -> BaseTurnChoiceData { self.inner.value().base.clone() } fn used_move(&self) -> LearnedMove { self.inner.value().used_move.value() } fn target_side(&self) -> u8 { self.inner.value().target_side.value() } fn target_index(&self) -> u8 { self.inner.value().target_index.value() } fn priority(&self) -> PkmnResult { unsafe { turn_choice_move_priority(self.base().reference().into()).as_res() } } fn move_script<'a>(&self) -> PkmnResult>> { unsafe { Ok( (turn_choice_move_script(self.base().reference().into()).as_res()? as *const Box) .as_ref(), ) } } } #[cfg(not(feature = "mock_data"))] impl ExternalReferenceType for TurnChoice { fn from_extern_value(reference: ExternRef) -> Self { let kind = unsafe { turn_choice_get_kind(reference).unwrap() }; match kind { 0 => TurnChoice::Move(Box::new(MoveTurnChoiceDataImpl { inner: Temporary::new( reference.get_internal_index(), MoveTurnChoiceDataInner::from_reference(reference.cast()), ), })), _ => panic!("Unknown turn choice type"), } } } #[cfg(not(feature = "mock_data"))] impl MoveTurnChoiceDataInner { fn from_reference(reference: ExternRef) -> Self { Self { base: Rc::new(BaseTurnChoiceDataImpl { reference: reference.cast(), user: cached_value!({ Rc::new( turn_choice_get_user(reference.cast()) .unwrap() .get_value() .unwrap(), ) }), }), used_move: cached_value!({ Rc::new( turn_choice_move_used_move(reference.cast()) .unwrap() .get_value() .unwrap(), ) }), target_side: cached_value!({ turn_choice_move_target_side(reference.cast()).unwrap() }), target_index: cached_value!({ turn_choice_move_target_index(reference.cast()).unwrap() }), } } } extern "wasm" { fn turn_choice_get_kind(r: ExternRef) -> WasmResult; fn turn_choice_get_user(r: ExternRef) -> WasmResult>; fn turn_choice_get_speed(r: ExternRef) -> WasmResult; fn turn_choice_has_failed(r: ExternRef) -> WasmResult; fn turn_choice_fail(r: ExternRef) -> WasmResult<()>; fn turn_choice_move_used_move( r: ExternRef, ) -> WasmResult>; fn turn_choice_move_target_side(r: ExternRef) -> WasmResult; fn turn_choice_move_target_index(r: ExternRef) -> WasmResult; fn turn_choice_move_priority(r: ExternRef) -> WasmResult; #[allow(improper_ctypes)] fn turn_choice_move_script(r: ExternRef) -> WasmResult; } } use crate::PkmnResult; #[cfg(not(feature = "mock_data"))] pub use implementation::*;