godot_core/builtin/collections/dictionary.rs
1/*
2 * Copyright (c) godot-rust; Bromeon and contributors.
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
6 */
7
8use std::cell::OnceCell;
9use std::marker::PhantomData;
10use std::{fmt, ptr};
11
12use godot_ffi as sys;
13use sys::types::OpaqueDictionary;
14use sys::{ffi_methods, interface_fn, GodotFfi};
15
16use crate::builtin::{inner, Variant, VariantArray};
17use crate::meta::{ElementType, ExtVariantType, FromGodot, ToGodot};
18
19/// Godot's `Dictionary` type.
20///
21/// Ordered associative hash-table, mapping keys to values.
22///
23/// The keys and values of the dictionary are all `Variant`s, so they can be of different types.
24/// Variants are designed to be generally cheap to clone. Typed dictionaries are planned in a future godot-rust version.
25///
26/// Check out the [book](https://godot-rust.github.io/book/godot-api/builtins.html#arrays-and-dictionaries) for a tutorial on dictionaries.
27///
28/// # Dictionary example
29///
30/// ```no_run
31/// # use godot::prelude::*;
32/// // Create empty dictionary and add key-values pairs.
33/// let mut dict = Dictionary::new();
34/// dict.set("str", "Hello");
35/// dict.set("num", 23);
36///
37/// // Keys don't need to be strings.
38/// let coord = Vector2i::new(0, 1);
39/// dict.set(coord, "Tile77");
40///
41/// // Or create the same dictionary in a single expression.
42/// let dict = vdict! {
43/// "str": "Hello",
44/// "num": 23,
45/// coord: "Tile77",
46/// };
47///
48/// // Access elements.
49/// let value: Variant = dict.at("str");
50/// let value: GString = dict.at("str").to(); // Variant::to() extracts GString.
51/// let maybe: Option<Variant> = dict.get("absent_key");
52///
53/// // Iterate over key-value pairs as (Variant, Variant).
54/// for (key, value) in dict.iter_shared() {
55/// println!("{key} => {value}");
56/// }
57///
58/// // Use typed::<K, V>() to get typed iterators.
59/// for (key, value) in dict.iter_shared().typed::<GString, Variant>() {
60/// println!("{key} => {value}");
61/// }
62///
63/// // Clone dictionary (shares the reference), and overwrite elements through clone.
64/// let mut cloned = dict.clone();
65/// cloned.remove("num");
66///
67/// // Overwrite with set(); use insert() to get the previous value.
68/// let prev = cloned.insert("str", "Goodbye"); // prev == Some("Hello")
69///
70/// // Changes will be reflected in the original dictionary.
71/// assert_eq!(dict.at("str"), "Goodbye".to_variant());
72/// assert_eq!(dict.get("num"), None);
73/// ```
74///
75/// # Thread safety
76///
77/// The same principles apply as for [`VariantArray`]. Consult its documentation for details.
78///
79/// # Godot docs
80///
81/// [`Dictionary` (stable)](https://docs.godotengine.org/en/stable/classes/class_dictionary.html)
82pub struct Dictionary {
83 opaque: OpaqueDictionary,
84
85 /// Lazily computed and cached element type information for the key type.
86 cached_key_type: OnceCell<ElementType>,
87
88 /// Lazily computed and cached element type information for the value type.
89 cached_value_type: OnceCell<ElementType>,
90}
91
92impl Dictionary {
93 fn from_opaque(opaque: OpaqueDictionary) -> Self {
94 Self {
95 opaque,
96 cached_key_type: OnceCell::new(),
97 cached_value_type: OnceCell::new(),
98 }
99 }
100
101 /// Constructs an empty `Dictionary`.
102 pub fn new() -> Self {
103 Self::default()
104 }
105
106 /// ⚠️ Returns the value for the given key, or panics.
107 ///
108 /// If you want to check for presence, use [`get()`][Self::get] or [`get_or_nil()`][Self::get_or_nil].
109 ///
110 /// # Panics
111 ///
112 /// If there is no value for the given key. Note that this is distinct from a `NIL` value, which is returned as `Variant::nil()`.
113 pub fn at<K: ToGodot>(&self, key: K) -> Variant {
114 // Code duplication with get(), to avoid third clone (since K: ToGodot takes ownership).
115
116 let key = key.to_variant();
117 if self.contains_key(key.clone()) {
118 self.get_or_nil(key)
119 } else {
120 panic!("key {key:?} missing in dictionary: {self:?}")
121 }
122 }
123
124 /// Returns the value for the given key, or `None`.
125 ///
126 /// Note that `NIL` values are returned as `Some(Variant::nil())`, while absent values are returned as `None`.
127 /// If you want to treat both as `NIL`, use [`get_or_nil()`][Self::get_or_nil].
128 ///
129 /// When you are certain that a key is present, use [`at()`][`Self::at`] instead.
130 ///
131 /// This can be combined with Rust's `Option` methods, e.g. `dict.get(key).unwrap_or(default)`.
132 pub fn get<K: ToGodot>(&self, key: K) -> Option<Variant> {
133 // If implementation is changed, make sure to update at().
134
135 let key = key.to_variant();
136 if self.contains_key(key.clone()) {
137 Some(self.get_or_nil(key))
138 } else {
139 None
140 }
141 }
142
143 /// Returns the value at the key in the dictionary, or `NIL` otherwise.
144 ///
145 /// This method does not let you differentiate `NIL` values stored as values from absent keys.
146 /// If you need that, use [`get()`][`Self::get`] instead.
147 ///
148 /// When you are certain that a key is present, use [`at()`][`Self::at`] instead.
149 ///
150 /// _Godot equivalent: `dict.get(key, null)`_
151 pub fn get_or_nil<K: ToGodot>(&self, key: K) -> Variant {
152 self.as_inner().get(&key.to_variant(), &Variant::nil())
153 }
154
155 /// Gets a value and ensures the key is set, inserting default if key is absent.
156 ///
157 /// If the `key` exists in the dictionary, this behaves like [`get()`][Self::get], and the existing value is returned.
158 /// Otherwise, the `default` value is inserted and returned.
159 ///
160 /// # Compatibility
161 /// This function is natively available from Godot 4.3 onwards, we provide a polyfill for older versions.
162 ///
163 /// _Godot equivalent: `get_or_add`_
164 #[doc(alias = "get_or_add")]
165 pub fn get_or_insert<K: ToGodot, V: ToGodot>(&mut self, key: K, default: V) -> Variant {
166 self.balanced_ensure_mutable();
167
168 let key_variant = key.to_variant();
169 let default_variant = default.to_variant();
170
171 // Godot 4.3+: delegate to native get_or_add().
172 #[cfg(since_api = "4.3")]
173 {
174 self.as_inner().get_or_add(&key_variant, &default_variant)
175 }
176
177 // Polyfill for Godot versions before 4.3.
178 #[cfg(before_api = "4.3")]
179 {
180 if let Some(existing_value) = self.get(key_variant.clone()) {
181 existing_value
182 } else {
183 self.set(key_variant, default_variant.clone());
184 default_variant
185 }
186 }
187 }
188
189 /// Returns `true` if the dictionary contains the given key.
190 ///
191 /// _Godot equivalent: `has`_
192 #[doc(alias = "has")]
193 pub fn contains_key<K: ToGodot>(&self, key: K) -> bool {
194 let key = key.to_variant();
195 self.as_inner().has(&key)
196 }
197
198 /// Returns `true` if the dictionary contains all the given keys.
199 ///
200 /// _Godot equivalent: `has_all`_
201 #[doc(alias = "has_all")]
202 pub fn contains_all_keys(&self, keys: &VariantArray) -> bool {
203 self.as_inner().has_all(keys)
204 }
205
206 /// Returns the number of entries in the dictionary.
207 ///
208 /// _Godot equivalent: `size`_
209 #[doc(alias = "size")]
210 pub fn len(&self) -> usize {
211 self.as_inner().size().try_into().unwrap()
212 }
213
214 /// Returns true if the dictionary is empty.
215 pub fn is_empty(&self) -> bool {
216 self.as_inner().is_empty()
217 }
218
219 /// Reverse-search a key by its value.
220 ///
221 /// Unlike Godot, this will return `None` if the key does not exist and `Some(Variant::nil())` the key is `NIL`.
222 ///
223 /// This operation is rarely needed and very inefficient. If you find yourself needing it a lot, consider
224 /// using a `HashMap` or `Dictionary` with the inverse mapping (`V` -> `K`).
225 ///
226 /// _Godot equivalent: `find_key`_
227 #[doc(alias = "find_key")]
228 pub fn find_key_by_value<V: ToGodot>(&self, value: V) -> Option<Variant> {
229 let key = self.as_inner().find_key(&value.to_variant());
230
231 if !key.is_nil() || self.contains_key(key.clone()) {
232 Some(key)
233 } else {
234 None
235 }
236 }
237
238 /// Removes all key-value pairs from the dictionary.
239 pub fn clear(&mut self) {
240 self.balanced_ensure_mutable();
241
242 self.as_inner().clear()
243 }
244
245 /// Set a key to a given value.
246 ///
247 /// If you are interested in the previous value, use [`insert()`][Self::insert] instead.
248 ///
249 /// _Godot equivalent: `dict[key] = value`_
250 pub fn set<K: ToGodot, V: ToGodot>(&mut self, key: K, value: V) {
251 self.balanced_ensure_mutable();
252
253 let key = key.to_variant();
254
255 // SAFETY: `self.get_ptr_mut(key)` always returns a valid pointer to a value in the dictionary; either pre-existing or newly inserted.
256 unsafe {
257 value.to_variant().move_into_var_ptr(self.get_ptr_mut(key));
258 }
259 }
260
261 /// Insert a value at the given key, returning the previous value for that key (if available).
262 ///
263 /// If you don't need the previous value, use [`set()`][Self::set] instead.
264 #[must_use]
265 pub fn insert<K: ToGodot, V: ToGodot>(&mut self, key: K, value: V) -> Option<Variant> {
266 self.balanced_ensure_mutable();
267
268 let key = key.to_variant();
269 let old_value = self.get(key.clone());
270 self.set(key, value);
271 old_value
272 }
273
274 /// Removes a key from the map, and returns the value associated with
275 /// the key if the key was in the dictionary.
276 ///
277 /// _Godot equivalent: `erase`_
278 #[doc(alias = "erase")]
279 pub fn remove<K: ToGodot>(&mut self, key: K) -> Option<Variant> {
280 self.balanced_ensure_mutable();
281
282 let key = key.to_variant();
283 let old_value = self.get(key.clone());
284 self.as_inner().erase(&key);
285 old_value
286 }
287
288 crate::declare_hash_u32_method! {
289 /// Returns a 32-bit integer hash value representing the dictionary and its contents.
290 }
291
292 #[deprecated = "renamed to `hash_u32`"]
293 #[must_use]
294 pub fn hash(&self) -> u32 {
295 self.as_inner().hash().try_into().unwrap()
296 }
297
298 /// Creates a new `Array` containing all the keys currently in the dictionary.
299 ///
300 /// _Godot equivalent: `keys`_
301 #[doc(alias = "keys")]
302 pub fn keys_array(&self) -> VariantArray {
303 self.as_inner().keys()
304 }
305
306 /// Creates a new `Array` containing all the values currently in the dictionary.
307 ///
308 /// _Godot equivalent: `values`_
309 #[doc(alias = "values")]
310 pub fn values_array(&self) -> VariantArray {
311 self.as_inner().values()
312 }
313
314 /// Copies all keys and values from `other` into `self`.
315 ///
316 /// If `overwrite` is true, it will overwrite pre-existing keys.
317 ///
318 /// _Godot equivalent: `merge`_
319 #[doc(alias = "merge")]
320 pub fn extend_dictionary(&mut self, other: &Self, overwrite: bool) {
321 self.balanced_ensure_mutable();
322
323 self.as_inner().merge(other, overwrite)
324 }
325
326 /// Deep copy, duplicating nested collections.
327 ///
328 /// All nested arrays and dictionaries are duplicated and will not be shared with the original dictionary.
329 /// Note that any `Object`-derived elements will still be shallow copied.
330 ///
331 /// To create a shallow copy, use [`Self::duplicate_shallow()`] instead.
332 /// To create a new reference to the same dictionary data, use [`clone()`][Clone::clone].
333 ///
334 /// _Godot equivalent: `dict.duplicate(true)`_
335 pub fn duplicate_deep(&self) -> Self {
336 self.as_inner().duplicate(true).with_cache(self)
337 }
338
339 /// Shallow copy, copying elements but sharing nested collections.
340 ///
341 /// All dictionary keys and values are copied, but any reference types (such as `Array`, `Dictionary` and `Gd<T>` objects)
342 /// will still refer to the same value.
343 ///
344 /// To create a deep copy, use [`Self::duplicate_deep()`] instead.
345 /// To create a new reference to the same dictionary data, use [`clone()`][Clone::clone].
346 ///
347 /// _Godot equivalent: `dict.duplicate(false)`_
348 pub fn duplicate_shallow(&self) -> Self {
349 self.as_inner().duplicate(false).with_cache(self)
350 }
351
352 /// Returns an iterator over the key-value pairs of the `Dictionary`.
353 ///
354 /// The pairs are each of type `(Variant, Variant)`. Each pair references the original `Dictionary`, but instead of a `&`-reference
355 /// to key-value pairs as you might expect, the iterator returns a (cheap, shallow) copy of each key-value pair.
356 ///
357 /// Note that it's possible to modify the `Dictionary` through another reference while iterating over it. This will not result in
358 /// unsoundness or crashes, but will cause the iterator to behave in an unspecified way.
359 ///
360 /// Use `dict.iter_shared().typed::<K, V>()` to iterate over `(K, V)` pairs instead.
361 pub fn iter_shared(&self) -> Iter<'_> {
362 Iter::new(self)
363 }
364
365 /// Returns an iterator over the keys in a `Dictionary`.
366 ///
367 /// The keys are each of type `Variant`. Each key references the original `Dictionary`, but instead of a `&`-reference to keys pairs
368 /// as you might expect, the iterator returns a (cheap, shallow) copy of each key pair.
369 ///
370 /// Note that it's possible to modify the `Dictionary` through another reference while iterating over it. This will not result in
371 /// unsoundness or crashes, but will cause the iterator to behave in an unspecified way.
372 ///
373 /// Use `dict.keys_shared().typed::<K>()` to iterate over `K` keys instead.
374 pub fn keys_shared(&self) -> Keys<'_> {
375 Keys::new(self)
376 }
377
378 /// Turns the dictionary into a shallow-immutable dictionary.
379 ///
380 /// Makes the dictionary read-only and returns the original dictionary. Disables modification of the dictionary's contents.
381 /// Does not apply to nested content, e.g. elements of nested dictionaries.
382 ///
383 /// In GDScript, dictionaries are automatically read-only if declared with the `const` keyword.
384 ///
385 /// # Semantics and alternatives
386 /// You can use this in Rust, but the behavior of mutating methods is only validated in a best-effort manner (more than in GDScript though):
387 /// some methods like `set()` panic in Debug mode, when used on a read-only dictionary. There is no guarantee that any attempts to change
388 /// result in feedback; some may silently do nothing.
389 ///
390 /// In Rust, you can use shared references (`&Dictionary`) to prevent mutation. Note however that `Clone` can be used to create another
391 /// reference, through which mutation can still occur. For deep-immutable dictionaries, you'll need to keep your `Dictionary` encapsulated
392 /// or directly use Rust data structures.
393 ///
394 /// _Godot equivalent: `make_read_only`_
395 #[doc(alias = "make_read_only")]
396 pub fn into_read_only(self) -> Self {
397 self.as_inner().make_read_only();
398 self
399 }
400
401 /// Returns true if the dictionary is read-only.
402 ///
403 /// See [`into_read_only()`][Self::into_read_only].
404 /// In GDScript, dictionaries are automatically read-only if declared with the `const` keyword.
405 pub fn is_read_only(&self) -> bool {
406 self.as_inner().is_read_only()
407 }
408
409 /// Best-effort mutability check.
410 ///
411 /// # Panics (safeguards-balanced)
412 /// If the dictionary is marked as read-only.
413 fn balanced_ensure_mutable(&self) {
414 sys::balanced_assert!(
415 !self.is_read_only(),
416 "mutating operation on read-only dictionary"
417 );
418 }
419
420 /// Returns the runtime element type information for keys in this dictionary.
421 ///
422 /// Provides information about Godot typed dictionaries, even though godot-rust currently doesn't implement generics for those.
423 ///
424 /// The result is generally cached, so feel free to call this method repeatedly.
425 ///
426 /// # Panics (Debug)
427 /// In the astronomically rare case where another extension in Godot modifies a dictionary's key type (which godot-rust already cached as `Untyped`)
428 /// via C function `dictionary_set_typed`, thus leading to incorrect cache values. Such bad practice of not typing dictionaries immediately on
429 /// construction is not supported, and will not be checked in Release mode.
430 #[cfg(since_api = "4.4")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.4")))]
431 pub fn key_element_type(&self) -> ElementType {
432 ElementType::get_or_compute_cached(
433 &self.cached_key_type,
434 || self.as_inner().get_typed_key_builtin(),
435 || self.as_inner().get_typed_key_class_name(),
436 || self.as_inner().get_typed_key_script(),
437 )
438 }
439
440 /// Returns the runtime element type information for values in this dictionary.
441 ///
442 /// Provides information about Godot typed dictionaries, even though godot-rust currently doesn't implement generics for those.
443 ///
444 /// The result is generally cached, so feel free to call this method repeatedly.
445 ///
446 /// # Panics (Debug)
447 /// In the astronomically rare case where another extension in Godot modifies a dictionary's value type (which godot-rust already cached as `Untyped`)
448 /// via C function `dictionary_set_typed`, thus leading to incorrect cache values. Such bad practice of not typing dictionaries immediately on
449 /// construction is not supported, and will not be checked in Release mode.
450 #[cfg(since_api = "4.4")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.4")))]
451 pub fn value_element_type(&self) -> ElementType {
452 ElementType::get_or_compute_cached(
453 &self.cached_value_type,
454 || self.as_inner().get_typed_value_builtin(),
455 || self.as_inner().get_typed_value_class_name(),
456 || self.as_inner().get_typed_value_script(),
457 )
458 }
459
460 #[doc(hidden)]
461 pub fn as_inner(&self) -> inner::InnerDictionary<'_> {
462 inner::InnerDictionary::from_outer(self)
463 }
464
465 /// Get the pointer corresponding to the given key in the dictionary.
466 ///
467 /// If there exists no value at the given key, a `NIL` variant will be inserted for that key.
468 fn get_ptr_mut<K: ToGodot>(&mut self, key: K) -> sys::GDExtensionVariantPtr {
469 let key = key.to_variant();
470
471 // Never a null pointer, since entry either existed already or was inserted above.
472 // SAFETY: accessing an unknown key _mutably_ creates that entry in the dictionary, with value `NIL`.
473 unsafe { interface_fn!(dictionary_operator_index)(self.sys_mut(), key.var_sys()) }
474 }
475
476 /// Execute a function that creates a new Dictionary, transferring cached element types if available.
477 ///
478 /// This is a convenience helper for methods that create new Dictionary instances and want to preserve
479 /// cached type information to avoid redundant FFI calls.
480 fn with_cache(self, source: &Self) -> Self {
481 // Transfer both key and value type caches independently
482 ElementType::transfer_cache(&source.cached_key_type, &self.cached_key_type);
483 ElementType::transfer_cache(&source.cached_value_type, &self.cached_value_type);
484 self
485 }
486}
487
488// ----------------------------------------------------------------------------------------------------------------------------------------------
489// Traits
490
491// SAFETY:
492// - `move_return_ptr`
493// Nothing special needs to be done beyond a `std::mem::swap` when returning a Dictionary.
494// So we can just use `ffi_methods`.
495//
496// - `from_arg_ptr`
497// Dictionaries are properly initialized through a `from_sys` call, but the ref-count should be
498// incremented as that is the callee's responsibility. Which we do by calling
499// `std::mem::forget(dictionary.clone())`.
500unsafe impl GodotFfi for Dictionary {
501 const VARIANT_TYPE: ExtVariantType = ExtVariantType::Concrete(sys::VariantType::DICTIONARY);
502
503 ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque; .. }
504}
505
506crate::meta::impl_godot_as_self!(Dictionary: ByRef);
507
508impl_builtin_traits! {
509 for Dictionary {
510 Default => dictionary_construct_default;
511 Drop => dictionary_destroy;
512 PartialEq => dictionary_operator_equal;
513 // No < operator for dictionaries.
514 // Hash could be added, but without Eq it's not that useful.
515 }
516}
517
518impl fmt::Debug for Dictionary {
519 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
520 write!(f, "{:?}", self.to_variant().stringify())
521 }
522}
523
524impl fmt::Display for Dictionary {
525 /// Formats `Dictionary` to match Godot's string representation.
526 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
527 write!(f, "{{ ")?;
528 for (count, (key, value)) in self.iter_shared().enumerate() {
529 if count != 0 {
530 write!(f, ", ")?;
531 }
532 write!(f, "{key}: {value}")?;
533 }
534 write!(f, " }}")
535 }
536}
537
538/// Creates a new reference to the data in this dictionary. Changes to the original dictionary will be
539/// reflected in the copy and vice versa.
540///
541/// To create a (mostly) independent copy instead, see [`Dictionary::duplicate_shallow()`] and
542/// [`Dictionary::duplicate_deep()`].
543impl Clone for Dictionary {
544 fn clone(&self) -> Self {
545 // SAFETY: `self` is a valid dictionary, since we have a reference that keeps it alive.
546 let result = unsafe {
547 Self::new_with_uninit(|self_ptr| {
548 let ctor = sys::builtin_fn!(dictionary_construct_copy);
549 let args = [self.sys()];
550 ctor(self_ptr, args.as_ptr());
551 })
552 };
553 result.with_cache(self)
554 }
555}
556
557// ----------------------------------------------------------------------------------------------------------------------------------------------
558// Conversion traits
559
560/// Creates a dictionary from the given iterator `I` over a `(&K, &V)` key-value pair.
561///
562/// Each key and value are converted to a `Variant`.
563impl<'a, 'b, K, V, I> From<I> for Dictionary
564where
565 I: IntoIterator<Item = (&'a K, &'b V)>,
566 K: ToGodot + 'a,
567 V: ToGodot + 'b,
568{
569 fn from(iterable: I) -> Self {
570 iterable
571 .into_iter()
572 .map(|(key, value)| (key.to_variant(), value.to_variant()))
573 .collect()
574 }
575}
576
577/// Insert iterator range into dictionary.
578///
579/// Inserts all key-value pairs from the iterator into the dictionary. Previous values for keys appearing
580/// in `iter` will be overwritten.
581impl<K: ToGodot, V: ToGodot> Extend<(K, V)> for Dictionary {
582 fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
583 for (k, v) in iter.into_iter() {
584 self.set(k.to_variant(), v.to_variant())
585 }
586 }
587}
588
589impl<K: ToGodot, V: ToGodot> FromIterator<(K, V)> for Dictionary {
590 fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
591 let mut dict = Dictionary::new();
592 dict.extend(iter);
593 dict
594 }
595}
596
597// ----------------------------------------------------------------------------------------------------------------------------------------------
598
599/// Internal helper for different iterator impls -- not an iterator itself
600struct DictionaryIter<'a> {
601 last_key: Option<Variant>,
602 dictionary: &'a Dictionary,
603 is_first: bool,
604 next_idx: usize,
605}
606
607impl<'a> DictionaryIter<'a> {
608 fn new(dictionary: &'a Dictionary) -> Self {
609 Self {
610 last_key: None,
611 dictionary,
612 is_first: true,
613 next_idx: 0,
614 }
615 }
616
617 fn next_key(&mut self) -> Option<Variant> {
618 let new_key = if self.is_first {
619 self.is_first = false;
620 Self::call_init(self.dictionary)
621 } else {
622 Self::call_next(self.dictionary, self.last_key.take()?)
623 };
624
625 if self.next_idx < self.dictionary.len() {
626 self.next_idx += 1;
627 }
628
629 self.last_key.clone_from(&new_key);
630 new_key
631 }
632
633 fn next_key_value(&mut self) -> Option<(Variant, Variant)> {
634 let key = self.next_key()?;
635 if !self.dictionary.contains_key(key.clone()) {
636 return None;
637 }
638
639 let value = self.dictionary.as_inner().get(&key, &Variant::nil());
640 Some((key, value))
641 }
642
643 fn size_hint(&self) -> (usize, Option<usize>) {
644 // Need to check for underflow in case any entry was removed while
645 // iterating (i.e. next_index > dicitonary.len())
646 let remaining = usize::saturating_sub(self.dictionary.len(), self.next_idx);
647
648 (remaining, Some(remaining))
649 }
650
651 fn call_init(dictionary: &Dictionary) -> Option<Variant> {
652 let variant: Variant = Variant::nil();
653 let iter_fn = |dictionary, next_value: sys::GDExtensionVariantPtr, valid| unsafe {
654 interface_fn!(variant_iter_init)(dictionary, sys::SysPtr::as_uninit(next_value), valid)
655 };
656
657 Self::ffi_iterate(iter_fn, dictionary, variant)
658 }
659
660 fn call_next(dictionary: &Dictionary, last_key: Variant) -> Option<Variant> {
661 let iter_fn = |dictionary, next_value, valid| unsafe {
662 interface_fn!(variant_iter_next)(dictionary, next_value, valid)
663 };
664
665 Self::ffi_iterate(iter_fn, dictionary, last_key)
666 }
667
668 /// Calls the provided Godot FFI function, in order to iterate the current state.
669 ///
670 /// # Safety:
671 /// `iter_fn` must point to a valid function that interprets the parameters according to their type specification.
672 fn ffi_iterate(
673 iter_fn: unsafe fn(
674 sys::GDExtensionConstVariantPtr,
675 sys::GDExtensionVariantPtr,
676 *mut sys::GDExtensionBool,
677 ) -> sys::GDExtensionBool,
678 dictionary: &Dictionary,
679 mut next_value: Variant,
680 ) -> Option<Variant> {
681 let dictionary = dictionary.to_variant();
682 let mut valid_u8: u8 = 0;
683
684 // SAFETY:
685 // `dictionary` is a valid `Dictionary` since we have a reference to it,
686 // so this will call the implementation for dictionaries.
687 // `last_key` is an initialized and valid `Variant`, since we own a copy of it.
688 let has_next = unsafe {
689 iter_fn(
690 dictionary.var_sys(),
691 next_value.var_sys_mut(),
692 ptr::addr_of_mut!(valid_u8),
693 )
694 };
695 let valid = u8_to_bool(valid_u8);
696 let has_next = u8_to_bool(has_next);
697
698 if has_next {
699 assert!(valid);
700 Some(next_value)
701 } else {
702 None
703 }
704 }
705}
706
707// ----------------------------------------------------------------------------------------------------------------------------------------------
708
709/// Iterator over key-value pairs in a [`Dictionary`].
710///
711/// See [`Dictionary::iter_shared()`] for more information about iteration over dictionaries.
712pub struct Iter<'a> {
713 iter: DictionaryIter<'a>,
714}
715
716impl<'a> Iter<'a> {
717 fn new(dictionary: &'a Dictionary) -> Self {
718 Self {
719 iter: DictionaryIter::new(dictionary),
720 }
721 }
722
723 /// Creates an iterator that converts each `(Variant, Variant)` key-value pair into a `(K, V)` key-value
724 /// pair, panicking upon conversion failure.
725 pub fn typed<K: FromGodot, V: FromGodot>(self) -> TypedIter<'a, K, V> {
726 TypedIter::from_untyped(self)
727 }
728}
729
730impl Iterator for Iter<'_> {
731 type Item = (Variant, Variant);
732
733 fn next(&mut self) -> Option<Self::Item> {
734 self.iter.next_key_value()
735 }
736
737 fn size_hint(&self) -> (usize, Option<usize>) {
738 self.iter.size_hint()
739 }
740}
741
742// ----------------------------------------------------------------------------------------------------------------------------------------------
743
744/// Iterator over keys in a [`Dictionary`].
745///
746/// See [`Dictionary::keys_shared()`] for more information about iteration over dictionaries.
747pub struct Keys<'a> {
748 iter: DictionaryIter<'a>,
749}
750
751impl<'a> Keys<'a> {
752 fn new(dictionary: &'a Dictionary) -> Self {
753 Self {
754 iter: DictionaryIter::new(dictionary),
755 }
756 }
757
758 /// Creates an iterator that will convert each `Variant` key into a key of type `K`,
759 /// panicking upon failure to convert.
760 pub fn typed<K: FromGodot>(self) -> TypedKeys<'a, K> {
761 TypedKeys::from_untyped(self)
762 }
763
764 /// Returns an array of the keys.
765 pub fn array(self) -> VariantArray {
766 // Can only be called
767 assert!(self.iter.is_first);
768 self.iter.dictionary.keys_array()
769 }
770}
771
772impl Iterator for Keys<'_> {
773 type Item = Variant;
774
775 fn next(&mut self) -> Option<Self::Item> {
776 self.iter.next_key()
777 }
778
779 fn size_hint(&self) -> (usize, Option<usize>) {
780 self.iter.size_hint()
781 }
782}
783
784// ----------------------------------------------------------------------------------------------------------------------------------------------
785
786/// [`Dictionary`] iterator that converts each key-value pair into a typed `(K, V)`.
787///
788/// See [`Dictionary::iter_shared()`] for more information about iteration over dictionaries.
789pub struct TypedIter<'a, K, V> {
790 iter: DictionaryIter<'a>,
791 _k: PhantomData<K>,
792 _v: PhantomData<V>,
793}
794
795impl<'a, K, V> TypedIter<'a, K, V> {
796 fn from_untyped(value: Iter<'a>) -> Self {
797 Self {
798 iter: value.iter,
799 _k: PhantomData,
800 _v: PhantomData,
801 }
802 }
803}
804
805impl<K: FromGodot, V: FromGodot> Iterator for TypedIter<'_, K, V> {
806 type Item = (K, V);
807
808 fn next(&mut self) -> Option<Self::Item> {
809 self.iter
810 .next_key_value()
811 .map(|(key, value)| (K::from_variant(&key), V::from_variant(&value)))
812 }
813
814 fn size_hint(&self) -> (usize, Option<usize>) {
815 self.iter.size_hint()
816 }
817}
818
819// ----------------------------------------------------------------------------------------------------------------------------------------------
820
821/// [`Dictionary`] iterator that converts each key into a typed `K`.
822///
823/// See [`Dictionary::iter_shared()`] for more information about iteration over dictionaries.
824pub struct TypedKeys<'a, K> {
825 iter: DictionaryIter<'a>,
826 _k: PhantomData<K>,
827}
828
829impl<'a, K> TypedKeys<'a, K> {
830 fn from_untyped(value: Keys<'a>) -> Self {
831 Self {
832 iter: value.iter,
833 _k: PhantomData,
834 }
835 }
836}
837
838impl<K: FromGodot> Iterator for TypedKeys<'_, K> {
839 type Item = K;
840
841 fn next(&mut self) -> Option<Self::Item> {
842 self.iter.next_key().map(|k| K::from_variant(&k))
843 }
844
845 fn size_hint(&self) -> (usize, Option<usize>) {
846 self.iter.size_hint()
847 }
848}
849
850// ----------------------------------------------------------------------------------------------------------------------------------------------
851// Helper functions
852
853fn u8_to_bool(u: u8) -> bool {
854 match u {
855 0 => false,
856 1 => true,
857 _ => panic!("Invalid boolean value {u}"),
858 }
859}
860
861// ----------------------------------------------------------------------------------------------------------------------------------------------
862
863/// Constructs [`Dictionary`] literals, close to Godot's own syntax.
864///
865/// Any value can be used as a key, but to use an expression you need to surround it
866/// in `()` or `{}`.
867///
868/// # Example
869/// ```no_run
870/// use godot::builtin::{vdict, Variant};
871///
872/// let key = "my_key";
873/// let d = vdict! {
874/// "key1": 10,
875/// "another": Variant::nil(),
876/// key: true,
877/// (1 + 2): "final",
878/// };
879/// ```
880///
881/// # See also
882///
883/// For arrays, similar macros [`array!`][macro@crate::builtin::array] and [`varray!`][macro@crate::builtin::varray] exist.
884#[macro_export]
885macro_rules! vdict {
886 ($($key:tt: $value:expr),* $(,)?) => {
887 {
888 let mut d = $crate::builtin::Dictionary::new();
889 $(
890 // `cargo check` complains that `(1 + 2): true` has unused parens, even though it's not
891 // possible to omit the parens.
892 #[allow(unused_parens)]
893 d.set($key, $value);
894 )*
895 d
896 }
897 };
898}
899
900#[macro_export]
901#[deprecated = "Migrate to `vdict!`. The name `dict!` will be used in the future for typed dictionaries."]
902macro_rules! dict {
903 ($($key:tt: $value:expr),* $(,)?) => {
904 $crate::vdict!(
905 $($key: $value),*
906 )
907 };
908}