use crate::ffi::zend_string;
use std::{ops::Deref, slice::from_raw_parts};
use crate::{convert::FromZval, flags::DataType, types::Zval};
#[derive(Debug)]
pub struct BinarySlice<'a, T>(&'a [T])
where
T: PackSlice;
impl<'a, T> BinarySlice<'a, T>
where
T: PackSlice,
{
pub fn new(data: &'a [T]) -> Self {
Self(data)
}
}
impl<'a, T> Deref for BinarySlice<'a, T>
where
T: PackSlice,
{
type Target = &'a [T];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a, T> FromZval<'a> for BinarySlice<'a, T>
where
T: PackSlice,
{
const TYPE: DataType = DataType::String;
fn from_zval(zval: &'a Zval) -> Option<Self> {
zval.binary_slice().map(BinarySlice)
}
}
impl<'a, T> From<BinarySlice<'a, T>> for &'a [T]
where
T: PackSlice,
{
fn from(value: BinarySlice<'a, T>) -> Self {
value.0
}
}
impl<'a, T> From<&'a [T]> for BinarySlice<'a, T>
where
T: PackSlice,
{
fn from(value: &'a [T]) -> Self {
Self::new(value)
}
}
pub unsafe trait PackSlice: Clone {
fn unpack_into(s: &zend_string) -> &[Self];
}
macro_rules! pack_slice_impl {
($t: ty) => {
pack_slice_impl!($t, <$t>::BITS);
};
($t: ty, $d: expr) => {
unsafe impl PackSlice for $t {
fn unpack_into(s: &zend_string) -> &[Self] {
let bytes = ($d / 8) as usize;
let len = (s.len as usize) / bytes;
#[allow(clippy::cast_ptr_alignment)]
let ptr = s.val.as_ptr().cast::<$t>();
unsafe { from_raw_parts(ptr, len) }
}
}
};
}
pack_slice_impl!(u8);
pack_slice_impl!(i8);
pack_slice_impl!(u16);
pack_slice_impl!(i16);
pack_slice_impl!(u32);
pack_slice_impl!(i32);
pack_slice_impl!(u64);
pack_slice_impl!(i64);
pack_slice_impl!(isize);
pack_slice_impl!(usize);
pack_slice_impl!(f32, 32);
pack_slice_impl!(f64, 64);