use std::ptr::NonNull;
use crate::dlkr::DLAllocator;
use super::FD4BasicHashString;
use shared::{Subclass, Superclass};
#[repr(C)]
#[derive(Superclass)]
pub struct FD4ResCap {
vftable: usize,
pub name: FD4BasicHashString,
pub owning_repository: Option<NonNull<FD4ResCapHolder<FD4ResCap>>>,
pub next_item: Option<NonNull<FD4ResCap>>,
_unk58: u64,
_unk60: u64,
}
#[repr(C)]
pub struct FD4ResCapHolder<T>
where
T: Subclass<FD4ResCap>,
{
vftable: usize,
pub allocator: &'static DLAllocator,
_unk10: u64,
_unk18: u32,
pub bucket_count: u32,
pub buckets: NonNull<Option<NonNull<T>>>,
}
impl<T> FD4ResCapHolder<T>
where
T: Subclass<FD4ResCap>,
{
pub fn entries<'a>(&'a self) -> impl Iterator<Item = &'a T> + 'a {
struct Iter<'a, T: Subclass<FD4ResCap>> {
buckets_ptr: *const Option<NonNull<T>>,
bucket_count: usize,
current_bucket: usize,
current_ptr: Option<NonNull<T>>,
_marker: std::marker::PhantomData<&'a T>,
}
impl<'a, T: Subclass<FD4ResCap>> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
while self.current_ptr.is_none() && self.current_bucket < self.bucket_count {
let bucket = *self.buckets_ptr.add(self.current_bucket);
self.current_bucket += 1;
if bucket.is_some() {
self.current_ptr = bucket;
break;
}
}
if let Some(ptr) = self.current_ptr {
let item = ptr.as_ref();
let next = item.superclass().next_item.map(|p| p.cast());
self.current_ptr = next;
Some(item)
} else {
None
}
}
}
}
let buckets_ptr = self.buckets.as_ptr() as *const Option<NonNull<T>>;
let bucket_count = self.bucket_count as usize;
Iter {
buckets_ptr,
bucket_count,
current_bucket: 0,
current_ptr: None,
_marker: std::marker::PhantomData,
}
}
pub fn entries_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut T> + 'a {
struct IterMut<'a, T: Subclass<FD4ResCap>> {
buckets_ptr: *const Option<NonNull<T>>,
bucket_count: usize,
current_bucket: usize,
current_ptr: Option<NonNull<T>>,
_marker: std::marker::PhantomData<&'a mut T>,
}
impl<'a, T: Subclass<FD4ResCap>> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
while self.current_ptr.is_none() && self.current_bucket < self.bucket_count {
let bucket = *self.buckets_ptr.add(self.current_bucket);
self.current_bucket += 1;
if bucket.is_some() {
self.current_ptr = bucket;
break;
}
}
if let Some(mut ptr) = self.current_ptr {
let item = ptr.as_mut();
let next = item.superclass_mut().next_item.map(|p| p.cast());
self.current_ptr = next;
Some(item)
} else {
None
}
}
}
}
let buckets_ptr = self.buckets.as_ptr() as *const Option<NonNull<T>>;
let bucket_count = self.bucket_count as usize;
IterMut {
buckets_ptr,
bucket_count,
current_bucket: 0,
current_ptr: None,
_marker: std::marker::PhantomData,
}
}
}