use std::ptr::NonNull;
use bitfield::bitfield;
use crate::dlkr::DLAllocator;
use crate::fd4::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>>,
pub reference_count: u32,
unk5c: u32,
unk60: bool,
unk61: [u8; 7],
unk68: usize,
unk70: u8,
unk71: [u8; 7],
}
#[repr(C)]
#[derive(Superclass, Subclass)]
pub struct FD4ResRep {
pub res_cap: FD4ResCap,
}
#[repr(C)]
pub struct FD4ResCapHolder<T>
where
T: Subclass<FD4ResCap>,
{
vftable: usize,
pub allocator: &'static DLAllocator,
pub owning_repository: Option<NonNull<FD4ResRep>>,
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,
}
}
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum FD4FileCapState {
Initial = 0x0,
Queued = 0x1,
Processing = 0x2,
Unknown = 0x3,
Ready = 0x4,
}
bitfield! {
pub struct FD4FileCapUnk89Properties(u8);
impl Debug;
pub file_load_queue_index, set_file_load_queue_index: 4, 2;
}
bitfield! {
pub struct FD4FileCapUnk8AProperties(u16);
impl Debug;
pub use_secondary_repository, set_use_secondary_repository: 1;
u16;
pub mutex_index, set_mutex_index: 15, 3;
}
#[repr(C)]
#[derive(Superclass, Subclass)]
pub struct FD4FileCap {
pub res_cap: FD4ResCap,
load_process: usize,
load_task: usize,
pub load_state: FD4FileCapState,
unk89: FD4FileCapUnk89Properties,
unk8a: FD4FileCapUnk8AProperties,
unk8c: u32,
}