use std::{ ops::{Index, IndexMut}, ptr::NonNull, slice::SliceIndex, }; use once_cell::sync::OnceCell; static ALLOCATOR: OnceCell> = OnceCell::new(); pub fn set_allocator(ally: A) where A: std::alloc::Allocator + Send + Sync + 'static, { _ = ALLOCATOR.set(Box::new(ally)); } #[repr(C)] #[derive(Debug)] pub struct TArray { data: Option>, count: u32, max: u32, } unsafe impl Send for TArray where T: Send {} unsafe impl Sync for TArray where T: Sync {} pub type FString = TArray; impl ToString for FString { fn to_string(&self) -> String { widestring::U16Str::from_slice(&self).to_string_lossy() } } impl Drop for TArray { fn drop(&mut self) { if let Some(ptr) = self.data { unsafe { ALLOCATOR .get() .expect("allocator") .deallocate(ptr.cast(), std::alloc::Layout::for_value(ptr.as_ref())); } } } } impl TArray { pub fn new() -> Self { Self { data: None, count: 0, max: 0, } } pub unsafe fn set_len(&mut self, size: usize) { self.count = (size as u32).min(self.max); } pub fn reserve(&mut self, size: usize) { self.ensure_space(size); } fn ensure_space(&mut self, size: usize) { if self.data.is_none() || size >= self.max as usize { self.grow(size.max(self.max as usize * 2)); } } fn grow(&mut self, new_size: usize) { if new_size <= self.max as usize { return; } if self.max == 0 || self.data.is_none() { if let Some(alloc) = ALLOCATOR.get() { match alloc.allocate(std::alloc::Layout::array::(32).unwrap()) { Ok(ptr) => { self.data = Some(ptr.cast()); self.max = ptr.len() as u32; } Err(e) => { log::error!("failed to allocate with UE4 allocator: {e}."); } } } } else if let Some(alloc) = ALLOCATOR.get() { unsafe { match alloc.grow_zeroed( self.data.unwrap().cast(), std::alloc::Layout::array::(self.max as usize).unwrap(), std::alloc::Layout::array::(new_size).unwrap(), ) { Ok(ptr) => { self.data = Some(ptr.cast()); self.max = ptr.len() as u32; } Err(e) => { log::error!("failed to allocate with UE4 allocator: {e}."); } } } } } pub fn push(&mut self, value: T) { self.ensure_space(self.count as usize + 1); self.data.map(|ptr| unsafe { ptr.as_ptr().offset(self.count as isize).write(value); self.count += 1; }); } pub fn len(&self) -> usize { self.count as usize } pub fn capacity(&self) -> usize { self.max as usize } pub fn as_slice(&self) -> &[T] { match self.data { Some(ptr) => unsafe { core::slice::from_raw_parts(ptr.as_ptr(), self.len()) }, None => unsafe { core::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0) }, } } pub fn as_slice_mut(&mut self) -> &mut [T] { match self.data { Some(ptr) => unsafe { core::slice::from_raw_parts_mut(ptr.as_ptr(), self.len()) }, None => unsafe { core::slice::from_raw_parts_mut(NonNull::dangling().as_ptr(), 0) }, } } } impl> Index for TArray { type Output = I::Output; fn index(&self, i: I) -> &Self::Output { let data = self.as_slice(); &data[i] } } impl> IndexMut for TArray { fn index_mut(&mut self, i: I) -> &mut Self::Output { let data = self.as_slice_mut(); &mut data[i] } } impl std::ops::Deref for TArray { type Target = [T]; fn deref(&self) -> &Self::Target { self.as_slice() } } impl std::ops::DerefMut for TArray { fn deref_mut(&mut self) -> &mut Self::Target { self.as_slice_mut() } } pub struct IntoIter { //array_ref: &'a TArray, ptr: *const T, end: *const T, } impl<'a, T> IntoIter { pub fn new(array: &'a TArray) -> Self { let ptr = array.data.unwrap().as_ptr(); Self { ptr, end: unsafe { ptr.offset(array.count as isize) }, } } } impl<'a, T> Iterator for IntoIter { type Item = T; fn next(&mut self) -> Option { if self.ptr == self.end { None } else { let old = self.ptr; self.ptr = unsafe { self.ptr.offset(1) }; Some(unsafe { std::ptr::read(old) }) } } } impl<'a, T> IntoIterator for &'a TArray { type Item = T; type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter::new(self) } }