Skip to content

Commit 47fb204

Browse files
authored
Merge pull request #738 from godot-rust/qol/streamlined-modules-5
Streamline modules - part V: `IoError`, `Array`/`Dictionary` docs
2 parents 3d7575f + 359ec1b commit 47fb204

File tree

11 files changed

+130
-22
lines changed

11 files changed

+130
-22
lines changed

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

+54
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,60 @@ use sys::{ffi_methods, interface_fn, GodotFfi};
4545
/// If you want to create a copy of the data, use [`duplicate_shallow()`][Self::duplicate_shallow]
4646
/// or [`duplicate_deep()`][Self::duplicate_deep].
4747
///
48+
/// # Typed array example
49+
///
50+
/// ```no_run
51+
/// # use godot::prelude::*;
52+
/// // Create typed Array<i64> and add values.
53+
/// let mut array = Array::new();
54+
/// array.push(10);
55+
/// array.push(20);
56+
/// array.push(30);
57+
///
58+
/// // Or create the same array in a single expression.
59+
/// let array = array![10, 20, 30];
60+
///
61+
/// // Access elements.
62+
/// let value: i64 = array.at(0); // 10
63+
/// let maybe: Option<i64> = array.get(3); // None
64+
///
65+
/// // Iterate over i64 elements.
66+
/// for value in array.iter_shared() {
67+
/// println!("{value}");
68+
/// }
69+
///
70+
/// // Clone array (shares the reference), and overwrite elements through clone.
71+
/// let mut cloned = array.clone();
72+
/// cloned.set(0, 50); // [50, 20, 30]
73+
/// cloned.remove(1); // [50, 30]
74+
/// cloned.pop(); // [50]
75+
///
76+
/// // Changes will be reflected in the original array.
77+
/// assert_eq!(array.len(), 1);
78+
/// assert_eq!(array.front(), Some(50));
79+
/// ```
80+
///
81+
/// # Untyped array example
82+
///
83+
/// ```no_run
84+
/// # use godot::prelude::*;
85+
/// // VariantArray allows dynamic element types.
86+
/// let mut array = VariantArray::new();
87+
/// array.push(10.to_variant());
88+
/// array.push("Hello".to_variant());
89+
///
90+
/// // Or equivalent, use the `varray!` macro which converts each element.
91+
/// let array = varray![10, "Hello"];
92+
///
93+
/// // Access elements.
94+
/// let value: Variant = array.at(0);
95+
/// let value: i64 = array.at(0).to(); // Variant::to() extracts i64.
96+
/// let maybe: Result<i64, _> = array.at(1).try_to(); // "Hello" is not i64 -> Err.
97+
/// let maybe: Option<Variant> = array.get(3);
98+
///
99+
/// // ...and so on.
100+
/// ```
101+
///
48102
/// # Thread safety
49103
///
50104
/// Usage is safe if the `Array` is used on a single thread only. Concurrent reads on

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

+50-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,53 @@ use std::{fmt, ptr};
2323
/// The keys and values of the dictionary are all `Variant`s, so they can be of different types.
2424
/// Variants are designed to be generally cheap to clone.
2525
///
26+
/// # Dictionary example
27+
///
28+
/// ```no_run
29+
/// # use godot::prelude::*;
30+
/// // Create empty dictionary and add key-values pairs.
31+
/// let mut dict = Dictionary::new();
32+
/// dict.set("str", "Hello");
33+
/// dict.set("num", 23);
34+
///
35+
/// // Keys don't need to be strings.
36+
/// let coord = Vector2i::new(0, 1);
37+
/// dict.set(coord, "Tile77");
38+
///
39+
/// // Or create the same dictionary in a single expression.
40+
/// let dict = dict! {
41+
/// "str": "Hello",
42+
/// "num": 23,
43+
/// coord: "Tile77",
44+
/// };
45+
///
46+
/// // Access elements.
47+
/// let value: Variant = dict.at("str");
48+
/// let value: GString = dict.at("str").to(); // Variant::to() extracts GString.
49+
/// let maybe: Option<Variant> = dict.get("absent_key");
50+
///
51+
/// // Iterate over key-value pairs as (Variant, Variant).
52+
/// for (key, value) in dict.iter_shared() {
53+
/// println!("{key} => {value}");
54+
/// }
55+
///
56+
/// // Use typed::<K, V>() to get typed iterators.
57+
/// for (key, value) in dict.iter_shared().typed::<GString, Variant>() {
58+
/// println!("{key} => {value}");
59+
/// }
60+
///
61+
/// // Clone dictionary (shares the reference), and overwrite elements through clone.
62+
/// let mut cloned = dict.clone();
63+
/// cloned.remove("num");
64+
///
65+
/// // Overwrite with set(); use insert() to get the previous value.
66+
/// let prev = cloned.insert("str", "Goodbye"); // prev == Some("Hello")
67+
///
68+
/// // Changes will be reflected in the original dictionary.
69+
/// assert_eq!(dict.at("str"), "Goodbye".to_variant());
70+
/// assert_eq!(dict.get("num"), None);
71+
/// ```
72+
///
2673
/// # Thread safety
2774
///
2875
/// The same principles apply as for [`VariantArray`]. Consult its documentation for details.
@@ -160,6 +207,7 @@ impl Dictionary {
160207
/// Insert a value at the given key, returning the previous value for that key (if available).
161208
///
162209
/// If you don't need the previous value, use [`set()`][Self::set] instead.
210+
#[must_use]
163211
pub fn insert<K: ToGodot, V: ToGodot>(&mut self, key: K, value: V) -> Option<Variant> {
164212
let key = key.to_variant();
165213
let old_value = self.get(key.clone());
@@ -245,7 +293,7 @@ impl Dictionary {
245293
/// Note that it's possible to modify the `Dictionary` through another reference while iterating over it. This will not result in
246294
/// unsoundness or crashes, but will cause the iterator to behave in an unspecified way.
247295
///
248-
/// Use `iter_shared().typed::<K, V>()` to iterate over `(K, V)` pairs instead.
296+
/// Use `dict.iter_shared().typed::<K, V>()` to iterate over `(K, V)` pairs instead.
249297
pub fn iter_shared(&self) -> Iter<'_> {
250298
Iter::new(self)
251299
}
@@ -258,7 +306,7 @@ impl Dictionary {
258306
/// Note that it's possible to modify the `Dictionary` through another reference while iterating over it. This will not result in
259307
/// unsoundness or crashes, but will cause the iterator to behave in an unspecified way.
260308
///
261-
/// Use `.keys_shared.typed::<K>()` to iterate over `K` keys instead.
309+
/// Use `dict.keys_shared().typed::<K>()` to iterate over `K` keys instead.
262310
pub fn keys_shared(&self) -> Keys<'_> {
263311
Keys::new(self)
264312
}

godot-core/src/builtin/quaternion.rs

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ use crate::builtin::math::{ApproxEq, FloatExt, GlamConv, GlamType};
1212
use crate::builtin::{inner, real, Basis, EulerOrder, RQuat, RealConv, Vector3};
1313
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
1414

15+
/// Unit quaternion to represent 3D rotations.
16+
///
17+
/// See also [`Quaternion`](https://docs.godotengine.org/en/stable/classes/class_quaternion.html) in the Godot documentation.
1518
#[derive(Copy, Clone, PartialEq, Debug)]
1619
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1720
#[repr(C)]

godot-core/src/engine/mod.rs renamed to godot-core/src/engine.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ pub use crate::obj::script::SiMut;
4141
#[deprecated = "`GFile` has been moved to `godot::tools`."]
4242
pub use crate::tools::GFile;
4343

44-
#[deprecated = "`IoError` has been moved to `godot::tools`."]
45-
pub use crate::tools::IoError;
44+
#[deprecated = "`IoError` has been moved to `godot::meta::error`."]
45+
pub use crate::meta::error::IoError;
4646

4747
#[deprecated = "`save` has been moved to `godot::global`."]
4848
pub use crate::tools::save;

godot-core/src/tools/io_error.rs renamed to godot-core/src/meta/error/io_error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use std::error::Error;
99
use std::fmt;
1010

11-
use crate::gen::classes::FileAccess;
11+
use crate::classes::FileAccess;
1212
use crate::global::Error as GodotError;
1313
use crate::obj::Gd;
1414

godot-core/src/meta/error/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
1010
mod call_error;
1111
mod convert_error;
12+
mod io_error;
1213

1314
pub use call_error::*;
1415
pub use convert_error::*;
16+
pub use io_error::*;

godot-core/src/tools/gfile.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use crate::classes::file_access::{CompressionMode, ModeFlags};
1010
use crate::classes::FileAccess;
1111
use crate::global::Error;
1212
use crate::obj::Gd;
13-
use crate::tools::IoError;
1413

14+
use crate::engine::IoError;
1515
use std::cmp;
1616
use std::io::{BufRead, ErrorKind, Read, Seek, SeekFrom, Write};
1717

godot-core/src/tools/mod.rs

-2
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,9 @@
1111
//! or better integrated with Rust.
1212
1313
mod gfile;
14-
mod io_error;
1514
mod save_load;
1615
mod translate;
1716

1817
pub use gfile::*;
19-
pub use io_error::*;
2018
pub use save_load::*;
2119
pub use translate::*;

godot-core/src/tools/save_load.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88
use crate::builtin::GString;
99
use crate::classes::{Resource, ResourceLoader, ResourceSaver};
10+
use crate::engine::IoError;
1011
use crate::global::Error as GodotError;
1112
use crate::obj::{Gd, Inherits};
12-
use crate::tools::IoError;
1313

1414
/// ⚠️ Loads a resource from the filesystem located at `path`, panicking on error.
1515
///

godot/src/prelude.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ pub use super::register::{godot_api, Export, GodotClass, GodotConvert, Var};
1212

1313
pub use super::builtin::__prelude_reexport::*;
1414
pub use super::builtin::math::FloatExt as _;
15-
pub use super::meta::{FromGodot, ToGodot};
15+
pub use super::meta::error::{ConvertError, IoError};
16+
pub use super::meta::{FromGodot, GodotConvert, ToGodot};
1617

1718
pub use super::classes::{
1819
AudioStreamPlayer, Camera2D, Camera3D, IAudioStreamPlayer, ICamera2D, ICamera3D, INode,
@@ -22,7 +23,7 @@ pub use super::classes::{
2223
pub use super::global::{
2324
godot_error, godot_print, godot_print_rich, godot_script_error, godot_warn,
2425
};
25-
pub use super::tools::{load, save, try_load, try_save, GFile, IoError};
26+
pub use super::tools::{load, save, try_load, try_save, GFile};
2627

2728
pub use super::init::{gdextension, ExtensionLibrary, InitLevel};
2829
pub use super::obj::{Base, Gd, GdMut, GdRef, GodotClass, Inherits, InstanceId, OnReady};

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

+13-11
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ fn dictionary_clone() {
101101

102102
#[allow(clippy::redundant_clone)]
103103
let clone = dictionary.clone();
104-
Dictionary::from_variant(&clone.get("bar").unwrap()).insert("final", 4);
104+
Dictionary::from_variant(&clone.get("bar").unwrap()).set("final", 4);
105105
assert_eq!(subdictionary.get("final"), Some(4.to_variant()));
106106
}
107107

@@ -147,7 +147,7 @@ fn dictionary_duplicate_deep() {
147147
"bar": subdictionary.clone()
148148
};
149149
let clone = dictionary.duplicate_deep();
150-
Dictionary::from_variant(&clone.get("bar").unwrap()).insert("baz", 4);
150+
Dictionary::from_variant(&clone.get("bar").unwrap()).set("baz", 4);
151151
assert_eq!(
152152
subdictionary.get("baz"),
153153
Some(true.to_variant()),
@@ -167,14 +167,14 @@ fn dictionary_duplicate_shallow() {
167167
};
168168

169169
let mut clone = dictionary.duplicate_shallow();
170-
Dictionary::from_variant(&clone.get("bar").unwrap()).insert("baz", 4);
170+
Dictionary::from_variant(&clone.get("bar").unwrap()).set("baz", 4);
171171
assert_eq!(
172172
subdictionary.get("baz"),
173173
Some(4.to_variant()),
174174
"key = \"baz\""
175175
);
176176

177-
clone.insert("foo", false.to_variant());
177+
clone.set("foo", false);
178178
assert_eq!(dictionary.get("foo"), Some(0.to_variant()));
179179
assert_eq!(clone.get("foo"), Some(false.to_variant()));
180180
}
@@ -256,13 +256,13 @@ fn dictionary_insert_multiple() {
256256
let mut dictionary = dict! {};
257257
assert!(dictionary.is_empty());
258258

259-
dictionary.insert(1, true);
259+
dictionary.set(1, true);
260260
assert_eq!(dictionary.get(1), Some(true.to_variant()));
261261

262262
let mut other = dict! {};
263263
assert!(other.is_empty());
264264

265-
other.insert(1, 2);
265+
other.set(1, 2);
266266
assert_eq!(other.get(1), Some(2.to_variant()));
267267
}
268268
#[itest]
@@ -430,7 +430,7 @@ fn dictionary_iter_size_hint() {
430430
assert_eq!(iter.size_hint(), (0, Some(0)));
431431

432432
// Insertion while iterating is allowed and might change size hint.
433-
dictionary_clone.insert("new_key", "soma_val");
433+
dictionary_clone.set("new_key", "soma_val");
434434
assert_eq!(iter.size_hint(), (1, Some(1)));
435435

436436
// Removal while iterating is also allowed and might change size_hint.
@@ -465,7 +465,9 @@ fn dictionary_iter_insert() {
465465
iter.next();
466466
iter.next();
467467

468-
dictionary2.insert("new_key", 10);
468+
let prev = dictionary2.insert("new_key", 10);
469+
assert_eq!(prev, None);
470+
469471
let v: Vec<_> = iter.collect();
470472
assert_eq!(dictionary.len(), 5);
471473
assert!(dictionary.contains_key("new_key"));
@@ -488,7 +490,7 @@ fn dictionary_iter_insert_after_completion() {
488490
}
489491
assert_eq!(iter.next(), None);
490492

491-
dictionary2.insert("new_key", 10);
493+
dictionary2.set("new_key", 10);
492494
assert_eq!(iter.next(), None);
493495
assert_eq!(dictionary.len(), 5);
494496
}
@@ -504,7 +506,7 @@ fn dictionary_iter_big() {
504506
for _ in 0..16 {
505507
iter.next();
506508
}
507-
dictionary2.insert("a", "b");
509+
dictionary2.set("a", "b");
508510
}
509511
dictionary2.clear();
510512
dictionary2.extend((0..64).zip(0..64));
@@ -531,7 +533,7 @@ fn dictionary_iter_simultaneous() {
531533
})
532534
.collect();
533535

534-
assert!(map.len() == 4);
536+
assert_eq!(map.len(), 4);
535537

536538
let mut tens = 0;
537539
let mut trues = 0;

0 commit comments

Comments
 (0)