use std::{
any::Any,
fmt::Debug,
ops::{Deref, DerefMut, RangeBounds},
ptr::NonNull,
slice::{from_raw_parts, from_raw_parts_mut},
sync::Arc,
};
use allocator_api2::alloc::{handle_alloc_error, Allocator, Global, Layout};
use foyer_common::bits;
use super::PAGE;
pub trait IoB: Deref<Target = [u8]> + Send + Sync + 'static + Debug + Any {
fn as_raw_parts(&self) -> (*mut u8, usize);
fn as_any(&self) -> &dyn Any;
fn into_any(self: Box<Self>) -> Box<dyn Any>;
}
pub trait IoBuf: Deref<Target = [u8]> + IoB {
fn into_iob(self: Box<Self>) -> Box<dyn IoB>;
}
pub trait IoBufMut: DerefMut<Target = [u8]> + IoB {
fn into_iob(self: Box<Self>) -> Box<dyn IoB>;
}
#[derive(Debug)]
pub struct Raw {
ptr: *mut u8,
cap: usize,
}
unsafe impl Send for Raw {}
unsafe impl Sync for Raw {}
impl Raw {
pub fn new(capacity: usize) -> Self {
let capacity = bits::align_up(PAGE, capacity);
let layout = unsafe { Layout::from_size_align_unchecked(capacity, PAGE) };
let mut nonnull = match Global.allocate(layout) {
Ok(nonnull) => nonnull,
Err(_) => handle_alloc_error(layout),
};
let slice = unsafe { nonnull.as_mut() };
let ptr = slice.as_mut_ptr();
let cap = slice.len();
Self { ptr, cap }
}
pub fn into_raw_parts(self) -> (*mut u8, usize) {
let res = (self.ptr, self.cap);
std::mem::forget(self);
res
}
pub unsafe fn from_raw_parts(ptr: *mut u8, cap: usize) -> Self {
Self { ptr, cap }
}
}
impl Clone for Raw {
fn clone(&self) -> Self {
let mut buf = Raw::new(self.cap);
assert_eq!(buf.cap, self.cap);
buf.copy_from_slice(self);
buf
}
}
impl Drop for Raw {
fn drop(&mut self) {
let layout = unsafe { Layout::from_size_align_unchecked(self.cap, PAGE) };
unsafe { Global.deallocate(NonNull::new_unchecked(self.ptr), layout) };
}
}
impl Deref for Raw {
type Target = [u8];
fn deref(&self) -> &Self::Target {
unsafe { from_raw_parts(self.ptr, self.cap) }
}
}
impl DerefMut for Raw {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { from_raw_parts_mut(self.ptr, self.cap) }
}
}
impl AsRef<[u8]> for Raw {
fn as_ref(&self) -> &[u8] {
self
}
}
impl AsMut<[u8]> for Raw {
fn as_mut(&mut self) -> &mut [u8] {
&mut *self
}
}
impl PartialEq for Raw {
fn eq(&self, other: &Self) -> bool {
self.as_ref() == other.as_ref()
}
}
impl Eq for Raw {}
impl IoB for Raw {
fn as_raw_parts(&self) -> (*mut u8, usize) {
(self.ptr, self.cap)
}
fn as_any(&self) -> &dyn Any {
self
}
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
}
impl IoBuf for Raw {
fn into_iob(self: Box<Self>) -> Box<dyn IoB> {
self
}
}
impl IoBufMut for Raw {
fn into_iob(self: Box<Self>) -> Box<dyn IoB> {
self
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IoSlice {
raw: Arc<Raw>,
start: usize,
end: usize,
}
impl From<Raw> for IoSlice {
fn from(value: Raw) -> Self {
let len = value.len();
Self {
raw: Arc::new(value),
start: 0,
end: len,
}
}
}
impl From<IoSliceMut> for IoSlice {
fn from(value: IoSliceMut) -> Self {
let len = value.len();
Self {
raw: Arc::new(value.raw),
start: 0,
end: len,
}
}
}
impl Deref for IoSlice {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.raw[self.start..self.end]
}
}
impl AsRef<[u8]> for IoSlice {
fn as_ref(&self) -> &[u8] {
self
}
}
impl IoB for IoSlice {
fn as_raw_parts(&self) -> (*mut u8, usize) {
let ptr = unsafe { self.raw.ptr.add(self.start) };
let len = self.end - self.start;
(ptr, len)
}
fn as_any(&self) -> &dyn Any {
self
}
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
}
impl IoBuf for IoSlice {
fn into_iob(self: Box<Self>) -> Box<dyn IoB> {
self
}
}
impl IoSlice {
pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
let s = match range.start_bound() {
std::ops::Bound::Included(i) => self.start + *i,
std::ops::Bound::Excluded(_) => unreachable!(),
std::ops::Bound::Unbounded => self.start,
};
let e = match range.end_bound() {
std::ops::Bound::Included(i) => self.start + *i + 1,
std::ops::Bound::Excluded(i) => self.start + *i,
std::ops::Bound::Unbounded => self.end,
};
if s > e {
panic!("slice index starts at {s} but ends at {e}");
}
bits::assert_aligned(PAGE, s);
bits::assert_aligned(PAGE, e);
Self {
raw: self.raw.clone(),
start: s,
end: e,
}
}
pub fn try_into_io_slice_mut(self) -> Option<IoSliceMut> {
let raw = Arc::into_inner(self.raw)?;
Some(IoSliceMut { raw })
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IoSliceMut {
raw: Raw,
}
impl IoSliceMut {
pub fn new(capacity: usize) -> Self {
let raw = Raw::new(capacity);
Self { raw }
}
pub fn len(&self) -> usize {
self.raw.cap
}
}
impl Deref for IoSliceMut {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.raw
}
}
impl DerefMut for IoSliceMut {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.raw
}
}
impl AsRef<[u8]> for IoSliceMut {
fn as_ref(&self) -> &[u8] {
self
}
}
impl AsMut<[u8]> for IoSliceMut {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.raw
}
}
impl IoB for IoSliceMut {
fn as_raw_parts(&self) -> (*mut u8, usize) {
(self.raw.ptr, self.raw.cap)
}
fn as_any(&self) -> &dyn Any {
self
}
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
}
impl IoBuf for IoSliceMut {
fn into_iob(self: Box<Self>) -> Box<dyn IoB> {
self
}
}
impl IoBufMut for IoSliceMut {
fn into_iob(self: Box<Self>) -> Box<dyn IoB> {
self
}
}
impl IoSliceMut {
pub fn into_io_slice(self) -> IoSlice {
let start = 0;
let end = self.raw.cap;
let raw = Arc::new(self.raw);
IoSlice { raw, start, end }
}
}
impl dyn IoB {
pub fn try_into_io_slice(self: Box<Self>) -> Option<Box<IoSlice>> {
let any: Box<dyn Any> = self.into_any();
any.downcast::<IoSlice>().ok()
}
pub fn try_into_io_slice_mut(self: Box<Self>) -> Option<Box<IoSliceMut>> {
let any: Box<dyn Any> = self.into_any();
any.downcast::<IoSliceMut>().ok()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dyn() {
let raw = Raw::new(4096);
let _: Box<dyn IoBuf> = Box::new(raw.clone());
let _: Box<dyn IoBufMut> = Box::new(raw.clone());
}
}