use crate::sys::*;
use log;
use std::{
ffi::c_void,
fmt::Debug,
io::{Read, Seek, SeekFrom, Write},
marker::PhantomData,
};
pub trait RWSeekable: Read + Write + Seek {
fn as_mut_dyn(&mut self) -> &mut dyn RWSeekable;
}
impl<T: Read + Write + Seek> RWSeekable for T {
fn as_mut_dyn(&mut self) -> &mut dyn RWSeekable {
self
}
}
impl<'a> Debug for dyn RWSeekable + 'a {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "RWSeekable({:p})", self)
}
}
#[allow(unused)]
pub struct RustKtxStream<'a, T: RWSeekable + ?Sized + 'a> {
inner_ptr: Option<*mut T>,
ktx_stream: Option<Box<ktxStream>>,
ktx_phantom: PhantomData<&'a ktxStream>,
}
impl<'a, T: RWSeekable + ?Sized + 'a> RustKtxStream<'a, T> {
pub fn new(inner: Box<T>) -> Result<Self, ktx_error_code_e> {
let inner_ptr = Box::into_raw(inner);
let inner_rwseekable_ptr = unsafe { (*inner_ptr).as_mut_dyn() } as *mut dyn RWSeekable;
let (t_addr, vtable_addr): (*mut c_void, *mut c_void) =
unsafe { std::mem::transmute(inner_rwseekable_ptr) };
let mut ktx_stream = Box::new(ktxStream {
read: Some(ktxRustStream_read),
skip: Some(ktxRustStream_skip),
write: Some(ktxRustStream_write),
getpos: Some(ktxRustStream_getpos),
setpos: Some(ktxRustStream_setpos),
getsize: Some(ktxRustStream_getsize),
destruct: Some(ktxRustStream_destruct),
closeOnDestruct: false,
type_: streamType_eStreamTypeCustom,
data: unsafe { std::mem::zeroed() },
readpos: 0,
});
let custom_ptr = unsafe { ktx_stream.data.custom_ptr.as_mut() };
custom_ptr.address = t_addr;
custom_ptr.allocatorAddress = vtable_addr;
custom_ptr.size = 0;
Ok(Self {
inner_ptr: Some(inner_ptr),
ktx_stream: Some(ktx_stream),
ktx_phantom: PhantomData,
})
}
pub fn ktx_stream(&self) -> *mut ktxStream {
match &self.ktx_stream {
Some(boxed) => unsafe { std::mem::transmute(boxed.as_ref()) },
None => std::ptr::null_mut(),
}
}
pub fn inner(&self) -> &T {
unsafe { &*self.inner_ptr.expect("Self was destroyed") as &T }
}
pub fn inner_mut(&mut self) -> &mut T {
unsafe { &mut *self.inner_ptr.expect("Self was destroyed") as &mut T }
}
fn rebox_inner_ptr(&mut self) -> Box<T> {
let moved_t = std::mem::replace(&mut self.inner_ptr, unsafe { std::mem::zeroed() });
unsafe {
Box::from_raw(moved_t.expect("Self was already destroyed"))
}
}
pub fn into_inner(mut self) -> Box<T> {
self.rebox_inner_ptr()
}
}
impl<'a, T: RWSeekable + ?Sized + 'a> Drop for RustKtxStream<'a, T> {
fn drop(&mut self) {
let mut moved_self = std::mem::replace(
self,
RustKtxStream {
inner_ptr: None,
ktx_stream: None,
ktx_phantom: PhantomData,
},
);
if let Some(mut ktx_stream) = std::mem::replace(&mut moved_self.ktx_stream, None) {
let mut custom_ptr = unsafe { ktx_stream.data.custom_ptr.as_mut() };
custom_ptr.address = std::ptr::null_mut();
custom_ptr.allocatorAddress = std::ptr::null_mut();
custom_ptr.size = 0xBADDA7A;
std::mem::drop(ktx_stream);
}
if let Some(_) = moved_self.inner_ptr {
std::mem::drop(moved_self.rebox_inner_ptr())
}
std::mem::forget(moved_self);
}
}
fn format_option_ptr<T>(f: &mut std::fmt::Formatter<'_>, option: &Option<T>) -> std::fmt::Result {
match option {
Some(t) => write!(f, "{:p}", t),
None => write!(f, "<none>"),
}
}
impl<'a, T: RWSeekable + ?Sized + 'a> Debug for RustKtxStream<'a, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "RustKtxStream(inner=")?;
format_option_ptr(f, &self.inner_ptr)?;
write!(f, ", ktxStream=")?;
format_option_ptr(f, &self.ktx_stream)?;
write!(f, ")")
}
}
unsafe fn inner_rwseekable<'a>(str: *mut ktxStream) -> &'a mut dyn RWSeekable {
let fat_t_ptr = {
let custom_ptr = (*str).data.custom_ptr.as_ref();
(custom_ptr.address, custom_ptr.allocatorAddress)
};
let inner_ref: *mut dyn RWSeekable = std::mem::transmute(fat_t_ptr);
&mut *inner_ref
}
fn stream_len(seek: &mut dyn RWSeekable) -> std::io::Result<u64> {
let old_pos = seek.stream_position()?;
let size = seek.seek(SeekFrom::End(0))?;
seek.seek(SeekFrom::Start(old_pos))?;
Ok(size)
}
#[no_mangle]
unsafe extern "C" fn ktxRustStream_read(
str: *mut ktxStream,
dst: *mut c_void,
count: ktx_size_t,
) -> ktx_error_code_e {
let inner = inner_rwseekable(str);
let buf = std::slice::from_raw_parts_mut(dst as *mut u8, count as usize);
match inner.read_exact(buf) {
Ok(_) => ktx_error_code_e_KTX_SUCCESS,
Err(err) => {
log::error!("ktxRustStream_read: {}", err);
ktx_error_code_e_KTX_FILE_READ_ERROR
}
}
}
#[no_mangle]
unsafe extern "C" fn ktxRustStream_skip(
str: *mut ktxStream,
count: ktx_size_t,
) -> ktx_error_code_e {
let inner = inner_rwseekable(str);
match inner.seek(SeekFrom::Current(count as i64)) {
Ok(_) => ktx_error_code_e_KTX_SUCCESS,
Err(err) => {
log::error!("ktxRustStream_skip: {}", err);
ktx_error_code_e_KTX_FILE_SEEK_ERROR
}
}
}
#[no_mangle]
unsafe extern "C" fn ktxRustStream_write(
str: *mut ktxStream,
src: *const c_void,
size: ktx_size_t,
count: ktx_size_t,
) -> ktx_error_code_e {
let inner = inner_rwseekable(str);
let len = (size * count) as usize;
let buf = std::slice::from_raw_parts(src as *const u8, len);
match inner.write_all(buf) {
Ok(_) => ktx_error_code_e_KTX_SUCCESS,
Err(err) => {
log::error!("ktxRustStream_write: {}", err);
ktx_error_code_e_KTX_FILE_WRITE_ERROR
}
}
}
#[no_mangle]
unsafe extern "C" fn ktxRustStream_getpos(
str: *mut ktxStream,
pos: *mut ktx_off_t,
) -> ktx_error_code_e {
let inner = inner_rwseekable(str);
match inner.stream_position() {
Ok(cur) => {
*pos = cur as ktx_off_t;
ktx_error_code_e_KTX_SUCCESS
}
Err(err) => {
log::error!("ktxRustStream_getpos: {}", err);
ktx_error_code_e_KTX_FILE_SEEK_ERROR
}
}
}
#[no_mangle]
unsafe extern "C" fn ktxRustStream_setpos(str: *mut ktxStream, off: ktx_off_t) -> ktx_error_code_e {
let inner = inner_rwseekable(str);
match inner.seek(SeekFrom::Start(off as u64)) {
Ok(_) => ktx_error_code_e_KTX_SUCCESS,
Err(err) => {
log::error!("ktxRustStream_setpos: {}", err);
ktx_error_code_e_KTX_FILE_SEEK_ERROR
}
}
}
#[no_mangle]
unsafe extern "C" fn ktxRustStream_getsize(
str: *mut ktxStream,
size: *mut ktx_size_t,
) -> ktx_error_code_e {
let inner = inner_rwseekable(str);
match stream_len(inner) {
Ok(len) => {
*size = len as ktx_size_t;
ktx_error_code_e_KTX_SUCCESS
}
Err(err) => {
log::error!("ktxRustStream_getsize: {}", err);
ktx_error_code_e_KTX_FILE_SEEK_ERROR
}
}
}
#[no_mangle]
unsafe extern "C" fn ktxRustStream_destruct(_str: *mut ktxStream) {
}