Skip to content

Commit d7f9aa4

Browse files
committed
feat(array): FromZval/IntoZval impls for BTreeMap
1 parent 1166e29 commit d7f9aa4

File tree

4 files changed

+95
-20
lines changed

4 files changed

+95
-20
lines changed

src/builders/ini.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,8 @@ impl AsRef<str> for IniBuilder {
218218
}
219219
}
220220

221-
// Ensure the C buffer is properly deinitialized when the builder goes out of scope.
221+
// Ensure the C buffer is properly deinitialized when the builder goes out of
222+
// scope.
222223
impl Drop for IniBuilder {
223224
fn drop(&mut self) {
224225
if !self.value.is_null() {

src/builders/sapi.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ impl SapiBuilder {
166166
///
167167
/// # Parameters
168168
///
169-
/// * `func` - The function to be called when PHP gets an environment variable.
169+
/// * `func` - The function to be called when PHP gets an environment
170+
/// variable.
170171
pub fn getenv_function(mut self, func: SapiGetEnvFunc) -> Self {
171172
self.module.getenv = Some(func);
172173
self
@@ -216,7 +217,8 @@ impl SapiBuilder {
216217
///
217218
/// # Parameters
218219
///
219-
/// * `func` - The function to be called when PHP registers server variables.
220+
/// * `func` - The function to be called when PHP registers server
221+
/// variables.
220222
pub fn register_server_variables_function(
221223
mut self,
222224
func: SapiRegisterServerVariablesFunc,
@@ -450,8 +452,9 @@ mod test {
450452
extern "C" fn test_getenv(_name: *const c_char, _name_length: usize) -> *mut c_char {
451453
ptr::null_mut()
452454
}
453-
// Note: C-variadic functions are unstable in Rust, so we can't test this properly
454-
// extern "C" fn test_sapi_error(_type: c_int, _error_msg: *const c_char, _args: ...) {}
455+
// Note: C-variadic functions are unstable in Rust, so we can't test this
456+
// properly extern "C" fn test_sapi_error(_type: c_int, _error_msg: *const
457+
// c_char, _args: ...) {}
455458
extern "C" fn test_send_header(_header: *mut sapi_header_struct, _server_context: *mut c_void) {
456459
}
457460
extern "C" fn test_read_post(_buffer: *mut c_char, _length: usize) -> usize {
@@ -591,9 +594,10 @@ mod test {
591594
);
592595
}
593596

594-
// Note: Cannot test sapi_error_function because C-variadic functions are unstable in Rust
595-
// The sapi_error field accepts a function with variadic arguments which cannot be
596-
// created in stable Rust. However, the builder method itself works correctly.
597+
// Note: Cannot test sapi_error_function because C-variadic functions are
598+
// unstable in Rust The sapi_error field accepts a function with variadic
599+
// arguments which cannot be created in stable Rust. However, the builder
600+
// method itself works correctly.
597601

598602
#[test]
599603
fn test_send_header_function() {

src/embed/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,9 @@ mod tests {
287287
#[test]
288288
fn test_eval_bailout() {
289289
Embed::run(|| {
290-
// TODO: For PHP 8.5, this needs to be replaced, as `E_USER_ERROR` is deprecated.
291-
// Currently, this seems to still be the best way to trigger a bailout.
290+
// TODO: For PHP 8.5, this needs to be replaced, as `E_USER_ERROR` is
291+
// deprecated. Currently, this seems to still be the best way
292+
// to trigger a bailout.
292293
let result = Embed::eval("trigger_error(\"Fatal error\", E_USER_ERROR);");
293294

294295
assert!(result.is_err());

src/types/array.rs

Lines changed: 79 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,6 @@
11
//! Represents an array in PHP. As all arrays in PHP are associative arrays,
22
//! they are represented by hash tables.
33
4-
use std::{
5-
collections::HashMap,
6-
convert::{TryFrom, TryInto},
7-
ffi::CString,
8-
fmt::{Debug, Display},
9-
iter::FromIterator,
10-
ptr,
11-
str::FromStr,
12-
};
13-
144
use crate::{
155
boxed::{ZBox, ZBoxable},
166
convert::{FromZval, IntoZval},
@@ -27,6 +17,15 @@ use crate::{
2717
flags::DataType,
2818
types::Zval,
2919
};
20+
use std::{
21+
collections::{BTreeMap, HashMap},
22+
convert::{TryFrom, TryInto},
23+
ffi::CString,
24+
fmt::{Debug, Display},
25+
iter::FromIterator,
26+
ptr,
27+
str::FromStr,
28+
};
3029

3130
/// A PHP hashtable.
3231
///
@@ -1165,6 +1164,76 @@ where
11651164
}
11661165
}
11671166

1167+
///////////////////////////////////////////
1168+
// BTreeMap
1169+
///////////////////////////////////////////
1170+
1171+
impl<'a, V> TryFrom<&'a ZendHashTable> for BTreeMap<String, V>
1172+
where
1173+
V: FromZval<'a>,
1174+
{
1175+
type Error = Error;
1176+
1177+
fn try_from(value: &'a ZendHashTable) -> Result<Self> {
1178+
let mut hm = BTreeMap::new();
1179+
1180+
for (key, val) in value {
1181+
hm.insert(
1182+
key.to_string(),
1183+
V::from_zval(val).ok_or_else(|| Error::ZvalConversion(val.get_type()))?,
1184+
);
1185+
}
1186+
1187+
Ok(hm)
1188+
}
1189+
}
1190+
1191+
impl<K, V> TryFrom<BTreeMap<K, V>> for ZBox<ZendHashTable>
1192+
where
1193+
K: AsRef<str>,
1194+
V: IntoZval,
1195+
{
1196+
type Error = Error;
1197+
1198+
fn try_from(value: BTreeMap<K, V>) -> Result<Self> {
1199+
let mut ht = ZendHashTable::with_capacity(
1200+
value.len().try_into().map_err(|_| Error::IntegerOverflow)?,
1201+
);
1202+
1203+
for (k, v) in value {
1204+
ht.insert(k.as_ref(), v)?;
1205+
}
1206+
1207+
Ok(ht)
1208+
}
1209+
}
1210+
1211+
impl<K, V> IntoZval for BTreeMap<K, V>
1212+
where
1213+
K: AsRef<str>,
1214+
V: IntoZval,
1215+
{
1216+
const TYPE: DataType = DataType::Array;
1217+
const NULLABLE: bool = false;
1218+
1219+
fn set_zval(self, zv: &mut Zval, _: bool) -> Result<()> {
1220+
let arr = self.try_into()?;
1221+
zv.set_hashtable(arr);
1222+
Ok(())
1223+
}
1224+
}
1225+
1226+
impl<'a, T> FromZval<'a> for BTreeMap<String, T>
1227+
where
1228+
T: FromZval<'a>,
1229+
{
1230+
const TYPE: DataType = DataType::Array;
1231+
1232+
fn from_zval(zval: &'a Zval) -> Option<Self> {
1233+
zval.array().and_then(|arr| arr.try_into().ok())
1234+
}
1235+
}
1236+
11681237
///////////////////////////////////////////
11691238
// Vec
11701239
///////////////////////////////////////////

0 commit comments

Comments
 (0)