diff --git a/src/types/array.rs b/src/types/array.rs index 602eda7d4..db89e884b 100644 --- a/src/types/array.rs +++ b/src/types/array.rs @@ -1,16 +1,6 @@ //! Represents an array in PHP. As all arrays in PHP are associative arrays, //! they are represented by hash tables. -use std::{ - collections::HashMap, - convert::{TryFrom, TryInto}, - ffi::CString, - fmt::{Debug, Display}, - iter::FromIterator, - ptr, - str::FromStr, -}; - use crate::{ boxed::{ZBox, ZBoxable}, convert::{FromZval, IntoZval}, @@ -27,6 +17,15 @@ use crate::{ flags::DataType, types::Zval, }; +use std::{ + collections::{BTreeMap, HashMap}, + convert::{TryFrom, TryInto}, + ffi::CString, + fmt::{Debug, Display}, + iter::FromIterator, + ptr, + str::FromStr, +}; /// A PHP hashtable. /// @@ -1288,6 +1287,76 @@ where } } +/////////////////////////////////////////// +// BTreeMap +/////////////////////////////////////////// + +impl<'a, V> TryFrom<&'a ZendHashTable> for BTreeMap +where + V: FromZval<'a>, +{ + type Error = Error; + + fn try_from(value: &'a ZendHashTable) -> Result { + let mut hm = BTreeMap::new(); + + for (key, val) in value { + hm.insert( + key.to_string(), + V::from_zval(val).ok_or_else(|| Error::ZvalConversion(val.get_type()))?, + ); + } + + Ok(hm) + } +} + +impl TryFrom> for ZBox +where + K: AsRef, + V: IntoZval, +{ + type Error = Error; + + fn try_from(value: BTreeMap) -> Result { + let mut ht = ZendHashTable::with_capacity( + value.len().try_into().map_err(|_| Error::IntegerOverflow)?, + ); + + for (k, v) in value { + ht.insert(k.as_ref(), v)?; + } + + Ok(ht) + } +} + +impl IntoZval for BTreeMap +where + K: AsRef, + V: IntoZval, +{ + const TYPE: DataType = DataType::Array; + const NULLABLE: bool = false; + + fn set_zval(self, zv: &mut Zval, _: bool) -> Result<()> { + let arr = self.try_into()?; + zv.set_hashtable(arr); + Ok(()) + } +} + +impl<'a, T> FromZval<'a> for BTreeMap +where + T: FromZval<'a>, +{ + const TYPE: DataType = DataType::Array; + + fn from_zval(zval: &'a Zval) -> Option { + zval.array().and_then(|arr| arr.try_into().ok()) + } +} + /////////////////////////////////////////// // Vec ///////////////////////////////////////////