use std::convert::AsMut;
use std::marker::PhantomData;
use libc::{c_int, c_void, posix_madvise};
use crate::wrappers::advisor::Advise::DontNeed;
#[repr(transparent)]
pub struct Adviser<C: AsMut<[T]>, T> {
pub buf: C,
item_type: PhantomData<T>,
}
impl<C: AsMut<[T]>, T> Adviser<C, T> {
pub fn new(buf: C) -> Self {
Self {
buf,
item_type: PhantomData,
}
}
pub fn syscall_advise(&mut self, advise: Advise) -> Result<(), AdviseError> {
let buf = self.buf.as_mut();
assert!(size_of_val(buf) > 0, "Zero size buffer");
let ptr = buf.as_mut_ptr() as *mut c_void;
let len = size_of_val(buf);
let result = unsafe {
posix_madvise(ptr, len, advise as c_int)
};
match result {
0 => Ok(()),
result => Err(AdviseError::from(result)),
}
}
}
impl<C: AsMut<[T]>, T> Drop for Adviser<C, T> {
fn drop(&mut self) {
self.syscall_advise(DontNeed)
.expect("Cant give advise while dropping")
}
}
#[repr(i32)]
pub enum Advise {
WillNeed = 3,
DontNeed = 4,
}
#[derive(Debug)]
pub enum AdviseError {
EFAULT,
EINVAL,
ENOMEM,
ENOSYS,
EUNIM(c_int),
}
impl From<c_int> for AdviseError {
fn from(err: c_int) -> Self {
match err {
12 => AdviseError::ENOMEM,
14 => AdviseError::EFAULT,
22 => AdviseError::EINVAL,
38 => AdviseError::ENOSYS,
_ => AdviseError::EUNIM(err),
}
}
}