Skip to content

Commit 8815dda

Browse files
ironpeakBromeon
authored andcommitted
Implement Export for Vec, HashMap, HashSet + new example
1 parent 2560d1d commit 8815dda

File tree

12 files changed

+360
-1
lines changed

12 files changed

+360
-1
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ members = [
1717
"examples/native-plugin",
1818
"examples/rpc",
1919
"examples/array-export",
20+
"examples/collection-properties",
2021
"impl/proc-macros"
2122
]
2223

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "collection-properties"
3+
version = "0.1.0"
4+
authors = ["The godot-rust developers"]
5+
publish = false
6+
edition = "2021"
7+
rust-version = "1.56"
8+
license = "MIT"
9+
10+
[lib]
11+
crate-type = ["cdylib"]
12+
13+
[dependencies]
14+
gdnative = { path = "../../gdnative" }
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
[gd_scene load_steps=5 format=2]
2+
3+
[ext_resource path="res://collection_properties_library.gdnlib" type="GDNativeLibrary" id=1]
4+
5+
[sub_resource type="NativeScript" id=1]
6+
resource_name = "ExampleHashMapProperty"
7+
class_name = "ExampleHashMapProperty"
8+
library = ExtResource( 1 )
9+
10+
[sub_resource type="NativeScript" id=2]
11+
resource_name = "ExampleHashSetProperty"
12+
class_name = "ExampleHashSetProperty"
13+
library = ExtResource( 1 )
14+
15+
[sub_resource type="NativeScript" id=3]
16+
resource_name = "ExampleVecProperty"
17+
class_name = "ExampleVecProperty"
18+
library = ExtResource( 1 )
19+
20+
[node name="Node" type="Node"]
21+
22+
[node name="HashMap" type="Node" parent="."]
23+
script = SubResource( 1 )
24+
players = {
25+
0: "Player0",
26+
1: "Player1"
27+
}
28+
29+
[node name="HashSet" type="Node" parent="."]
30+
script = SubResource( 2 )
31+
players = [ "Player0", "Player0", "Player1" ]
32+
33+
[node name="Vec" type="Node" parent="."]
34+
script = SubResource( 3 )
35+
players = [ "Player0", "Player1" ]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[entry]
2+
3+
X11.64="res://../../target/debug/libcollection_properties.so"
4+
OSX.64="res://../../target/debug/libcollection_properties.dylib"
5+
Windows.64="res://../../target/debug/collection_properties.dll"
6+
7+
[dependencies]
8+
9+
X11.64=[ ]
10+
OSX.64=[ ]
11+
12+
[general]
13+
14+
singleton=false
15+
load_once=true
16+
symbol_prefix="godot_"
17+
reloadable=true
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[gd_resource type="Environment" load_steps=2 format=2]
2+
3+
[sub_resource type="ProceduralSky" id=1]
4+
sky_top_color = Color( 0.0470588, 0.454902, 0.976471, 1 )
5+
sky_horizon_color = Color( 0.556863, 0.823529, 0.909804, 1 )
6+
sky_curve = 0.25
7+
ground_bottom_color = Color( 0.101961, 0.145098, 0.188235, 1 )
8+
ground_horizon_color = Color( 0.482353, 0.788235, 0.952941, 1 )
9+
ground_curve = 0.01
10+
sun_energy = 16.0
11+
12+
[resource]
13+
background_mode = 2
14+
background_sky = SubResource( 1 )
3.42 KB
Loading
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
[remap]
2+
3+
importer="texture"
4+
type="StreamTexture"
5+
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
6+
metadata={
7+
"vram_texture": false
8+
}
9+
10+
[deps]
11+
12+
source_file="res://icon.png"
13+
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
14+
15+
[params]
16+
17+
compress/mode=0
18+
compress/lossy_quality=0.7
19+
compress/hdr_mode=0
20+
compress/bptc_ldr=0
21+
compress/normal_map=0
22+
flags/repeat=0
23+
flags/filter=true
24+
flags/mipmaps=false
25+
flags/anisotropic=false
26+
flags/srgb=2
27+
process/fix_alpha_border=true
28+
process/premult_alpha=false
29+
process/HDR_as_SRGB=false
30+
process/invert_color=false
31+
process/normal_map_invert_y=false
32+
stream=false
33+
size_limit=0
34+
detect_3d=true
35+
svg/scale=1.0
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
; Engine configuration file.
2+
; It's best edited using the editor UI and not directly,
3+
; since the parameters that go here are not all obvious.
4+
;
5+
; Format:
6+
; [section] ; section goes between []
7+
; param=value ; assign values to parameters
8+
9+
config_version=4
10+
11+
_global_script_classes=[ ]
12+
_global_script_class_icons={
13+
}
14+
15+
[application]
16+
17+
config/name="Godot Rust - Collection Properties"
18+
run/main_scene="res://Main.tscn"
19+
config/icon="res://icon.png"
20+
21+
[rendering]
22+
23+
environment/default_environment="res://default_env.tres"
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
use gdnative::api::*;
2+
use gdnative::prelude::*;
3+
4+
use std::collections::{HashMap, HashSet};
5+
6+
// HashMap
7+
#[derive(NativeClass, Default)]
8+
#[inherit(Node)]
9+
pub struct ExampleHashMapProperty {
10+
#[property]
11+
players: HashMap<i64, String>,
12+
}
13+
14+
impl ExampleHashMapProperty {
15+
fn new(_owner: &Node) -> Self {
16+
Self::default()
17+
}
18+
}
19+
20+
#[methods]
21+
impl ExampleHashMapProperty {
22+
#[export]
23+
fn _ready(&self, _owner: &Node) {
24+
godot_print!("HashMap:");
25+
for (id, name) in &self.players {
26+
godot_print!("Hello, {} - {}!", id, name);
27+
}
28+
}
29+
}
30+
31+
// HashSet
32+
#[derive(NativeClass, Default)]
33+
#[inherit(Node)]
34+
pub struct ExampleHashSetProperty {
35+
#[property]
36+
players: HashSet<String>,
37+
}
38+
39+
impl ExampleHashSetProperty {
40+
fn new(_owner: &Node) -> Self {
41+
Self::default()
42+
}
43+
}
44+
45+
#[methods]
46+
impl ExampleHashSetProperty {
47+
#[export]
48+
fn _ready(&self, _owner: &Node) {
49+
godot_print!("HashSet:");
50+
for name in &self.players {
51+
godot_print!("Hello, {}!", name);
52+
}
53+
}
54+
}
55+
56+
// Vec
57+
#[derive(NativeClass, Default)]
58+
#[inherit(Node)]
59+
pub struct ExampleVecProperty {
60+
#[property]
61+
players: Vec<String>,
62+
}
63+
64+
impl ExampleVecProperty {
65+
fn new(_owner: &Node) -> Self {
66+
Self::default()
67+
}
68+
}
69+
70+
#[methods]
71+
impl ExampleVecProperty {
72+
#[export]
73+
fn _ready(&self, _owner: &Node) {
74+
godot_print!("Vec:");
75+
for name in &self.players {
76+
godot_print!("Hello, {}!", name);
77+
}
78+
}
79+
}
80+
81+
// Function that registers all exposed classes to Godot
82+
fn init(handle: InitHandle) {
83+
// Register the new `HelloWorld` type we just declared.
84+
handle.add_class::<ExampleHashMapProperty>();
85+
handle.add_class::<ExampleHashSetProperty>();
86+
handle.add_class::<ExampleVecProperty>();
87+
}
88+
89+
// Macro that creates the entry-points of the dynamic library.
90+
godot_init!(init);

gdnative-core/src/core_types/variant.rs

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::*;
22
use std::borrow::Cow;
3-
use std::collections::HashMap;
3+
use std::collections::{HashMap, HashSet};
44
use std::default::Default;
55
use std::fmt;
66
use std::hash::Hash;
@@ -1632,6 +1632,38 @@ impl<K: FromVariant + Hash + Eq, V: FromVariant> FromVariant for HashMap<K, V> {
16321632
}
16331633
}
16341634

1635+
impl<T: ToVariant> ToVariant for HashSet<T> {
1636+
#[inline]
1637+
fn to_variant(&self) -> Variant {
1638+
let array = VariantArray::new();
1639+
for value in self {
1640+
array.push(value.to_variant());
1641+
}
1642+
array.owned_to_variant()
1643+
}
1644+
}
1645+
1646+
impl<T: Eq + std::hash::Hash + FromVariant> FromVariant for HashSet<T> {
1647+
#[inline]
1648+
fn from_variant(variant: &Variant) -> Result<Self, FromVariantError> {
1649+
let arr = VariantArray::from_variant(variant)?;
1650+
let len: usize = arr
1651+
.len()
1652+
.try_into()
1653+
.expect("VariantArray length should fit in usize");
1654+
let mut set = HashSet::with_capacity(len);
1655+
for idx in 0..len as i32 {
1656+
let item =
1657+
T::from_variant(&arr.get(idx)).map_err(|e| FromVariantError::InvalidItem {
1658+
index: idx as usize,
1659+
error: Box::new(e),
1660+
})?;
1661+
set.insert(item);
1662+
}
1663+
Ok(set)
1664+
}
1665+
}
1666+
16351667
macro_rules! tuple_length {
16361668
() => { 0usize };
16371669
($_x:ident, $($xs:ident,)*) => {
@@ -1836,6 +1868,63 @@ godot_test!(
18361868
);
18371869
}
18381870

1871+
test_variant_hash_set {
1872+
let original_hash_set = HashSet::from([
1873+
"Foo".to_string(),
1874+
"Bar".to_string(),
1875+
]);
1876+
let variant = original_hash_set.to_variant();
1877+
let check_hash_set = variant.try_to::<HashSet<String>>().expect("should be hash set");
1878+
assert_eq!(original_hash_set, check_hash_set);
1879+
1880+
let duplicate_variant_set = VariantArray::new();
1881+
duplicate_variant_set.push("Foo".to_string());
1882+
duplicate_variant_set.push("Bar".to_string());
1883+
duplicate_variant_set.push("Bar".to_string());
1884+
let duplicate_hash_set = variant.try_to::<HashSet<String>>().expect("should be hash set");
1885+
assert_eq!(original_hash_set, duplicate_hash_set);
1886+
1887+
// Check conversion of heterogeneous set types
1888+
let non_homogenous_set = VariantArray::new();
1889+
non_homogenous_set.push("Foo".to_string());
1890+
non_homogenous_set.push(7);
1891+
assert_eq!(
1892+
non_homogenous_set.owned_to_variant().try_to::<HashSet<String>>(),
1893+
Err(FromVariantError::InvalidItem {
1894+
index: 1,
1895+
error: Box::new(FromVariantError::InvalidVariantType {
1896+
variant_type: VariantType::I64,
1897+
expected: VariantType::GodotString
1898+
})
1899+
}),
1900+
);
1901+
}
1902+
1903+
test_variant_vec {
1904+
let original_vec = Vec::from([
1905+
"Foo".to_string(),
1906+
"Bar".to_string(),
1907+
]);
1908+
let variant = original_vec.to_variant();
1909+
let check_vec = variant.try_to::<Vec<String>>().expect("should be hash set");
1910+
assert_eq!(original_vec, check_vec);
1911+
1912+
// Check conversion of heterogeneous vec types
1913+
let non_homogenous_vec = VariantArray::new();
1914+
non_homogenous_vec.push("Foo".to_string());
1915+
non_homogenous_vec.push(7);
1916+
assert_eq!(
1917+
non_homogenous_vec.owned_to_variant().try_to::<Vec<String>>(),
1918+
Err(FromVariantError::InvalidItem {
1919+
index: 1,
1920+
error: Box::new(FromVariantError::InvalidVariantType {
1921+
variant_type: VariantType::I64,
1922+
expected: VariantType::GodotString
1923+
})
1924+
}),
1925+
);
1926+
}
1927+
18391928
test_variant_tuple {
18401929
let variant = (42i64, 54i64).to_variant();
18411930
let arr = variant.try_to::<VariantArray>().expect("should be array");

0 commit comments

Comments
 (0)