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}