use crate::builtin::{GString, StringName, VariantType};
use crate::meta::ClassId;
use crate::obj::{Bounds, EngineBitfield, EngineEnum, GodotClass, bounds};
use crate::registry::info::{PropertyHint, PropertyUsageFlags};
use crate::registry::property::{Export, Var};
use crate::{classes, sys};
#[derive(Clone, Debug)]
pub struct PropertyInfo {
pub variant_type: VariantType,
pub class_name: StringName,
pub property_name: StringName,
pub hint_info: PropertyHintInfo,
pub usage: PropertyUsageFlags,
}
impl PropertyInfo {
pub fn new_var<T: Var>(property_name: &str) -> Self {
T::godot_shape().to_var_property(property_name)
}
pub fn new_export<T: Export>(property_name: &str) -> Self {
T::godot_shape().to_export_property(property_name)
}
pub fn with_hint_info(self, hint_info: PropertyHintInfo) -> Self {
Self { hint_info, ..self }
}
pub fn new_group(group_name: &str, group_prefix: &str) -> Self {
Self {
variant_type: VariantType::NIL,
class_name: StringName::default(),
property_name: group_name.into(),
hint_info: PropertyHintInfo {
hint: PropertyHint::NONE,
hint_string: group_prefix.into(),
},
usage: PropertyUsageFlags::GROUP,
}
}
pub fn new_subgroup(subgroup_name: &str, subgroup_prefix: &str) -> Self {
Self {
variant_type: VariantType::NIL,
class_name: StringName::default(),
property_name: subgroup_name.into(),
hint_info: PropertyHintInfo {
hint: PropertyHint::NONE,
hint_string: subgroup_prefix.into(),
},
usage: PropertyUsageFlags::SUBGROUP,
}
}
#[doc(hidden)]
pub fn property_sys(&self) -> sys::GDExtensionPropertyInfo {
use crate::obj::{EngineBitfield as _, EngineEnum as _};
sys::GDExtensionPropertyInfo {
type_: self.variant_type.sys(),
name: sys::SysPtr::force_mut(self.property_name.string_sys()),
class_name: sys::SysPtr::force_mut(self.class_name.string_sys()),
hint: u32::try_from(self.hint_info.hint.ord()).expect("hint.ord()"),
hint_string: sys::SysPtr::force_mut(self.hint_info.hint_string.string_sys()),
usage: u32::try_from(self.usage.ord()).expect("usage.ord()"),
}
}
#[doc(hidden)]
pub fn empty_sys() -> sys::GDExtensionPropertyInfo {
use crate::obj::{EngineBitfield as _, EngineEnum as _};
sys::GDExtensionPropertyInfo {
type_: VariantType::NIL.sys(),
name: std::ptr::null_mut(),
class_name: std::ptr::null_mut(),
hint: PropertyHint::NONE.ord() as u32,
hint_string: std::ptr::null_mut(),
usage: PropertyUsageFlags::NONE.ord() as u32,
}
}
pub(crate) fn into_owned_property_sys(self) -> sys::GDExtensionPropertyInfo {
use crate::obj::{EngineBitfield as _, EngineEnum as _};
sys::GDExtensionPropertyInfo {
type_: self.variant_type.sys(),
name: self.property_name.into_owned_string_sys(),
class_name: self.class_name.into_owned_string_sys(),
hint: u32::try_from(self.hint_info.hint.ord()).expect("hint.ord()"),
hint_string: self.hint_info.hint_string.into_owned_string_sys(),
usage: u32::try_from(self.usage.ord()).expect("usage.ord()"),
}
}
pub(crate) unsafe fn free_owned_property_sys(info: sys::GDExtensionPropertyInfo) {
unsafe {
let _name = StringName::from_owned_string_sys(info.name);
let _class_name = StringName::from_owned_string_sys(info.class_name);
let _hint_string = GString::from_owned_string_sys(info.hint_string);
}
}
pub(crate) unsafe fn move_into_property_info_ptr(
self,
property_info_ptr: *mut sys::GDExtensionPropertyInfo,
) {
unsafe {
let ptr = &mut *property_info_ptr;
ptr.usage = u32::try_from(self.usage.ord()).expect("usage.ord()");
ptr.hint = u32::try_from(self.hint_info.hint.ord()).expect("hint.ord()");
ptr.type_ = self.variant_type.sys();
*StringName::borrow_string_sys_mut(ptr.name) = self.property_name;
*GString::borrow_string_sys_mut(ptr.hint_string) = self.hint_info.hint_string;
*StringName::borrow_string_sys_mut(ptr.class_name) = self.class_name;
}
}
pub(crate) unsafe fn new_from_sys(
property_info_ptr: *mut sys::GDExtensionPropertyInfo,
) -> Self {
unsafe {
let ptr = *property_info_ptr;
Self {
variant_type: VariantType::from_sys(ptr.type_),
class_name: StringName::new_from_string_sys(ptr.class_name),
property_name: StringName::new_from_string_sys(ptr.name),
hint_info: PropertyHintInfo {
hint: PropertyHint::from_ord(ptr.hint.to_owned() as i32),
hint_string: GString::new_from_string_sys(ptr.hint_string),
},
usage: PropertyUsageFlags::from_ord(ptr.usage as u64),
}
}
}
}
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct PropertyHintInfo {
pub hint: PropertyHint,
pub hint_string: GString,
}
impl PropertyHintInfo {
pub fn none() -> Self {
Self {
hint: PropertyHint::NONE,
hint_string: GString::new(),
}
}
#[doc(hidden)]
pub fn object_as_node_class<T>() -> Option<ClassId>
where
T: GodotClass + Bounds<Exportable = bounds::Yes>,
{
T::inherits::<classes::Node>().then(|| T::class_id())
}
}