Skip to content

Commit c69c5a0

Browse files
Merge #880
880: Implemented From/To Variant for HashMap r=Bromeon a=RedstoneMedia Since the `FromVariant` and `ToVariant` traits are already implemented for `Vec<T>` it only makes sense to also implement it for the common `HashMap<K,V>`. \ This addition is useful, because it allows easier use of Dictionaries from Godot in rust. Co-authored-by: RedstoneMedia <34373974+RedstoneMedia@users.noreply.github.com>
2 parents 13417d9 + b005fc8 commit c69c5a0

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

gdnative-core/src/core_types/variant.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::*;
22
use std::borrow::Cow;
3+
use std::collections::HashMap;
34
use std::default::Default;
45
use std::fmt;
6+
use std::hash::Hash;
57
use std::mem::{forget, transmute};
68
use std::ptr;
79

@@ -1602,6 +1604,33 @@ impl<T: FromVariant> FromVariant for Vec<T> {
16021604
}
16031605
}
16041606

1607+
impl<K: ToVariant + Hash + ToVariantEq, V: ToVariant> ToVariant for HashMap<K, V> {
1608+
#[inline]
1609+
fn to_variant(&self) -> Variant {
1610+
let dict = Dictionary::new();
1611+
for (key, value) in self {
1612+
dict.insert(key, value);
1613+
}
1614+
dict.owned_to_variant()
1615+
}
1616+
}
1617+
1618+
impl<K: FromVariant + Hash + Eq, V: FromVariant> FromVariant for HashMap<K, V> {
1619+
#[inline]
1620+
fn from_variant(variant: &Variant) -> Result<Self, FromVariantError> {
1621+
let dictionary = Dictionary::from_variant(variant)?;
1622+
let len: usize = dictionary
1623+
.len()
1624+
.try_into()
1625+
.expect("Dictionary length should fit in usize");
1626+
let mut hash_map = HashMap::with_capacity(len);
1627+
for (key, value) in dictionary.iter() {
1628+
hash_map.insert(K::from_variant(&key)?, V::from_variant(&value)?);
1629+
}
1630+
Ok(hash_map)
1631+
}
1632+
}
1633+
16051634
macro_rules! tuple_length {
16061635
() => { 0usize };
16071636
($_x:ident, $($xs:ident,)*) => {
@@ -1774,6 +1803,38 @@ godot_test!(
17741803
assert_eq!(Some(&f64::to_variant(&54.0)), vec_maybe[2].as_ref().err());
17751804
}
17761805

1806+
test_variant_hash_map {
1807+
let original_hash_map = HashMap::from([
1808+
("Foo".to_string(), 4u32),
1809+
("Bar".to_string(), 2u32)
1810+
]);
1811+
let variant = original_hash_map.to_variant();
1812+
let check_hash_map = variant.try_to::<HashMap<String, u32>>().expect("should be hash map");
1813+
assert_eq!(original_hash_map, check_hash_map);
1814+
// Check conversion of heterogeneous dictionary key types
1815+
let non_homogenous_key_dictonary = Dictionary::new();
1816+
non_homogenous_key_dictonary.insert("Foo".to_string(), 4u32);
1817+
non_homogenous_key_dictonary.insert(7, 2u32);
1818+
assert_eq!(
1819+
non_homogenous_key_dictonary.owned_to_variant().try_to::<HashMap<String, u32>>(),
1820+
Err(FromVariantError::InvalidVariantType {
1821+
variant_type: VariantType::I64,
1822+
expected: VariantType::GodotString
1823+
}),
1824+
);
1825+
// Check conversion of heterogeneous dictionary value types
1826+
let non_homogenous_value_dictonary = Dictionary::new();
1827+
non_homogenous_value_dictonary.insert("Foo".to_string(), 4u32);
1828+
non_homogenous_value_dictonary.insert("Bar".to_string(), "Unexpected".to_string());
1829+
assert_eq!(
1830+
non_homogenous_value_dictonary.owned_to_variant().try_to::<HashMap<String, u32>>(),
1831+
Err(FromVariantError::InvalidVariantType {
1832+
variant_type: VariantType::GodotString,
1833+
expected: VariantType::I64
1834+
}),
1835+
);
1836+
}
1837+
17771838
test_variant_tuple {
17781839
let variant = (42i64, 54i64).to_variant();
17791840
let arr = variant.try_to::<VariantArray>().expect("should be array");

test/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub extern "C" fn run_tests(
4040

4141
status &= gdnative::core_types::test_variant_option();
4242
status &= gdnative::core_types::test_variant_result();
43+
status &= gdnative::core_types::test_variant_hash_map();
4344
status &= gdnative::core_types::test_to_variant_iter();
4445
status &= gdnative::core_types::test_variant_tuple();
4546
status &= gdnative::core_types::test_variant_dispatch();

0 commit comments

Comments
 (0)