1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
use crate::get_api;
use crate::sys;
use crate::GodotString;

use crate::Variant;
use crate::VariantArray;
use std::fmt;

/// A reference-counted `Dictionary` of `Variant` key-value pairs.
pub struct Dictionary(pub(crate) sys::godot_dictionary);

impl Dictionary {
    /// Creates an empty `Dictionary`.
    pub fn new() -> Self {
        Dictionary::default()
    }

    /// Returns `true` if the `Dictionary` contains no elements.
    pub fn is_empty(&self) -> bool {
        unsafe { (get_api().godot_dictionary_empty)(&self.0) }
    }

    /// Returns the number of elements in the `Dictionary`.
    pub fn len(&self) -> i32 {
        unsafe { (get_api().godot_dictionary_size)(&self.0) }
    }

    /// Clears the `Dictionary`, removing all key-value pairs.
    pub fn clear(&mut self) {
        unsafe { (get_api().godot_dictionary_clear)(&mut self.0) }
    }

    /// Returns true if the `Dictionary` contains the specified key.
    pub fn contains(&self, key: &Variant) -> bool {
        unsafe { (get_api().godot_dictionary_has)(&self.0, &key.0) }
    }

    /// Returns true if the `Dictionary` has all of the keys in the given array.
    pub fn contains_all(&self, keys: &VariantArray) -> bool {
        unsafe { (get_api().godot_dictionary_has_all)(&self.0, &keys.0) }
    }

    /// Erase a key-value pair in the `Dictionary` by the specified key.
    pub fn erase(&mut self, key: &Variant) {
        unsafe { (get_api().godot_dictionary_erase)(&mut self.0, &key.0) }
    }

    /// Returns a copy of the value corresponding to the key.
    pub fn get(&self, key: &Variant) -> Variant {
        unsafe { Variant((get_api().godot_dictionary_get)(&self.0, &key.0)) }
    }

    /// Sets a value to the element corresponding to the key.
    pub fn set(&mut self, key: &Variant, val: &Variant) {
        unsafe { (get_api().godot_dictionary_set)(&mut self.0, &key.0, &val.0) }
    }

    /// Returns a reference to the value corresponding to the key.
    pub fn get_ref(&self, key: &Variant) -> &Variant {
        unsafe {
            Variant::cast_ref((get_api().godot_dictionary_operator_index_const)(
                &self.0, &key.0,
            ))
        }
    }

    /// Returns a mutable reference to the value corresponding to the key.
    pub fn get_mut_ref(&mut self, key: &Variant) -> &mut Variant {
        unsafe {
            Variant::cast_mut_ref((get_api().godot_dictionary_operator_index)(
                &mut self.0,
                &key.0,
            ))
        }
    }

    /// Returns a GodotString of the `Dictionary`.
    pub fn to_json(&self) -> GodotString {
        unsafe { GodotString((get_api().godot_dictionary_to_json)(&self.0)) }
    }

    /// Returns an array of the keys in the `Dictionary`.
    pub fn keys(&self) -> VariantArray {
        unsafe { VariantArray((get_api().godot_dictionary_keys)(&self.0)) }
    }

    /// Returns an array of the values in the `Dictionary`.
    pub fn values(&self) -> VariantArray {
        unsafe { VariantArray((get_api().godot_dictionary_values)(&self.0)) }
    }

    pub fn get_next(&self, key: &Variant) -> &Variant {
        unsafe { Variant::cast_ref((get_api().godot_dictionary_next)(&self.0, &key.0)) }
    }

    /// Return a hashed i32 value representing the dictionary's contents.
    pub fn hash(&self) -> i32 {
        unsafe { (get_api().godot_dictionary_hash)(&self.0) }
    }

    #[doc(hidden)]
    pub fn sys(&self) -> *const sys::godot_dictionary {
        &self.0
    }

    #[doc(hidden)]
    pub fn from_sys(sys: sys::godot_dictionary) -> Self {
        Dictionary(sys)
    }

    impl_common_methods! {
        /// Creates a new reference to this dictionary.
        pub fn new_ref(&self) -> Dictionary : godot_dictionary_new_copy;
    }
}

impl_basic_traits!(
    for Dictionary as godot_dictionary {
        Drop => godot_dictionary_destroy;
        Default => godot_dictionary_new;
        Eq => godot_dictionary_operator_equal;
    }
);

impl fmt::Debug for Dictionary {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.to_json().to_string().fmt(f)
    }
}

godot_test!(test_dictionary {
    use crate::VariantType;
    let foo = Variant::from_str("foo");
    let bar = Variant::from_str("bar");
    let nope = Variant::from_str("nope");

    let x = Variant::from_i64(42);
    let y = Variant::from_i64(1337);

    let mut dict = Dictionary::new();

    dict.set(&foo, &x);
    dict.set(&bar, &y);

    assert!(dict.contains(&foo));
    assert!(dict.contains(&bar));
    assert!(!dict.contains(&nope));

    let mut keys_array = dict.keys();
    let baz = Variant::from_str("baz");
    keys_array.push(&baz);
    dict.set(&baz, &x);

    assert!(dict.contains_all(&keys_array));

    dict.erase(&baz);

    assert!(!dict.contains_all(&keys_array));

    let variant = Variant::from_dictionary(&dict);
    assert!(variant.get_type() == VariantType::Dictionary);

    let dict2 = dict.new_ref();
    assert!(dict == dict2);
    assert!(dict2.contains(&foo));
    assert!(dict2.contains(&bar));

    if let Some(dic_variant) = variant.try_to_dictionary() {
        assert!(dic_variant == dict);
    } else {
        panic!("variant should be a Dictionary");
    }
});

// TODO: clear dictionaries without affecting clones
//godot_test!(test_dictionary_clone_clear {
//    let foo = Variant::from_str("foo");
//    let bar = Variant::from_str("bar");
//    let mut dict = Dictionary::new();
//
//    dict.set(&foo, &bar);
//    let dict_clone = dict.clone();
//    dict.clear();
//
//    assert!(dict.is_empty());
//    assert!(!dict_clone.is_empty());
//});