Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 7 additions & 23 deletions src/binary_slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,11 @@

use crate::ffi::zend_string;

use std::{convert::TryFrom, ops::Deref, slice::from_raw_parts};
use std::{ops::Deref, slice::from_raw_parts};

use crate::{
convert::FromZval,
error::{Error, Result},
flags::DataType,
types::Zval,
};
use crate::{convert::FromZval, flags::DataType, types::Zval};

/// Acts as a wrapper around [`&[T]`] where `T` implements [`PackSlice`].
/// Acts as a wrapper around `&[T]` where `T` implements [`PackSlice`].
/// Primarily used for passing read-only binary data into Rust functions.
#[derive(Debug)]
pub struct BinarySlice<'a, T>(&'a [T])
Expand Down Expand Up @@ -47,28 +42,17 @@ where
}
}

impl<T> FromZval<'_> for BinarySlice<'_, T>
impl<'a, T> FromZval<'a> for BinarySlice<'a, T>
where
T: PackSlice,
{
const TYPE: DataType = DataType::String;

fn from_zval(zval: &Zval) -> Option<Self> {
fn from_zval(zval: &'a Zval) -> Option<Self> {
zval.binary_slice().map(BinarySlice)
}
}

impl<T> TryFrom<Zval> for BinarySlice<'_, T>
where
T: PackSlice,
{
type Error = Error;

fn try_from(value: Zval) -> Result<Self> {
Self::from_zval(&value).ok_or_else(|| Error::ZvalConversion(value.get_type()))
}
}

impl<'a, T> From<BinarySlice<'a, T>> for &'a [T]
where
T: PackSlice,
Expand Down Expand Up @@ -117,7 +101,7 @@ pub unsafe trait PackSlice: Clone {
/// * `s` - The Zend string containing the binary data.
///
/// [`pack`]: https://www.php.net/manual/en/function.pack.php
fn unpack_into<'a>(s: &zend_string) -> &'a [Self];
fn unpack_into(s: &zend_string) -> &[Self];
}

/// Implements the [`PackSlice`] trait for a given type.
Expand All @@ -128,7 +112,7 @@ macro_rules! pack_slice_impl {

($t: ty, $d: expr) => {
unsafe impl PackSlice for $t {
fn unpack_into<'a>(s: &zend_string) -> &'a [Self] {
fn unpack_into(s: &zend_string) -> &[Self] {
let bytes = ($d / 8) as usize;
let len = (s.len as usize) / bytes;
let ptr = s.val.as_ptr() as *const $t;
Expand Down
31 changes: 18 additions & 13 deletions src/types/zval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,21 +130,26 @@ impl Zval {
///
/// [`pack`]: https://www.php.net/manual/en/function.pack.php
pub fn binary<T: Pack>(&self) -> Option<Vec<T>> {
if self.is_string() {
// SAFETY: Type is string therefore we are able to take a reference.
Some(T::unpack_into(unsafe { self.value.str_.as_ref() }?))
} else {
None
}
self.zend_str().map(T::unpack_into)
}

pub fn binary_slice<'a, T: PackSlice>(&self) -> Option<&'a [T]> {
if self.is_string() {
// SAFETY: Type is string therefore we are able to take a reference.
Some(T::unpack_into(unsafe { self.value.str_.as_ref() }?))
} else {
None
}
/// Returns the value of the zval if it is a string and can be unpacked into
/// a slice of a given type. Similar to the [`unpack`](https://www.php.net/manual/en/function.unpack.php)
/// in PHP, except you can only unpack one type.
///
/// This function is similar to [`Zval::binary`] except that a slice is
/// returned instead of a vector, meaning the contents of the string is
/// not copied.
///
/// # Safety
///
/// There is no way to tell if the data stored in the string is actually of
/// the given type. The results of this function can also differ from
/// platform-to-platform due to the different representation of some
/// types on different platforms. Consult the [`pack`] function
/// documentation for more details.
pub fn binary_slice<T: PackSlice>(&self) -> Option<&[T]> {
self.zend_str().map(T::unpack_into)
}

/// Returns the value of the zval if it is a resource.
Expand Down