Gen7ScriptsRs/pkmn_lib_interface/src/app_interface/list.rs

115 lines
3.0 KiB
Rust
Executable File

use crate::{ExternalReferenceType, VecExternRef};
use alloc::boxed::Box;
#[cfg(feature = "mock_data")]
use alloc::rc::Rc;
use alloc::vec::Vec;
use core::marker::PhantomData;
#[cfg(not(feature = "mock_data"))]
struct ImmutableListInner<T: Clone> {
extern_ref: VecExternRef<T>,
resource_type: PhantomData<T>,
values: spin::RwLock<Vec<Option<Option<T>>>>,
}
#[derive(Clone)]
#[cfg(not(feature = "mock_data"))]
pub struct ImmutableList<T>
where
T: Clone,
T: ExternalReferenceType,
{
inner: *const ImmutableListInner<T>,
}
#[cfg(not(feature = "mock_data"))]
impl<T> ImmutableList<T>
where
T: Clone,
T: ExternalReferenceType,
{
fn new(extern_ref: VecExternRef<T>) -> Self {
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);
ImmutableList {
inner: inner_ptr as *const ImmutableListInner<T>,
}
}
pub(crate) fn from_ref(extern_ref: VecExternRef<T>) -> Self {
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>;
ImmutableList { inner }
} else {
let v = Self::new(extern_ref);
CACHE
.as_mut()
.unwrap()
.insert(extern_ref.get_internal_index(), v.inner as *const u8);
v
}
}
}
pub fn get(&self, index: u32) -> Option<T> {
unsafe {
let inner = self.inner.as_ref().unwrap();
{
let rg = inner.values.read();
let v = rg.get(index as usize).unwrap();
if let Some(v) = v {
return v.clone();
}
}
let r = inner.extern_ref.at(index);
let value = r.get_value();
let mut wg = inner.values.write();
wg[index as usize] = Some(value);
wg[index as usize].as_ref().unwrap().clone()
}
}
}
#[cfg(feature = "mock_data")]
pub struct ImmutableListInner<T> {
values: Vec<T>,
}
#[cfg(feature = "mock_data")]
#[derive(Clone)]
pub struct ImmutableList<T> {
inner: Rc<ImmutableListInner<T>>,
}
#[cfg(feature = "mock_data")]
impl<T> ImmutableList<T>
where
T: Clone,
{
pub fn mock(values: Vec<T>) -> Self {
Self {
inner: Rc::new(ImmutableListInner { values }),
}
}
pub fn get(&self, index: u32) -> Option<T> {
self.inner.values.get(index as usize).cloned()
}
}
static mut CACHE: Option<hashbrown::HashMap<u32, *const u8>> = None;