• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

davidcole1340 / ext-php-rs / 14501981872

16 Apr 2025 08:30PM UTC coverage: 14.129% (+0.7%) from 13.479%
14501981872

push

github

web-flow
style(clippy): apply pedantic rules

Refs: #418

41 of 345 new or added lines in 46 files covered. (11.88%)

48 existing lines in 25 files now uncovered.

553 of 3914 relevant lines covered (14.13%)

1.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/binary.rs
1
//! Provides implementations for converting to and from Zend binary strings,
2
//! commonly returned from functions such as [`pack`] and [`unpack`].
3
//!
4
//! [`pack`]: https://www.php.net/manual/en/function.pack.php
5
//! [`unpack`]: https://www.php.net/manual/en/function.unpack.php
6

7
use crate::ffi::{ext_php_rs_zend_string_init, zend_string};
8

9
use std::{
10
    convert::TryFrom,
11
    iter::FromIterator,
12
    ops::{Deref, DerefMut},
13
};
14

15
use crate::{
16
    convert::{FromZval, IntoZval},
17
    error::{Error, Result},
18
    flags::DataType,
19
    types::Zval,
20
};
21

22
/// Acts as a wrapper around [`Vec<T>`] where `T` implements [`Pack`]. Primarily
23
/// used for passing binary data into Rust functions. Can be treated as a
24
/// [`Vec`] in most situations, or can be 'unwrapped' into a [`Vec`] through the
25
/// [`From`] implementation on [`Vec`].
26
#[derive(Debug)]
27
pub struct Binary<T: Pack>(Vec<T>);
28

29
impl<T: Pack> Binary<T> {
30
    /// Creates a new binary wrapper from a set of data which can be converted
31
    /// into a vector.
32
    ///
33
    /// # Parameters
34
    ///
35
    /// * `data` - Data to store inside the binary wrapper.
36
    pub fn new(data: impl Into<Vec<T>>) -> Self {
×
37
        Self(data.into())
×
38
    }
39
}
40

41
impl<T: Pack> Deref for Binary<T> {
42
    type Target = Vec<T>;
43

44
    fn deref(&self) -> &Self::Target {
×
45
        &self.0
×
46
    }
47
}
48

49
impl<T: Pack> DerefMut for Binary<T> {
50
    fn deref_mut(&mut self) -> &mut Self::Target {
×
51
        &mut self.0
×
52
    }
53
}
54

55
impl<T: Pack> FromZval<'_> for Binary<T> {
56
    const TYPE: DataType = DataType::String;
57

58
    fn from_zval(zval: &Zval) -> Option<Self> {
×
59
        zval.binary().map(Binary)
×
60
    }
61
}
62

63
impl<T: Pack> TryFrom<Zval> for Binary<T> {
64
    type Error = Error;
65

66
    fn try_from(value: Zval) -> Result<Self> {
×
67
        Self::from_zval(&value).ok_or_else(|| Error::ZvalConversion(value.get_type()))
×
68
    }
69
}
70

71
impl<T: Pack> IntoZval for Binary<T> {
72
    const TYPE: DataType = DataType::String;
73
    const NULLABLE: bool = false;
74

75
    fn set_zval(self, zv: &mut Zval, _: bool) -> Result<()> {
×
76
        zv.set_binary(self.0);
×
77
        Ok(())
×
78
    }
79
}
80

81
impl<T: Pack> From<Binary<T>> for Vec<T> {
82
    fn from(value: Binary<T>) -> Self {
×
83
        value.0
×
84
    }
85
}
86

87
impl<T: Pack> From<Vec<T>> for Binary<T> {
88
    fn from(value: Vec<T>) -> Self {
×
89
        Self::new(value)
×
90
    }
91
}
92

93
impl<T: Pack> FromIterator<T> for Binary<T> {
94
    fn from_iter<U: IntoIterator<Item = T>>(iter: U) -> Self {
×
95
        Self(iter.into_iter().collect::<Vec<_>>())
×
96
    }
97
}
98

99
/// Used to convert between Zend binary strings and vectors. Useful in
100
/// conjunction with the [`pack`] and [`unpack`] functions built-in to PHP.
101
///
102
/// # Safety
103
///
104
/// The types cannot be ensured between PHP and Rust, as the data is represented
105
/// as a string when crossing the language boundary. Exercise caution when using
106
/// these functions.
107
///
108
/// [`pack`]: https://www.php.net/manual/en/function.pack.php
109
/// [`unpack`]: https://www.php.net/manual/en/function.unpack.php
110
pub unsafe trait Pack: Clone {
111
    /// Packs a given vector into a Zend binary string. Can be passed to PHP and
112
    /// then unpacked using the [`unpack`] function.
113
    ///
114
    /// # Parameters
115
    ///
116
    /// * `vec` - The vector to pack into a binary string.
117
    ///
118
    /// [`unpack`]: https://www.php.net/manual/en/function.unpack.php
119
    fn pack_into(vec: Vec<Self>) -> *mut zend_string;
120

121
    /// Unpacks a given Zend binary string into a Rust vector. Can be used to
122
    /// pass data from `pack` in PHP to Rust without encoding into another
123
    /// format. Note that the data *must* be all one type, as this
124
    /// implementation only unpacks one type.
125
    ///
126
    /// # Safety
127
    ///
128
    /// There is no way to tell if the data stored in the string is actually of
129
    /// the given type. The results of this function can also differ from
130
    /// platform-to-platform due to the different representation of some
131
    /// types on different platforms. Consult the [`pack`] function
132
    /// documentation for more details.
133
    ///
134
    /// # Parameters
135
    ///
136
    /// * `s` - The Zend string containing the binary data.
137
    ///
138
    /// [`pack`]: https://www.php.net/manual/en/function.pack.php
139
    fn unpack_into(s: &zend_string) -> Vec<Self>;
140
}
141

142
/// Implements the [`Pack`] trait for a given type.
143
macro_rules! pack_impl {
144
    ($t: ty) => {
145
        pack_impl!($t, <$t>::BITS);
146
    };
147

148
    ($t: ty, $d: expr) => {
149
        unsafe impl Pack for $t {
150
            fn pack_into(vec: Vec<Self>) -> *mut zend_string {
×
151
                let len = vec.len() * ($d as usize / 8);
×
152
                let ptr = Box::into_raw(vec.into_boxed_slice());
×
153
                unsafe { ext_php_rs_zend_string_init(ptr.cast(), len as _, false) }
×
154
            }
155

156
            fn unpack_into(s: &zend_string) -> Vec<Self> {
×
NEW
157
                #[allow(clippy::cast_lossless)]
×
158
                let bytes = ($d / 8) as u64;
×
159
                let len = (s.len as u64) / bytes;
×
NEW
160
                let mut result =
×
NEW
161
                    Vec::with_capacity(len.try_into().expect("Capacity integer overflow"));
×
162
                // TODO: Check alignment
NEW
163
                #[allow(clippy::cast_ptr_alignment)]
×
NEW
164
                let ptr = s.val.as_ptr().cast::<$t>();
×
165

166
                // SAFETY: We calculate the length of memory that we can legally read based on
167
                // the side of the type, therefore we never read outside the memory we
168
                // should.
169
                for i in 0..len {
×
NEW
170
                    result.push(unsafe {
×
NEW
171
                        *ptr.offset(i.try_into().expect("Offset integer overflow"))
×
172
                    });
173
                }
174

175
                result
×
176
            }
177
        }
178
    };
179
}
180

181
pack_impl!(u8);
182
pack_impl!(i8);
183

184
pack_impl!(u16);
185
pack_impl!(i16);
186

187
pack_impl!(u32);
188
pack_impl!(i32);
189

190
pack_impl!(u64);
191
pack_impl!(i64);
192

193
pack_impl!(isize);
194
pack_impl!(usize);
195

196
pack_impl!(f32, 32);
197
pack_impl!(f64, 64);
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc