6
6
7
7
use godot_ffi as sys;
8
8
9
- use crate :: builtin:: { inner, FromVariant , ToVariant , Variant , VariantConversionError } ;
9
+ use crate :: builtin:: { inner, FromVariant , ToVariant , Variant } ;
10
10
use crate :: obj:: Share ;
11
- use std:: collections:: { HashMap , HashSet } ;
12
11
use std:: fmt;
13
- use sys:: types:: * ;
12
+ use std:: marker:: PhantomData ;
13
+ use std:: ptr:: addr_of_mut;
14
+ use sys:: types:: OpaqueDictionary ;
14
15
use sys:: { ffi_methods, interface_fn, GodotFfi } ;
15
16
16
17
use super :: Array ;
@@ -134,12 +135,12 @@ impl Dictionary {
134
135
}
135
136
136
137
/// Creates a new `Array` containing all the keys currently in the dictionary.
137
- pub fn keys ( & self ) -> Array {
138
+ pub fn keys_array ( & self ) -> Array {
138
139
self . as_inner ( ) . keys ( )
139
140
}
140
141
141
142
/// Creates a new `Array` containing all the values currently in the dictionary.
142
- pub fn values ( & self ) -> Array {
143
+ pub fn values_array ( & self ) -> Array {
143
144
self . as_inner ( ) . values ( )
144
145
}
145
146
@@ -195,6 +196,28 @@ impl Dictionary {
195
196
}
196
197
}
197
198
199
+ /// Returns an iterator over the key-value pairs of the `Dictionary`. The pairs are each of type `(Variant, Variant)`.
200
+ /// Each pair references the original `Dictionary`, but instead of a `&`-reference to key-value pairs as
201
+ /// you might expect, the iterator returns a (cheap, shallow) copy of each key-value pair.
202
+ ///
203
+ /// Note that it's possible to modify the `Dictionary` through another reference while iterating
204
+ /// over it. This will not result in unsoundness or crashes, but will cause the iterator to
205
+ /// behave in an unspecified way.
206
+ pub fn iter_shared ( & self ) -> Iter < ' _ > {
207
+ Iter :: new ( self )
208
+ }
209
+
210
+ /// Returns an iterator over the keys `Dictionary`. The keys are each of type `Variant`. Each key references
211
+ /// the original `Dictionary`, but instead of a `&`-reference to keys pairs as you might expect, the
212
+ /// iterator returns a (cheap, shallow) copy of each key pair.
213
+ ///
214
+ /// Note that it's possible to modify the `Dictionary` through another reference while iterating
215
+ /// over it. This will not result in unsoundness or crashes, but will cause the iterator to
216
+ /// behave in an unspecified way.
217
+ pub fn keys_shared ( & self ) -> Keys < ' _ > {
218
+ Keys :: new ( self )
219
+ }
220
+
198
221
#[ doc( hidden) ]
199
222
pub fn as_inner ( & self ) -> inner:: InnerDictionary {
200
223
inner:: InnerDictionary :: from_outer ( self )
@@ -217,41 +240,6 @@ where
217
240
}
218
241
}
219
242
220
- /// Convert this dictionary to a strongly typed rust `HashMap`. If the conversion
221
- /// fails for any key or value, an error is returned.
222
- ///
223
- /// Will be replaced by a proper iteration implementation.
224
- impl < K : FromVariant + Eq + std:: hash:: Hash , V : FromVariant > TryFrom < & Dictionary > for HashMap < K , V > {
225
- type Error = VariantConversionError ;
226
-
227
- fn try_from ( dictionary : & Dictionary ) -> Result < Self , Self :: Error > {
228
- // TODO: try to panic or something if modified while iterating
229
- // Though probably better to fix when implementing iteration proper
230
- dictionary
231
- . keys ( )
232
- . iter_shared ( )
233
- . zip ( dictionary. values ( ) . iter_shared ( ) )
234
- . map ( |( key, value) | Ok ( ( K :: try_from_variant ( & key) ?, V :: try_from_variant ( & value) ?) ) )
235
- . collect ( )
236
- }
237
- }
238
-
239
- /// Convert the keys of this dictionary to a strongly typed rust `HashSet`. If the
240
- /// conversion fails for any key, an error is returned.
241
- impl < K : FromVariant + Eq + std:: hash:: Hash > TryFrom < & Dictionary > for HashSet < K > {
242
- type Error = VariantConversionError ;
243
-
244
- fn try_from ( dictionary : & Dictionary ) -> Result < Self , Self :: Error > {
245
- // TODO: try to panic or something if modified while iterating
246
- // Though probably better to fix when implementing iteration proper
247
- dictionary
248
- . keys ( )
249
- . iter_shared ( )
250
- . map ( |key| K :: try_from_variant ( & key) )
251
- . collect ( )
252
- }
253
- }
254
-
255
243
/// Inserts all key-values from the iterator into the dictionary,
256
244
/// replacing values with existing keys with new values returned
257
245
/// from the iterator.
@@ -320,6 +308,210 @@ impl Share for Dictionary {
320
308
}
321
309
}
322
310
311
+ struct DictionaryIter < ' a > {
312
+ last_key : Option < Variant > ,
313
+ dictionary : & ' a Dictionary ,
314
+ is_first : bool ,
315
+ }
316
+
317
+ impl < ' a > DictionaryIter < ' a > {
318
+ fn new ( dictionary : & ' a Dictionary ) -> Self {
319
+ Self {
320
+ last_key : None ,
321
+ dictionary,
322
+ is_first : true ,
323
+ }
324
+ }
325
+
326
+ fn call_init ( dictionary : & Dictionary ) -> Option < Variant > {
327
+ // SAFETY:
328
+ // `dictionary` is a valid `Dictionary` since we have a reference to it,
329
+ // so this will call the implementation for dictionaries.
330
+ // `variant` is an initialized and valid `Variant`.
331
+ let variant: Variant = Variant :: nil ( ) ;
332
+ unsafe { Self :: call_iter_fn ( interface_fn ! ( variant_iter_init) , dictionary, variant) }
333
+ }
334
+
335
+ fn call_next ( dictionary : & Dictionary , last_key : Variant ) -> Option < Variant > {
336
+ // SAFETY:
337
+ // `dictionary` is a valid `Dictionary` since we have a reference to it,
338
+ // so this will call the implementation for dictionaries.
339
+ // `last_key` is an initialized and valid `Variant`, since we own a copy of it.
340
+ unsafe { Self :: call_iter_fn ( interface_fn ! ( variant_iter_next) , dictionary, last_key) }
341
+ }
342
+
343
+ /// # SAFETY:
344
+ /// `iter_fn` must point to a valid function that interprets the parameters according to their type specification.
345
+ unsafe fn call_iter_fn (
346
+ iter_fn : unsafe extern "C" fn (
347
+ sys:: GDExtensionConstVariantPtr ,
348
+ sys:: GDExtensionVariantPtr ,
349
+ * mut sys:: GDExtensionBool ,
350
+ ) -> sys:: GDExtensionBool ,
351
+ dictionary : & Dictionary ,
352
+ next_var : Variant ,
353
+ ) -> Option < Variant > {
354
+ let dictionary = dictionary. to_variant ( ) ;
355
+ let mut valid: u8 = 0 ;
356
+
357
+ let has_next = iter_fn (
358
+ dictionary. var_sys ( ) ,
359
+ next_var. var_sys ( ) ,
360
+ addr_of_mut ! ( valid) ,
361
+ ) ;
362
+ let valid = u8_to_bool ( valid) ;
363
+ let has_next = u8_to_bool ( has_next) ;
364
+
365
+ if has_next {
366
+ assert ! ( valid) ;
367
+ Some ( next_var)
368
+ } else {
369
+ None
370
+ }
371
+ }
372
+
373
+ fn next_key ( & mut self ) -> Option < Variant > {
374
+ let new_key = if self . is_first {
375
+ self . is_first = false ;
376
+ Self :: call_init ( self . dictionary )
377
+ } else {
378
+ Self :: call_next ( self . dictionary , self . last_key . take ( ) ?)
379
+ } ;
380
+ self . last_key = new_key. clone ( ) ;
381
+ new_key
382
+ }
383
+
384
+ fn next_key_value ( & mut self ) -> Option < ( Variant , Variant ) > {
385
+ let key = self . next_key ( ) ?;
386
+ if !self . dictionary . contains_key ( key. clone ( ) ) {
387
+ return None ;
388
+ }
389
+
390
+ let value = self . dictionary . as_inner ( ) . get ( key. clone ( ) , Variant :: nil ( ) ) ;
391
+ Some ( ( key, value) )
392
+ }
393
+ }
394
+
395
+ /// An iterator over key-value pairs from a `Dictionary`.
396
+ ///
397
+ /// See [Dictionary::iter_shared()] for more information about iteration over dictionaries.
398
+ pub struct Iter < ' a > {
399
+ iter : DictionaryIter < ' a > ,
400
+ }
401
+
402
+ impl < ' a > Iter < ' a > {
403
+ fn new ( dictionary : & ' a Dictionary ) -> Self {
404
+ Self {
405
+ iter : DictionaryIter :: new ( dictionary) ,
406
+ }
407
+ }
408
+
409
+ /// Creates an iterator that will convert each `(Variant, Variant)` key-value pair into
410
+ /// a `(K,V)` key-value pair, panicking upon failure to convert.
411
+ pub fn typed < K : FromVariant , V : FromVariant > ( self ) -> TypedIter < ' a , K , V > {
412
+ TypedIter :: from_untyped ( self )
413
+ }
414
+ }
415
+
416
+ impl < ' a > Iterator for Iter < ' a > {
417
+ type Item = ( Variant , Variant ) ;
418
+
419
+ fn next ( & mut self ) -> Option < Self :: Item > {
420
+ self . iter . next_key_value ( )
421
+ }
422
+ }
423
+
424
+ /// An iterator over keys from a `Dictionary`.
425
+ ///
426
+ /// See [Dictionary::keys_shared()] for more information about iteration over dictionaries.
427
+ pub struct Keys < ' a > {
428
+ iter : DictionaryIter < ' a > ,
429
+ }
430
+
431
+ impl < ' a > Keys < ' a > {
432
+ fn new ( dictionary : & ' a Dictionary ) -> Self {
433
+ Self {
434
+ iter : DictionaryIter :: new ( dictionary) ,
435
+ }
436
+ }
437
+
438
+ /// Creates an iterator that will convert each `Variant` key into a key of type `K`,
439
+ /// panicking upon failure to convert.
440
+ pub fn typed < K : FromVariant > ( self ) -> TypedKeys < ' a , K > {
441
+ TypedKeys :: from_untyped ( self )
442
+ }
443
+ }
444
+ impl < ' a > Iterator for Keys < ' a > {
445
+ type Item = Variant ;
446
+
447
+ fn next ( & mut self ) -> Option < Self :: Item > {
448
+ self . iter . next_key ( )
449
+ }
450
+ }
451
+
452
+ /// An iterator over key-value pairs from a `Dictionary` that will attempt to convert each
453
+ /// key-value pair into a `(K,V)`.
454
+ ///
455
+ /// See [Dictionary::iter_shared()] for more information about iteration over dictionaries.
456
+ pub struct TypedIter < ' a , K , V > {
457
+ iter : DictionaryIter < ' a > ,
458
+ _k : PhantomData < K > ,
459
+ _v : PhantomData < V > ,
460
+ }
461
+
462
+ impl < ' a , K , V > TypedIter < ' a , K , V > {
463
+ fn from_untyped ( value : Iter < ' a > ) -> Self {
464
+ Self {
465
+ iter : value. iter ,
466
+ _k : PhantomData ,
467
+ _v : PhantomData ,
468
+ }
469
+ }
470
+ }
471
+
472
+ impl < ' a , K : FromVariant , V : FromVariant > Iterator for TypedIter < ' a , K , V > {
473
+ type Item = ( K , V ) ;
474
+
475
+ fn next ( & mut self ) -> Option < Self :: Item > {
476
+ self . iter
477
+ . next_key_value ( )
478
+ . map ( |( key, value) | ( K :: from_variant ( & key) , V :: from_variant ( & value) ) )
479
+ }
480
+ }
481
+
482
+ /// An iterator over keys from a `Dictionary` that will attempt to convert each key into a `K`.
483
+ ///
484
+ /// See [Dictionary::iter_shared()] for more information about iteration over dictionaries.
485
+ pub struct TypedKeys < ' a , K > {
486
+ iter : DictionaryIter < ' a > ,
487
+ _k : PhantomData < K > ,
488
+ }
489
+
490
+ impl < ' a , K > TypedKeys < ' a , K > {
491
+ fn from_untyped ( value : Keys < ' a > ) -> Self {
492
+ Self {
493
+ iter : value. iter ,
494
+ _k : PhantomData ,
495
+ }
496
+ }
497
+ }
498
+
499
+ impl < ' a , K : FromVariant > Iterator for TypedKeys < ' a , K > {
500
+ type Item = K ;
501
+
502
+ fn next ( & mut self ) -> Option < Self :: Item > {
503
+ self . iter . next_key ( ) . map ( |k| K :: from_variant ( & k) )
504
+ }
505
+ }
506
+
507
+ fn u8_to_bool ( u : u8 ) -> bool {
508
+ match u {
509
+ 0 => false ,
510
+ 1 => true ,
511
+ _ => panic ! ( "Invalid boolean value {u}" ) ,
512
+ }
513
+ }
514
+
323
515
/// Creates a new dictionary with the given keys and values, the syntax mirrors
324
516
/// Godot's dictionary creation syntax.
325
517
///
0 commit comments