use crate::ffi::{NotThreadSafe, borrow_cstr, copy_cstr, vcall};
use std::ffi::{CStr, CString, c_int};
use std::marker::PhantomData;
use std::ptr::NonNull;
const INVALID_STRING_INDEX: c_int = u16::MAX as c_int;
interface! {
#[doc(alias = "INetworkStringTableContainer")]
pub struct NetworkStringTables(sys::INetworkStringTableContainer) = Engine c"VEngineServerStringTable001";
}
#[doc(alias = "INetworkStringTable")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct NetworkStringTable<'s> {
raw: NonNull<sys::INetworkStringTable>,
_scope: PhantomData<&'s ()>,
_not_thread_safe: NotThreadSafe,
}
impl<'s> NetworkStringTable<'s> {
fn new(raw: *mut sys::INetworkStringTable) -> Option<Self> {
Some(Self {
raw: NonNull::new(raw)?,
_scope: PhantomData,
_not_thread_safe: PhantomData,
})
}
pub const fn as_ptr(self) -> *mut sys::INetworkStringTable {
self.raw.as_ptr()
}
#[doc(alias = "FindStringIndex")]
pub fn find(self, string: &CStr) -> Option<usize> {
let index = unsafe {
vcall!(self.as_ptr() => INetworkStringTable_FindStringIndex(string.as_ptr()))
};
(index != INVALID_STRING_INDEX)
.then(|| usize::try_from(index).ok())
.flatten()
}
pub fn is_empty(self) -> bool {
self.len() == 0
}
#[doc(alias = "GetNumStrings")]
pub fn len(self) -> usize {
usize::try_from(unsafe { vcall!(self.as_ptr() => INetworkStringTable_GetNumStrings()) })
.unwrap_or(0)
}
#[doc(alias = "GetTableName")]
pub fn name(self) -> &'s CStr {
unsafe { borrow_cstr(vcall!(self.as_ptr() => INetworkStringTable_GetTableName())) }
.unwrap_or_default()
}
#[doc(alias = "GetString")]
pub fn string(self, index: usize) -> Option<CString> {
let index = c_int::try_from(index)
.ok()
.filter(|&index| (index as usize) < self.len())?;
unsafe { copy_cstr(vcall!(self.as_ptr() => INetworkStringTable_GetString(index))) }
}
}
impl<'s> NetworkStringTables<'s> {
fn count(self) -> c_int {
unsafe { vcall!(self.as_ptr() => INetworkStringTableContainer_GetNumTables()) }
}
#[doc(alias = "FindTable")]
pub fn find(self, name: &CStr) -> Option<NetworkStringTable<'s>> {
NetworkStringTable::new(unsafe {
vcall!(self.as_ptr() => INetworkStringTableContainer_FindTable(name.as_ptr()))
})
}
#[doc(alias = "GetTable")]
pub fn get(self, id: usize) -> Option<NetworkStringTable<'s>> {
let id = c_int::try_from(id).ok().filter(|&id| id < self.count())?;
NetworkStringTable::new(unsafe {
vcall!(self.as_ptr() => INetworkStringTableContainer_GetTable(id))
})
}
pub fn is_empty(self) -> bool {
self.len() == 0
}
#[doc(alias = "GetNumTables")]
pub fn len(self) -> usize {
usize::try_from(self.count()).unwrap_or(0)
}
}