Skip to content

Commit f46e14a

Browse files
authored
Merge pull request #1295 from godot-rust/feature/dict-get-insert
Add `Dictionary::get_or_insert()`
2 parents b1e3621 + 1207df1 commit f46e14a

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

godot-core/src/builtin/collections/dictionary.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,40 @@ impl Dictionary {
141141
self.as_inner().get(&key.to_variant(), &Variant::nil())
142142
}
143143

144+
/// Gets a value and ensures the key is set, inserting default if key is absent.
145+
///
146+
/// If the `key` exists in the dictionary, this behaves like [`get()`][Self::get], and the existing value is returned.
147+
/// Otherwise, the `default` value is inserted and returned.
148+
///
149+
/// # Compatibility
150+
/// This function is natively available from Godot 4.3 onwards, we provide a polyfill for older versions.
151+
///
152+
/// _Godot equivalent: `get_or_add`_
153+
#[doc(alias = "get_or_add")]
154+
pub fn get_or_insert<K: ToGodot, V: ToGodot>(&mut self, key: K, default: V) -> Variant {
155+
self.debug_ensure_mutable();
156+
157+
let key_variant = key.to_variant();
158+
let default_variant = default.to_variant();
159+
160+
// Godot 4.3+: delegate to native get_or_add().
161+
#[cfg(since_api = "4.3")]
162+
{
163+
self.as_inner().get_or_add(&key_variant, &default_variant)
164+
}
165+
166+
// Polyfill for Godot versions before 4.3.
167+
#[cfg(before_api = "4.3")]
168+
{
169+
if let Some(existing_value) = self.get(key_variant.clone()) {
170+
existing_value
171+
} else {
172+
self.set(key_variant, default_variant.clone());
173+
default_variant
174+
}
175+
}
176+
}
177+
144178
/// Returns `true` if the dictionary contains the given key.
145179
///
146180
/// _Godot equivalent: `has`_

itest/rust/src/builtin_tests/containers/dictionary_test.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,39 @@ fn dictionary_at() {
225225
});
226226
}
227227

228+
#[itest]
229+
fn dictionary_get_or_insert() {
230+
let mut dict = vdict! {
231+
"existing": 11,
232+
"existing_nil": Variant::nil(),
233+
};
234+
235+
// Existing key -> return old value.
236+
let result = dict.get_or_insert("existing", 22);
237+
assert_eq!(result, 11.to_variant());
238+
assert_eq!(dict.at("existing"), 11.to_variant());
239+
240+
// New key -> insert + return new value.
241+
let result = dict.get_or_insert("new_key", Variant::nil());
242+
assert_eq!(result, Variant::nil());
243+
assert_eq!(dict.at("new_key"), Variant::nil());
244+
245+
// Existing key, with NIL value -> return old value.
246+
let result = dict.get_or_insert("existing_nil", "string");
247+
assert_eq!(result, Variant::nil());
248+
assert_eq!(dict.at("existing_nil"), Variant::nil());
249+
250+
// New NIL key -> insert + return new value.
251+
let result = dict.get_or_insert(Variant::nil(), 11);
252+
assert_eq!(result, 11.to_variant());
253+
assert_eq!(dict.at(Variant::nil()), 11.to_variant());
254+
255+
// Existing NIL key -> return old value.
256+
let result = dict.get_or_insert(Variant::nil(), 22);
257+
assert_eq!(result, 11.to_variant());
258+
assert_eq!(dict.at(Variant::nil()), 11.to_variant());
259+
}
260+
228261
#[itest]
229262
fn dictionary_set() {
230263
let mut dictionary = vdict! { "zero": 0, "one": 1 };

0 commit comments

Comments
 (0)