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