Gen7ScriptsRs/pkmn_lib_interface/src/app_interface/static_data/data_libraries/type_library.rs

142 lines
4.3 KiB
Rust
Executable File

use crate::app_interface::TypeIdentifier;
use alloc::rc::Rc;
pub trait TypeLibraryTrait {
fn get_type_from_name(&self, name: &str) -> PkmnResult<Option<TypeIdentifier>>;
fn get_single_effectiveness(
&self,
attacking_type: TypeIdentifier,
defending_type: TypeIdentifier,
) -> PkmnResult<f32>;
fn get_effectiveness(
&self,
attacking_type: TypeIdentifier,
defending_types: &[TypeIdentifier],
) -> PkmnResult<f32>;
}
pub type Typelibrary = Rc<dyn TypeLibraryTrait>;
#[cfg(not(feature = "mock_data"))]
mod implementation {
use super::*;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::WasmResult;
use crate::PkmnResult;
use alloc::rc::Rc;
use alloc::string::{String, ToString};
use cstr_core::{c_char, CString};
use spin::RwLock;
struct TypeLibraryInner {
reference: ExternRef<TypeLibraryImpl>,
name_to_type_cache: RwLock<hashbrown::HashMap<String, TypeIdentifier>>,
effectiveness_cache: RwLock<hashbrown::HashMap<(TypeIdentifier, TypeIdentifier), f32>>,
}
#[derive(Clone)]
pub struct TypeLibraryImpl {
inner: Rc<TypeLibraryInner>,
}
impl TypeLibraryImpl {
#[cfg(not(feature = "mock_data"))]
pub(crate) fn new(reference: ExternRef<Self>) -> Self {
Self {
inner: Rc::new(TypeLibraryInner {
reference,
name_to_type_cache: Default::default(),
effectiveness_cache: Default::default(),
}),
}
}
}
impl TypeLibraryTrait for TypeLibraryImpl {
fn get_type_from_name(&self, name: &str) -> PkmnResult<Option<TypeIdentifier>> {
if let Some(cached) = self.inner.name_to_type_cache.read().get(name) {
return Ok(Some(*cached));
}
let cstr = CString::new(name).unwrap();
let v = unsafe {
type_library_get_type_by_name(self.inner.reference, cstr.as_ptr()).as_res()?
};
if v == 255 {
return Ok(None);
}
let v = v.into();
self.inner
.name_to_type_cache
.write()
.insert(name.to_string(), v);
Ok(Some(v))
}
fn get_single_effectiveness(
&self,
attacking_type: TypeIdentifier,
defending_type: TypeIdentifier,
) -> PkmnResult<f32> {
if let Some(cached) = self
.inner
.effectiveness_cache
.read()
.get(&(attacking_type, defending_type))
{
return Ok(*cached);
}
let effectiveness = unsafe {
type_library_get_single_effectiveness(
self.inner.reference,
attacking_type.into(),
defending_type.into(),
)
}
.as_res()?;
self.inner
.effectiveness_cache
.write()
.insert((attacking_type, defending_type), effectiveness);
Ok(effectiveness)
}
fn get_effectiveness(
&self,
attacking_type: TypeIdentifier,
defending_types: &[TypeIdentifier],
) -> PkmnResult<f32> {
let mut f = 1.0;
for defending_type in defending_types {
f *= self.get_single_effectiveness(attacking_type, *defending_type)?;
}
Ok(f)
}
}
crate::handling::cacheable::cacheable!(TypeLibraryImpl);
#[cfg(not(feature = "mock_data"))]
impl ExternalReferenceType for TypeLibraryImpl {
fn from_extern_value(reference: ExternRef<Self>) -> Self {
Self::new(reference)
}
}
#[cfg(not(feature = "mock_data"))]
extern "wasm" {
fn type_library_get_single_effectiveness(
r: ExternRef<TypeLibraryImpl>,
attacking_type: u8,
defending_type: u8,
) -> WasmResult<f32>;
fn type_library_get_type_by_name(
r: ExternRef<TypeLibraryImpl>,
name: *const c_char,
) -> WasmResult<u8>;
}
}
use crate::PkmnResult;
#[cfg(not(feature = "mock_data"))]
pub use implementation::*;