1 /**
2 Variant hashmap/dictionary type.
3 
4 Copyright:
5 Copyright (c) 2007 Juan Linietsky, Ariel Manzur.
6 Copyright (c) 2014 Godot Engine contributors (cf. AUTHORS.md)
7 Copyright (c) 2017 Godot-D contributors
8 Copyright (c) 2022 Godot-DLang contributors
9 
10 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License)
11 
12 
13 */
14 module godot.dictionary;
15 
16 import godot.abi;
17 import godot;
18 import godot.builtins;
19 
20 import std.meta;
21 
22 /**
23 Associative container which contains values referenced by unique keys. Dictionaries are always passed by reference.
24 */
25 struct Dictionary {
26     int opApply(int delegate(const(Variant), ref Variant) dg) {
27 
28         godot_variant* k;
29         _godot_api.variant_iter_next(&_godot_dictionary, k, null);
30         while (k) {
31             Variant* v = cast(Variant*) _godot_api.dictionary_operator_index(
32                 &_godot_dictionary, k);
33             int res = dg(*cast(const(Variant*)) k, *v);
34             if (res)
35                 return res;
36             _godot_api.variant_iter_next(&_godot_dictionary, k, null);
37         }
38         return 0;
39     }
40 
41     int opApply(int delegate(const(Variant), ref const(Variant)) dg) const {
42         godot_variant* k;
43         _godot_api.variant_iter_next(&_godot_dictionary, k, null);
44         while (k) {
45             Variant* v = cast(Variant*) _godot_api.dictionary_operator_index(
46                 cast(godot_dictionary*)&_godot_dictionary, k);
47             int res = dg(*cast(const(Variant*)) k, *v);
48             if (res)
49                 return res;
50             _godot_api.variant_iter_next(&_godot_dictionary, k, null);
51         }
52         return 0;
53     }
54 
55     //@nogc nothrow:
56 
57     package(godot) union dictionary {
58         godot_dictionary _godot_dictionary;
59         Dictionary_Bind _bind;
60     }
61 
62     package(godot) dictionary _dictionary;
63     alias _dictionary this;
64 
65     @disable this();
66 
67     package(godot) this(godot_dictionary opaque) {
68         _godot_dictionary = opaque;
69     }
70 
71     this(this) {
72         const godot_dictionary tmp = _godot_dictionary;
73         _godot_api.variant_new_copy(&_godot_dictionary, &tmp);
74     }
75 
76     Dictionary opAssign(in Dictionary other) {
77         _godot_api.variant_destroy(&_godot_dictionary);
78         _godot_api.variant_new_copy(&_godot_dictionary, &other._godot_dictionary);
79         return this;
80     }
81 
82     /++
83 	Create a Dictionary and add the key-value pairs $(PARAM args) to it.
84 
85 	Example:
86 	---
87 	Dictionary emptyDictionary = Dictionary.make();
88 	Dictionary status = Dictionary.make(gs!"health", 100, gs!"shields", 75);
89 	---
90 	+/
91     static Dictionary make(Args...)(Args args)
92             if (Args.length % 2 == 0 && allSatisfy!(Variant.compatibleToGodot, Args)) {
93         Dictionary ret = void;
94         //_godot_api.dictionary_new(&ret._godot_dictionary);
95         _godot_api.get_variant_from_type_constructor(GDEXTENSION_VARIANT_TYPE_DICTIONARY)(
96             cast(GDExtensionTypePtr)&ret._godot_dictionary, null);
97         /+
98 		BUG: wtf? when using static foreach(i; 0..Args.length/2):
99 		Error: cannot use operator ~= in @nogc delegate godot.dictionary.Dictionary.make!(GodotStringLiteral!"name", String, GodotStringLiteral!"type", int).make.__lambda6
100 		+/
101         static foreach (i, Arg; Args) {
102             static if (i % 2 == 0) {
103                 ret[args[i]] = args[i + 1];
104             }
105         }
106         return ret;
107     }
108 
109     /// FIXME: naming convention fail again
110     deprecated("Use Dictionary.make() with 0 args instead.")
111     static Dictionary empty_dictionary() {
112         Dictionary d = void;
113         _godot_api.get_variant_from_type_constructor(GDEXTENSION_VARIANT_TYPE_DICTIONARY)(
114             cast(GDExtensionTypePtr)&d._godot_dictionary, null);
115         return d;
116     }
117 
118     void clear() {
119         //auto m =_godot_api.variant_get_ptr_builtin_method(GDEXTENSION_VARIANT_TYPE_DICTIONARY, "clear", 134152229);
120         //m(cast(GDExtensionTypePtr)&_godot_dictionary);
121         _bind.clear();
122     }
123 
124     bool empty() const {
125         //return cast(bool)_godot_api.dictionary_empty(&_godot_dictionary);
126         return _bind.isEmpty();
127     }
128 
129     void erase(K)(in K key) if (is(K : Variant) || Variant.compatibleToGodot!K) {
130         const Variant k = key;
131         //_godot_api.dictionary_erase(&_godot_dictionary, &k._godot_variant);
132         _bind.erase(k);
133     }
134 
135     bool has(K)(in K key) const if (is(K : Variant) || Variant.compatibleToGodot!K) {
136         const Variant k = key;
137         return cast(bool) _godot_api.dictionary_has(&_godot_dictionary, &k._godot_variant);
138     }
139 
140     bool hasAll(in Array keys) const {
141         //return cast(bool)_godot_api.dictionary_has_all(&_godot_dictionary, &keys._godot_array);
142         return _bind.hasAll(keys);
143     }
144 
145     uint hash() const {
146         //return _godot_api.dictionary_hash(&_godot_dictionary);
147         return cast(uint) _bind.hash();
148     }
149 
150     Array keys() const {
151         Array a = void;
152         //a._godot_array = _godot_api.dictionary_keys(&_godot_dictionary);
153         a = _bind.keys();
154         return a;
155     }
156 
157     Variant opIndex(K)(in K key) const 
158             if (is(K : Variant) || Variant.compatibleToGodot!K) {
159         const Variant k = key;
160         //Variant ret = void;
161         //ret._godot_variant = _godot_api.dictionary_get(&_godot_dictionary, &k._godot_variant);
162         //return ret;
163         return _bind.get(k, k);
164     }
165 
166     void opIndexAssign(K, V)(in auto ref V value, in auto ref K key)
167             if (
168                 (is(K : Variant) || Variant.compatibleToGodot!K) &&
169             (is(V
170             : Variant) || Variant.compatibleToGodot!V)) {
171         const Variant k = key;
172         const Variant v = value;
173         auto tmp = _godot_api.dictionary_operator_index(&_godot_dictionary, &k._godot_variant);
174         Variant t = void;
175         t._godot_variant = tmp;
176         t = value;
177     }
178 
179     int size() const {
180         //return _godot_api.dictionary_size(&_godot_dictionary);
181         return cast(int) _bind.size;
182     }
183 
184     String toJson() const {
185         import godot.json;
186         import godot.api;
187 
188         Variant v = void;
189         v._godot_variant = *cast(godot_variant*)&this;
190         JSON json = memnew!JSON();
191         return json.stringify(v, gs!(`""`), true, false);
192 
193         //godot_string s = _godot_api.dictionary_to_json(&_godot_dictionary);
194         //return cast(String)s;
195     }
196 
197     Array values() const {
198         //godot_array a = _godot_api.dictionary_values(&_godot_dictionary);
199         //return cast(Array)a;
200         return _bind.values();
201     }
202 
203     ~this() {
204         _godot_api.variant_destroy(&_godot_dictionary);
205     }
206 }