Skip to content

Commit

Permalink
godot-ffi: move symbols into toolbox + gdextension_plus modules
Browse files Browse the repository at this point in the history
  • Loading branch information
Bromeon committed Jul 30, 2023
1 parent d0f2a86 commit 1cf6b2d
Show file tree
Hide file tree
Showing 4 changed files with 285 additions and 250 deletions.
3 changes: 2 additions & 1 deletion ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ However, it is still in an early stage and there are certain things to keep in m

> **Warning**
> The public API introduces breaking changes from time to time. Most of these are motivated by new features and
> improved ergonomics for existing ones. Once we are on crates.io, we will adhere to SemVer for releases.
> improved ergonomics for existing ones. See also [API stability] in the book.
**Features:** While most Godot features are available, some less commonly used ones are missing. See [#24] for an up-to-date overview.
At this point, there is **no** support for Android, iOS or WASM. Contributions are very welcome!
Expand Down Expand Up @@ -67,6 +67,7 @@ Contributions are very welcome! If you want to help out, see [`Contributing.md`]
[#24]: https://github.com/godot-rust/gdext/issues/24
[`gdnative`]: https://github.com/godot-rust/gdnative
[API Docs]: https://godot-rust.github.io/docs/gdext
[API stability]: https://godot-rust.github.io/book/gdext/advanced/compatibility.html#rust-api-stability
[book]: https://godot-rust.github.io/book/gdext
[Discord]: https://discord.gg/aKUCJ8rJsc
[dodge-the-creeps]: examples/dodge-the-creeps
Expand Down
110 changes: 110 additions & 0 deletions godot-ffi/src/gdextension_plus.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

//! Extra functionality to enrich low-level C API.

use crate::gen::gdextension_interface::*;
use crate::VariantType;

// ----------------------------------------------------------------------------------------------------------------------------------------------
// Static checks

// The impls only compile if those are different types -- ensures type safety through patch
trait Distinct {}
impl Distinct for GDExtensionVariantPtr {}
impl Distinct for GDExtensionTypePtr {}
impl Distinct for GDExtensionConstTypePtr {}

// ----------------------------------------------------------------------------------------------------------------------------------------------
// Extension traits for conversion

/// Convert a GDExtension pointer type to its uninitialized version.
pub trait AsUninit {
type Ptr;

#[allow(clippy::wrong_self_convention)]
fn as_uninit(self) -> Self::Ptr;

fn force_init(uninit: Self::Ptr) -> Self;
}

macro_rules! impl_as_uninit {
($Ptr:ty, $Uninit:ty) => {
impl AsUninit for $Ptr {
type Ptr = $Uninit;

fn as_uninit(self) -> $Uninit {
self as $Uninit
}

fn force_init(uninit: Self::Ptr) -> Self {
uninit as Self
}
}
};
}

#[rustfmt::skip]
impl_as_uninit!(GDExtensionStringNamePtr, GDExtensionUninitializedStringNamePtr);
impl_as_uninit!(GDExtensionVariantPtr, GDExtensionUninitializedVariantPtr);
impl_as_uninit!(GDExtensionStringPtr, GDExtensionUninitializedStringPtr);
impl_as_uninit!(GDExtensionObjectPtr, GDExtensionUninitializedObjectPtr);
impl_as_uninit!(GDExtensionTypePtr, GDExtensionUninitializedTypePtr);

// ----------------------------------------------------------------------------------------------------------------------------------------------
// Helper functions

#[doc(hidden)]
#[inline]
pub fn default_call_error() -> GDExtensionCallError {
GDExtensionCallError {
error: GDEXTENSION_CALL_OK,
argument: -1,
expected: -1,
}
}

#[doc(hidden)]
#[inline]
#[track_caller] // panic message points to call site
pub fn panic_call_error(
err: &GDExtensionCallError,
function_name: &str,
arg_types: &[VariantType],
) -> ! {
debug_assert_ne!(err.error, GDEXTENSION_CALL_OK); // already checked outside

let GDExtensionCallError {
error,
argument,
expected,
} = *err;

let argc = arg_types.len();
let reason = match error {
GDEXTENSION_CALL_ERROR_INVALID_METHOD => "method not found".to_string(),
GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT => {
let from = arg_types[argument as usize];
let to = VariantType::from_sys(expected as GDExtensionVariantType);
let i = argument + 1;

format!("cannot convert argument #{i} from {from:?} to {to:?}")
}
GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS => {
format!("too many arguments; expected {argument}, but called with {argc}")
}
GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS => {
format!("too few arguments; expected {argument}, but called with {argc}")
}
GDEXTENSION_CALL_ERROR_INSTANCE_IS_NULL => "instance is null".to_string(),
GDEXTENSION_CALL_ERROR_METHOD_NOT_CONST => "method is not const".to_string(), // not handled in Godot
_ => format!("unknown reason (error code {error})"),
};

// Note: Godot also outputs thread ID
// In Godot source: variant.cpp:3043 or core_bind.cpp:2742
panic!("Function call failed: {function_name} -- {reason}.");
}
Loading

0 comments on commit 1cf6b2d

Please sign in to comment.