Skip to content

Commit 08bfe39

Browse files
committed
feat(array): BTreeMap/HashMap conversion
1 parent 25f508f commit 08bfe39

File tree

3 files changed

+89
-9
lines changed

3 files changed

+89
-9
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use std::{collections::BTreeMap, convert::TryFrom};
2+
3+
use super::super::ZendHashTable;
4+
use crate::types::ArrayKey;
5+
use crate::{
6+
boxed::ZBox,
7+
convert::{FromZval, IntoZval},
8+
error::{Error, Result},
9+
flags::DataType,
10+
types::Zval,
11+
};
12+
13+
impl<'a, K, V> TryFrom<&'a ZendHashTable> for BTreeMap<K, V>
14+
where
15+
K: TryFrom<ArrayKey<'a>, Error = Error> + Ord,
16+
V: FromZval<'a>,
17+
{
18+
type Error = Error;
19+
20+
fn try_from(value: &'a ZendHashTable) -> Result<Self> {
21+
let mut hm = Self::new();
22+
23+
for (key, val) in value {
24+
hm.insert(
25+
key.try_into()?,
26+
V::from_zval(val).ok_or_else(|| Error::ZvalConversion(val.get_type()))?,
27+
);
28+
}
29+
30+
Ok(hm)
31+
}
32+
}
33+
34+
impl<K, V> TryFrom<BTreeMap<K, V>> for ZBox<ZendHashTable>
35+
where
36+
K: AsRef<str>,
37+
V: IntoZval,
38+
{
39+
type Error = Error;
40+
41+
fn try_from(value: BTreeMap<K, V>) -> Result<Self> {
42+
let mut ht = ZendHashTable::with_capacity(
43+
value.len().try_into().map_err(|_| Error::IntegerOverflow)?,
44+
);
45+
46+
for (k, v) in value {
47+
ht.insert(k.as_ref(), v)?;
48+
}
49+
50+
Ok(ht)
51+
}
52+
}
53+
54+
impl<K, V> IntoZval for BTreeMap<K, V>
55+
where
56+
K: AsRef<str>,
57+
V: IntoZval,
58+
{
59+
const TYPE: DataType = DataType::Array;
60+
const NULLABLE: bool = false;
61+
62+
fn set_zval(self, zv: &mut Zval, _: bool) -> Result<()> {
63+
let arr = self.try_into()?;
64+
zv.set_hashtable(arr);
65+
Ok(())
66+
}
67+
}
68+
69+
impl<'a, T> FromZval<'a> for BTreeMap<String, T>
70+
where
71+
T: FromZval<'a>,
72+
{
73+
const TYPE: DataType = DataType::Array;
74+
75+
fn from_zval(zval: &'a Zval) -> Option<Self> {
76+
zval.array().and_then(|arr| arr.try_into().ok())
77+
}
78+
}

src/types/array/conversions/hash_map.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
1-
use std::{collections::HashMap, convert::TryFrom};
2-
1+
use super::super::ZendHashTable;
2+
use crate::types::ArrayKey;
33
use crate::{
44
boxed::ZBox,
55
convert::{FromZval, IntoZval},
66
error::{Error, Result},
77
flags::DataType,
88
types::Zval,
99
};
10+
use std::hash::{BuildHasher, Hash};
11+
use std::{collections::HashMap, convert::TryFrom};
1012

11-
use super::super::ZendHashTable;
12-
13-
// TODO: Generalize hasher
14-
#[allow(clippy::implicit_hasher)]
15-
impl<'a, V> TryFrom<&'a ZendHashTable> for HashMap<String, V>
13+
impl<'a, K, V, H> TryFrom<&'a ZendHashTable> for HashMap<K, V, H>
1614
where
15+
K: TryFrom<ArrayKey<'a>, Error = Error> + Eq + Hash,
1716
V: FromZval<'a>,
17+
H: BuildHasher + Default,
1818
{
1919
type Error = Error;
2020

2121
fn try_from(value: &'a ZendHashTable) -> Result<Self> {
22-
let mut hm = HashMap::with_capacity(value.len());
22+
let mut hm = Self::with_capacity_and_hasher(value.len(), H::default());
2323

2424
for (key, val) in value {
2525
hm.insert(
26-
key.to_string(),
26+
key.try_into()?,
2727
V::from_zval(val).ok_or_else(|| Error::ZvalConversion(val.get_type()))?,
2828
);
2929
}

src/types/array/conversions/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
//!
77
//! ## Supported Collections
88
//!
9+
//! - `BTreeMap<K, V>` ↔ `ZendHashTable` (via `btree_map` module)
910
//! - `HashMap<K, V>` ↔ `ZendHashTable` (via `hash_map` module)
1011
//! - `Vec<T>` and `Vec<(K, V)>` ↔ `ZendHashTable` (via `vec` module)
1112
13+
mod btree_map;
1214
mod hash_map;
1315
mod vec;

0 commit comments

Comments
 (0)