205 lines
6.3 KiB
Rust
Executable File
205 lines
6.3 KiB
Rust
Executable File
use alloc::rc::Rc;
|
|
|
|
pub trait ImmutableListTrait<T> {
|
|
fn get(&self, index: u32) -> Option<T>;
|
|
}
|
|
|
|
pub type ImmutableList<T> = Rc<dyn ImmutableListTrait<T>>;
|
|
|
|
#[cfg(not(feature = "mock_data"))]
|
|
mod implementation {
|
|
use super::*;
|
|
use crate::app_interface::{
|
|
BattleParty, BattlePartyImpl, BattleSide, BattleSideImpl, EffectParameter, StringKey,
|
|
};
|
|
use crate::handling::extern_ref::{ExternalReferenceType, VecExternRef};
|
|
use alloc::boxed::Box;
|
|
use alloc::vec::Vec;
|
|
use core::marker::PhantomData;
|
|
|
|
pub(crate) struct ImmutableListInner<T: Clone> {
|
|
extern_ref: VecExternRef<T>,
|
|
resource_type: PhantomData<T>,
|
|
values: spin::RwLock<Vec<Option<Option<Rc<T>>>>>,
|
|
}
|
|
|
|
pub(crate) trait ImmutableListWasm<T: Clone + ExternalReferenceType> {
|
|
fn initialize(inner: *const ImmutableListInner<T>) -> Self
|
|
where
|
|
Self: Sized;
|
|
|
|
fn new(extern_ref: VecExternRef<T>) -> Self
|
|
where
|
|
Self: Sized,
|
|
{
|
|
let mut values = Vec::new();
|
|
values.resize(extern_ref.len() as usize, None);
|
|
let inner = Box::new(ImmutableListInner {
|
|
extern_ref,
|
|
resource_type: Default::default(),
|
|
values: spin::RwLock::new(values),
|
|
});
|
|
let inner_ptr = Box::into_raw(inner);
|
|
Self::initialize(inner_ptr)
|
|
}
|
|
|
|
fn from_ref(extern_ref: VecExternRef<T>) -> Self
|
|
where
|
|
Self: Sized,
|
|
{
|
|
unsafe {
|
|
if let None = CACHE {
|
|
CACHE = Some(hashbrown::HashMap::new());
|
|
}
|
|
let existing = CACHE
|
|
.as_ref()
|
|
.unwrap()
|
|
.get(&extern_ref.get_internal_index());
|
|
if let Some(v) = existing {
|
|
let inner = *v as *const ImmutableListInner<T>;
|
|
Self::initialize(inner)
|
|
} else {
|
|
let v = Self::new(extern_ref);
|
|
CACHE.as_mut().unwrap().insert(
|
|
extern_ref.get_internal_index(),
|
|
v.get_inner_ptr() as *const u8,
|
|
);
|
|
v
|
|
}
|
|
}
|
|
}
|
|
|
|
fn get_inner(&self) -> &ImmutableListInner<T> {
|
|
unsafe { self.get_inner_ptr().as_ref().unwrap() }
|
|
}
|
|
fn get_inner_ptr(&self) -> *const ImmutableListInner<T>;
|
|
|
|
fn get_cached(&self, index: u32) -> Option<Rc<T>> {
|
|
let inner = self.get_inner();
|
|
let rg = inner.values.read();
|
|
let v = rg.get(index as usize).unwrap();
|
|
if let Some(v) = v {
|
|
return v.clone();
|
|
}
|
|
return None;
|
|
}
|
|
|
|
fn get_value(&self, index: u32) -> Option<Rc<T>> {
|
|
if let Some(cached) = self.get_cached(index) {
|
|
return Some(cached);
|
|
}
|
|
let inner = self.get_inner();
|
|
let r = inner.extern_ref.at(index);
|
|
let value = r.get_value();
|
|
let value = if let Some(value) = value {
|
|
Some(Rc::new(value))
|
|
} else {
|
|
None
|
|
};
|
|
let mut wg = inner.values.write();
|
|
wg[index as usize] = Some(value);
|
|
let v = wg[index as usize].as_ref().unwrap().clone();
|
|
v
|
|
}
|
|
}
|
|
|
|
macro_rules! immutable_list_type {
|
|
($type_name:ident, $underlying:ident) => {
|
|
paste::paste! {
|
|
pub struct [<$type_name ImmutableList>] {
|
|
inner: *const ImmutableListInner<$underlying>,
|
|
}
|
|
|
|
impl ImmutableListWasm<$underlying> for [<$type_name ImmutableList>] {
|
|
fn initialize(inner: *const ImmutableListInner<$underlying>) -> Self
|
|
where
|
|
Self: Sized,
|
|
{
|
|
Self { inner }
|
|
}
|
|
|
|
fn get_inner_ptr(&self) -> *const ImmutableListInner<$underlying> {
|
|
self.inner
|
|
}
|
|
}
|
|
|
|
impl ImmutableListTrait<$type_name> for [<$type_name ImmutableList>] {
|
|
fn get(&self, index: u32) -> Option<$type_name> {
|
|
let v = self.get_value(index);
|
|
if let Some(v) = v {
|
|
Some(v)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
immutable_list_type!(BattleSide, BattleSideImpl);
|
|
immutable_list_type!(BattleParty, BattlePartyImpl);
|
|
|
|
pub struct EffectParameterImmutableList {
|
|
inner: *const ImmutableListInner<EffectParameter>,
|
|
}
|
|
|
|
impl ImmutableListWasm<EffectParameter> for EffectParameterImmutableList {
|
|
fn initialize(inner: *const ImmutableListInner<EffectParameter>) -> Self
|
|
where
|
|
Self: Sized,
|
|
{
|
|
Self { inner }
|
|
}
|
|
|
|
fn get_inner_ptr(&self) -> *const ImmutableListInner<EffectParameter> {
|
|
self.inner
|
|
}
|
|
}
|
|
|
|
impl ImmutableListTrait<Rc<EffectParameter>> for EffectParameterImmutableList {
|
|
fn get(&self, index: u32) -> Option<Rc<EffectParameter>> {
|
|
let v = self.get_value(index);
|
|
if let Some(v) = v {
|
|
Some(v)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct StringKeyImmutableList {
|
|
inner: *const ImmutableListInner<StringKey>,
|
|
}
|
|
|
|
impl ImmutableListWasm<StringKey> for StringKeyImmutableList {
|
|
fn initialize(inner: *const ImmutableListInner<StringKey>) -> Self
|
|
where
|
|
Self: Sized,
|
|
{
|
|
Self { inner }
|
|
}
|
|
|
|
fn get_inner_ptr(&self) -> *const ImmutableListInner<StringKey> {
|
|
self.inner
|
|
}
|
|
}
|
|
|
|
impl ImmutableListTrait<Rc<StringKey>> for StringKeyImmutableList {
|
|
fn get(&self, index: u32) -> Option<Rc<StringKey>> {
|
|
let v = self.get_value(index);
|
|
if let Some(v) = v {
|
|
Some(v)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
static mut CACHE: Option<hashbrown::HashMap<u32, *const u8>> = None;
|
|
}
|
|
|
|
#[cfg(not(feature = "mock_data"))]
|
|
pub use implementation::*;
|