Skip to content

Commit 54ac2fc

Browse files
committed
Document some various stuff better
Cleanup a couple of things
1 parent be8a883 commit 54ac2fc

File tree

8 files changed

+55
-19
lines changed

8 files changed

+55
-19
lines changed

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

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ pub use signature::*;
2020

2121
pub(crate) use godot_convert::convert_error::*;
2222

23+
use crate::builtin::*;
2324
use crate::engine::global::{self, PropertyHint, PropertyUsageFlags};
25+
use crate::property::Var;
2426
use crate::property::{Export, PropertyHintInfo};
25-
use crate::{builtin::*, property::Var};
2627
use godot_ffi as sys;
2728
use registration::method::MethodParamOrReturnInfo;
2829
use sys::{GodotFfi, GodotNullableFfi};
@@ -278,7 +279,7 @@ pub struct PropertyInfo {
278279

279280
/// Which class this property is.
280281
///
281-
/// This should be set to [`ClassName::none()`] unless the variant type is object. You can use
282+
/// This should be set to [`ClassName::none()`] unless the variant type is `Object`. You can use
282283
/// [`GodotClass::class_name()`](crate::obj::GodotClass::class_name()) to get the right name to use here.
283284
pub class_name: ClassName,
284285

@@ -317,7 +318,7 @@ impl PropertyInfo {
317318

318319
/// Change the `hint` and `hint_string` to be the given `hint_info`.
319320
///
320-
/// See [`export_info_functions`](crate::property::export_info_function) for functions that return appropriate `PropertyHintInfo`s for
321+
/// See [`export_info_functions`](crate::property::export_info_functions) for functions that return appropriate `PropertyHintInfo`s for
321322
/// various Godot annotations.
322323
///
323324
/// # Examples
@@ -326,11 +327,11 @@ impl PropertyInfo {
326327
///
327328
// TODO: Make this nicer to use.
328329
/// ```no_run
329-
/// # use crate::property::export_info_function;
330-
/// # use crate::builtin::meta::PropertyInfo;
330+
/// use godot::register::property::export_info_functions;
331+
/// use godot::builtin::meta::PropertyInfo;
331332
///
332333
/// let property = PropertyInfo::new_export::<f64>("my_range_property")
333-
/// .with_hint_info(export_info_function::export_range(
334+
/// .with_hint_info(export_info_functions::export_range(
334335
/// 0.0,
335336
/// 10.0,
336337
/// Some(0.1),
@@ -340,7 +341,7 @@ impl PropertyInfo {
340341
/// false,
341342
/// false,
342343
/// false,
343-
/// ))
344+
/// ));
344345
/// ```
345346
pub fn with_hint_info(self, hint_info: PropertyHintInfo) -> Self {
346347
let PropertyHintInfo { hint, hint_string } = hint_info;
@@ -415,7 +416,7 @@ impl PropertyInfo {
415416
/// [`free_owned_property_sys`](Self::free_owned_property_sys).
416417
///
417418
/// This will leak memory unless used together with `free_owned_property_sys`.
418-
pub fn into_owned_property_sys(self) -> sys::GDExtensionPropertyInfo {
419+
pub(crate) fn into_owned_property_sys(self) -> sys::GDExtensionPropertyInfo {
419420
use crate::obj::EngineBitfield as _;
420421
use crate::obj::EngineEnum as _;
421422

@@ -433,9 +434,9 @@ impl PropertyInfo {
433434
///
434435
/// # Safety
435436
///
436-
/// * Must only be used on a struct returned from a call to [`into_owned_property_sys`], without modification.
437+
/// * Must only be used on a struct returned from a call to `into_owned_property_sys`, without modification.
437438
/// * Must not be called more than once on a `sys::GDExtensionPropertyInfo` struct.
438-
pub unsafe fn free_owned_property_sys(info: sys::GDExtensionPropertyInfo) {
439+
pub(crate) unsafe fn free_owned_property_sys(info: sys::GDExtensionPropertyInfo) {
439440
// SAFETY: This function was called on a pointer returned from `into_owned_property_sys`, thus both `info.name` and
440441
// `info.hint_string` were created from calls to `into_owned_string_sys` on their respective types.
441442
// Additionally this function isn't called more than once on a struct containing the same `name` or `hint_string` pointers.

godot-core/src/builtin/string/gstring.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ impl GString {
175175
sys::static_assert_eq_size_align!(StringName, sys::types::OpaqueString);
176176

177177
let ptr = ptr.cast::<Self>();
178+
179+
// SAFETY: `ptr` was returned from a call to `into_owned_string_sys`, which means it was created by a call to
180+
// `Box::into_raw`, thus we can use `Box::from_raw` here. Additionally this is only called once on this pointer.
178181
let boxed = unsafe { Box::from_raw(ptr) };
179182
*boxed
180183
}

godot-core/src/builtin/string/string_name.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ impl StringName {
134134
sys::static_assert_eq_size_align!(StringName, sys::types::OpaqueStringName);
135135

136136
let ptr = ptr.cast::<Self>();
137+
138+
// SAFETY: `ptr` was returned from a call to `into_owned_string_sys`, which means it was created by a call to
139+
// `Box::into_raw`, thus we can use `Box::from_raw` here. Additionally this is only called once on this pointer.
137140
let boxed = unsafe { Box::from_raw(ptr) };
138141
*boxed
139142
}

godot-core/src/registry/callbacks.rs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@ pub unsafe extern "C" fn unreference<T: GodotClass>(instance: sys::GDExtensionCl
201201
storage.on_dec_ref();
202202
}
203203

204+
/// # Safety
205+
///
206+
/// Must only be called by Godot as a callback for `get_property_list` for a rust-defined class of type `T`.
204207
#[deny(unsafe_op_in_unsafe_fn)]
205208
pub unsafe extern "C" fn get_property_list<T: cap::GodotGetPropertyList>(
206209
instance: sys::GDExtensionClassInstancePtr,
@@ -216,6 +219,7 @@ pub unsafe extern "C" fn get_property_list<T: cap::GodotGetPropertyList>(
216219
.map(|prop| prop.into_owned_property_sys())
217220
.collect();
218221

222+
// SAFETY: Godot ensures that `count` is initialized and valid to write into.
219223
unsafe {
220224
*count = property_list_sys
221225
.len()
@@ -226,20 +230,32 @@ pub unsafe extern "C" fn get_property_list<T: cap::GodotGetPropertyList>(
226230
Box::leak(property_list_sys).as_mut_ptr()
227231
}
228232

233+
/// # Safety
234+
///
235+
/// - Must only be called by Godot as a callback for `free_property_list` for a rust-defined class of type `T`.
236+
/// - Must only be passed to Godot as a callback when [`get_property_list`] is the corresponding `get_property_list` callback.
229237
#[deny(unsafe_op_in_unsafe_fn)]
230238
pub unsafe extern "C" fn free_property_list<T: cap::GodotGetPropertyList>(
231239
_instance: sys::GDExtensionClassInstancePtr,
232240
list: *const sys::GDExtensionPropertyInfo,
233241
count: u32,
234242
) {
235243
let list = list as *mut sys::GDExtensionPropertyInfo;
236-
let property_list_sys = unsafe {
237-
Box::from_raw(std::slice::from_raw_parts_mut(
238-
list,
239-
count.try_into().expect("`u32` should fit in `usize`"),
240-
))
244+
245+
// SAFETY: `list` comes from `get_property_list` above, and `count` also comes from the same function.
246+
// This means that `list` is a pointer to a `&[sys::GDExtensionPropertyInfo]` slice of length `count`.
247+
// This means all the preconditions of this function are satisfied except uniqueness of this point.
248+
// Uniqueness is guaranteed as Godot called this function at a point where the list is no longer accessed
249+
// through any other pointer, and we dont access the slice through any other pointer after this call either.
250+
let property_list_slice = unsafe {
251+
std::slice::from_raw_parts_mut(list, count.try_into().expect("`u32` should fit in `usize`"))
241252
};
242253

254+
// SAFETY: This slice was created by calling `Box::leak` on a `Box<[sys::GDExtensionPropertyInfo]>`, we can thus
255+
// call `Box::from_raw` on this slice to get back the original boxed slice.
256+
// Note that this relies on coercion of `&mut` -> `*mut`.
257+
let property_list_sys = unsafe { Box::from_raw(property_list_slice) };
258+
243259
for property_info in property_list_sys.iter() {
244260
// SAFETY: The structs contained in this list were all returned from `into_owned_property_sys`.
245261
// We only call this method once for each struct and for each list.
@@ -267,6 +283,9 @@ unsafe fn raw_property_get_revert<T: cap::GodotPropertyGetRevert>(
267283
T::__godot_property_get_revert(&*instance, property.clone())
268284
}
269285

286+
/// # Safety
287+
///
288+
/// - Must only be called by Godot as a callback for `property_can_revert` for a rust-defined class of type `T`.
270289
#[deny(unsafe_op_in_unsafe_fn)]
271290
pub unsafe extern "C" fn property_can_revert<T: cap::GodotPropertyGetRevert>(
272291
instance: sys::GDExtensionClassInstancePtr,
@@ -278,6 +297,9 @@ pub unsafe extern "C" fn property_can_revert<T: cap::GodotPropertyGetRevert>(
278297
revert.is_some() as sys::GDExtensionBool
279298
}
280299

300+
/// # Safety
301+
///
302+
/// - Must only be called by Godot as a callback for `property_get_revert` for a rust-defined class of type `T`.
281303
#[deny(unsafe_op_in_unsafe_fn)]
282304
pub unsafe extern "C" fn property_get_revert<T: cap::GodotPropertyGetRevert>(
283305
instance: sys::GDExtensionClassInstancePtr,

godot-core/src/registry/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ pub enum PluginItem {
191191
) -> *const sys::GDExtensionPropertyInfo,
192192
>,
193193

194+
// We do not support using this in Godot < 4.3, however it's easier to leave this in and fail elsewhere when attempting to use
195+
// this in Godot < 4.3.
194196
#[cfg(before_api = "4.3")]
195197
user_free_property_list_fn: Option<
196198
unsafe extern "C" fn(

godot-core/src/registry/property.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ impl PropertyHintInfo {
139139

140140
/// Functions used to translate user-provided arguments into export hints.
141141
///
142-
/// Each function is named the same as the equivalent Godot annotation. E.g `@export_range` is `fn export_range`.
142+
/// Each function is named the same as the equivalent Godot annotation. For instance `@export_range` in Godot is `fn export_range` here.
143143
pub mod export_info_functions {
144144
use crate::builtin::GString;
145145
use crate::engine::global::PropertyHint;
@@ -247,7 +247,8 @@ pub mod export_info_functions {
247247
/// # Examples
248248
///
249249
/// ```no_run
250-
/// export_enum(&[("a", None), ("b", "Some(10)")]);
250+
/// # use godot::register::property::export_info_functions::export_enum;
251+
/// export_enum(&[("a", None), ("b", Some(10))]);
251252
/// ```
252253
pub fn export_enum<T>(variants: &[T]) -> PropertyHintInfo
253254
where
@@ -279,7 +280,8 @@ pub mod export_info_functions {
279280
/// # Examples
280281
///
281282
/// ```no_run
282-
/// export_flags(&[("a", None), ("b", "Some(10)")]);
283+
/// # use godot::register::property::export_info_functions::export_flags;
284+
/// export_flags(&[("a", None), ("b", Some(10))]);
283285
/// ```
284286
pub fn export_flags<T>(bits: &[T]) -> PropertyHintInfo
285287
where

godot-macros/src/class/data_models/interface_trait_impl.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,8 @@ pub fn transform_trait_impl(original_impl: venial::Impl) -> ParseResult<TokenStr
228228
#(#cfg_attrs)*
229229
impl ::godot::obj::cap::GodotGetPropertyList for #class_name {
230230
fn __godot_get_property_list(&mut self) -> Vec<::godot::builtin::meta::PropertyInfo> {
231-
// Only supported in godot api > 4.3. If support is added for earlier versions this is still needed.
231+
// `get_property_list` is only supported in Godot API >= 4.3. If we add support for `get_property_list` to earlier
232+
// versions of Godot then this code is still needed and should be uncommented.
232233
//
233234
// use ::godot::obj::UserClass as _;
234235
//

itest/rust/src/object_tests/virtual_methods_test.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ impl IRefCounted for RevertTest {
296296
match String::from(property).as_str() {
297297
"property_not_revert" => None,
298298
"property_do_revert" => Some(GString::from("hello!").to_variant()),
299+
// No UB or anything else like a crash or panic should happen when `property_can_revert` and `property_get_revert` return
300+
// inconsistent values, but in case something like that happens we should be able to detect it through this function.
299301
"property_changes" => {
300302
if INC.fetch_add(1, std::sync::atomic::Ordering::AcqRel) % 2 == 0 {
301303
None

0 commit comments

Comments
 (0)