use alloc::vec::Vec;
use core::{
mem,
mem::{MaybeUninit, size_of},
};
use crate::{ByteRepr, Result};
use alloc::boxed::Box;
use super::Path;
pub trait ElfReader {
fn path(&self) -> &Path;
fn read(&mut self, buf: &mut [u8], offset: usize) -> Result<()>;
fn as_fd(&self) -> Option<isize>;
fn file_name(&self) -> &str {
self.path().file_name()
}
}
pub(crate) trait ElfReaderExt: ElfReader {
#[inline]
fn read_to_vec<T: ByteRepr>(&mut self, offset: usize, count: usize) -> Result<Vec<T>> {
let byte_len = count
.checked_mul(size_of::<T>())
.expect("ElfReaderExt::read_to_vec length overflow");
let mut values = Vec::<MaybeUninit<T>>::with_capacity(count);
unsafe {
values.set_len(count);
}
let bytes =
unsafe { core::slice::from_raw_parts_mut(values.as_mut_ptr().cast::<u8>(), byte_len) };
self.read(bytes, offset)?;
Ok(unsafe { assume_init_vec(values) })
}
#[inline]
fn read_slice<T: ByteRepr>(&mut self, buf: &mut [T], offset: usize) -> Result<()> {
let byte_len = buf
.len()
.checked_mul(size_of::<T>())
.expect("ElfReaderExt::read_slice length overflow");
let bytes =
unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr().cast::<u8>(), byte_len) };
self.read(bytes, offset)
}
}
impl<T: ElfReader + ?Sized> ElfReaderExt for T {}
#[inline]
unsafe fn assume_init_vec<T>(mut values: Vec<MaybeUninit<T>>) -> Vec<T> {
let len = values.len();
let cap = values.capacity();
let ptr = values.as_mut_ptr().cast::<T>();
mem::forget(values);
unsafe { Vec::from_raw_parts(ptr, len, cap) }
}
pub trait IntoElfReader<'a> {
type Reader: ElfReader + 'a;
fn into_reader(self) -> Result<Self::Reader>;
}
impl<R: ElfReader + ?Sized> ElfReader for Box<R> {
#[inline]
fn path(&self) -> &Path {
(**self).path()
}
#[inline]
fn read(&mut self, buf: &mut [u8], offset: usize) -> Result<()> {
(**self).read(buf, offset)
}
#[inline]
fn as_fd(&self) -> Option<isize> {
(**self).as_fd()
}
}
impl<'a, R> IntoElfReader<'a> for Box<R>
where
R: ElfReader + 'a + ?Sized,
{
type Reader = Box<R>;
#[inline]
fn into_reader(self) -> Result<Self::Reader> {
Ok(self)
}
}