Skip to content

Commit

Permalink
fix binary slice lifetimes (davidcole1340#181)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidcole1340 authored Nov 19, 2022
1 parent 4ea01f8 commit 8d2ad7d
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 36 deletions.
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

0 comments on commit 8d2ad7d

Please sign in to comment.