Skip to content

Commit 68d9d9c

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

File tree

4 files changed

+100
-21
lines changed

4 files changed

+100
-21
lines changed

src/types/array/array_key.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,19 @@ impl From<String> for ArrayKey<'_> {
2424
impl TryFrom<ArrayKey<'_>> for String {
2525
type Error = Error;
2626

27-
fn try_from(value: ArrayKey<'_>) -> std::result::Result<Self, Self::Error> {
27+
fn try_from(value: ArrayKey<'_>) -> Result<Self, Self::Error> {
2828
match value {
2929
ArrayKey::String(s) => Ok(s),
3030
ArrayKey::Str(s) => Ok(s.to_string()),
31-
ArrayKey::Long(_) => Err(Error::InvalidProperty),
31+
ArrayKey::Long(l) => Ok(l.to_string()),
3232
}
3333
}
3434
}
3535

3636
impl TryFrom<ArrayKey<'_>> for i64 {
3737
type Error = Error;
3838

39-
fn try_from(value: ArrayKey<'_>) -> std::result::Result<Self, Self::Error> {
39+
fn try_from(value: ArrayKey<'_>) -> Result<Self, Self::Error> {
4040
match value {
4141
ArrayKey::Long(i) => Ok(i),
4242
ArrayKey::String(s) => s.parse::<i64>().map_err(|_| Error::InvalidProperty),
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: 17 additions & 18 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
}
@@ -32,14 +32,15 @@ where
3232
}
3333
}
3434

35-
impl<K, V> TryFrom<HashMap<K, V>> for ZBox<ZendHashTable>
35+
impl<K, V, H> TryFrom<HashMap<K, V, H>> for ZBox<ZendHashTable>
3636
where
3737
K: AsRef<str>,
3838
V: IntoZval,
39+
H: BuildHasher,
3940
{
4041
type Error = Error;
4142

42-
fn try_from(value: HashMap<K, V>) -> Result<Self> {
43+
fn try_from(value: HashMap<K, V, H>) -> Result<Self> {
4344
let mut ht = ZendHashTable::with_capacity(
4445
value.len().try_into().map_err(|_| Error::IntegerOverflow)?,
4546
);
@@ -52,12 +53,11 @@ where
5253
}
5354
}
5455

55-
// TODO: Generalize hasher
56-
#[allow(clippy::implicit_hasher)]
57-
impl<K, V> IntoZval for HashMap<K, V>
56+
impl<K, V, H> IntoZval for HashMap<K, V, H>
5857
where
5958
K: AsRef<str>,
6059
V: IntoZval,
60+
H: BuildHasher,
6161
{
6262
const TYPE: DataType = DataType::Array;
6363
const NULLABLE: bool = false;
@@ -69,11 +69,10 @@ where
6969
}
7070
}
7171

72-
// TODO: Generalize hasher
73-
#[allow(clippy::implicit_hasher)]
74-
impl<'a, T> FromZval<'a> for HashMap<String, T>
72+
impl<'a, V, H> FromZval<'a> for HashMap<String, V, H>
7573
where
76-
T: FromZval<'a>,
74+
V: FromZval<'a>,
75+
H: BuildHasher + Default,
7776
{
7877
const TYPE: DataType = DataType::Array;
7978

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)