use godot_ffi as sys;
use sys::GodotFfi;
use crate::builtin::{GString, NodePath, StringName};
pub trait GodotStringExt {
fn to_gstring(&self) -> GString;
fn to_string_name(&self) -> StringName;
fn to_node_path(&self) -> NodePath {
self.to_gstring().to_node_path()
}
}
macro_rules! unsafe_builtin_convert {
($ctor:ident -> $Type:ty, $arg:expr) => {
unsafe_builtin_convert!(@impl sys::builtin_fn!($ctor), $Type, $arg)
};
(@thread_safe $ctor:ident -> $Type:ty, $arg:expr) => {
unsafe_builtin_convert!(@impl sys::thread_safe_lifecycle().$ctor, $Type, $arg)
};
(@impl $ctor:expr, $Type:ty, $arg:expr) => {{
let __arg = $arg;
unsafe {
<$Type>::new_with_uninit(|self_ptr| {
let ctor = $ctor;
let args = [__arg.sys()];
ctor(self_ptr, args.as_ptr());
})
}
}};
}
impl GodotStringExt for GString {
fn to_gstring(&self) -> GString {
self.clone()
}
fn to_string_name(&self) -> StringName {
unsafe_builtin_convert!(@thread_safe string_name_from_string -> StringName, self)
}
fn to_node_path(&self) -> NodePath {
unsafe_builtin_convert!(node_path_from_string -> NodePath, self)
}
}
impl GodotStringExt for StringName {
fn to_gstring(&self) -> GString {
unsafe_builtin_convert!(@thread_safe string_from_string_name -> GString, self)
}
fn to_string_name(&self) -> StringName {
self.clone()
}
}
impl GodotStringExt for NodePath {
fn to_gstring(&self) -> GString {
unsafe_builtin_convert!(@thread_safe string_from_node_path -> GString, self)
}
fn to_string_name(&self) -> StringName {
self.to_gstring().to_string_name()
}
fn to_node_path(&self) -> NodePath {
self.clone()
}
}
impl GodotStringExt for str {
fn to_gstring(&self) -> GString {
let utf8_bytes = self.as_bytes();
unsafe {
GString::new_with_string_uninit(|string_ptr| {
#[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
let ctor = sys::thread_safe().string_new_with_utf8_chars_and_len;
#[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
let ctor = sys::thread_safe().string_new_with_utf8_chars_and_len2;
ctor(
string_ptr,
utf8_bytes.as_ptr().cast::<std::ffi::c_char>(),
utf8_bytes.len() as i64,
);
})
}
}
fn to_string_name(&self) -> StringName {
let utf8_bytes = self.as_bytes();
unsafe {
StringName::new_with_string_uninit(|string_ptr| {
(sys::thread_safe().string_name_new_with_utf8_chars_and_len)(
string_ptr,
utf8_bytes.as_ptr().cast::<std::ffi::c_char>(),
utf8_bytes.len() as i64,
);
})
}
}
}
impl GodotStringExt for [char] {
fn to_gstring(&self) -> GString {
let chars = self;
unsafe {
GString::new_with_string_uninit(|string_ptr| {
(sys::thread_safe().string_new_with_utf32_chars_and_len)(
string_ptr,
chars.as_ptr().cast::<sys::char32_t>(),
chars.len() as i64,
);
})
}
}
fn to_string_name(&self) -> StringName {
self.to_gstring().to_string_name()
}
}