use super::*;
use std::mem::{transmute, forget};
use std::default::Default;
use std::fmt;
pub struct Variant(pub(crate) sys::godot_variant);
macro_rules! variant_constructors_transmute {
(
$(
$(#[$attr:meta])*
pub fn $ctor:ident($Type:ty) -> Self as $GdType:ty : $gd_method:ident;
)*
) => (
$(
$(#[$attr])*
pub fn $ctor(val: $Type) -> Variant {
unsafe {
let api = get_api();
let mut dest = sys::godot_variant::default();
let gd_val: $GdType = transmute(*val);
(api.$gd_method)(&mut dest, &gd_val);
Variant(dest)
}
}
)*
)
}
macro_rules! variant_constructors_wrap {
(
$(
$(#[$attr:meta])*
pub fn $ctor:ident($Type:ty) -> Self as $GdType:ty : $gd_method:ident;
)*
) => (
$(
$(#[$attr])*
pub fn $ctor(val: $Type) -> Variant {
unsafe {
let api = get_api();
let mut dest = sys::godot_variant::default();
(api.$gd_method)(&mut dest, &val.0);
Variant(dest)
}
}
)*
)
}
macro_rules! variant_to_type_transmute {
(
$(
$(#[$to_attr:meta])*
pub fn $to_method:ident(&self) -> $ToType:ident : $to_gd_method:ident;
$(#[$try_attr:meta])*
pub fn $try_method:ident(&self) -> Option<$TryType:ident> : $try_gd_method:ident;
)*
) => (
$(
$(#[$to_attr])*
pub fn $to_method(&self) -> $ToType {
unsafe {
transmute((get_api().$to_gd_method)(&self.0))
}
}
$(#[$try_attr])*
pub fn $try_method(&self) -> Option<$TryType> {
if self.get_type() != VariantType::$TryType {
return None;
}
unsafe {
Some(transmute((get_api().$try_gd_method)(&self.0)))
}
}
)*
)
}
macro_rules! variant_to_type_wrap {
(
$(
$(#[$to_attr:meta])*
pub fn $to_method:ident(&self) -> $ToType:ident : $to_gd_method:ident;
$(#[$try_attr:meta])*
pub fn $try_method:ident(&self) -> Option<$TryType:ident> : $try_gd_method:ident;
)*
) => (
$(
$(#[$to_attr])*
pub fn $to_method(&self) -> $ToType {
unsafe {
$ToType((get_api().$to_gd_method)(&self.0))
}
}
$(#[$try_attr])*
pub fn $try_method(&self) -> Option<$TryType> {
if self.get_type() != VariantType::$TryType {
return None;
}
unsafe {
Some($TryType((get_api().$try_gd_method)(&self.0)))
}
}
)*
)
}
use sys::godot_variant_type::*;
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum VariantType {
Nil = GODOT_VARIANT_TYPE_NIL as u32,
Bool = GODOT_VARIANT_TYPE_BOOL as u32,
I64 = GODOT_VARIANT_TYPE_INT as u32,
F64 = GODOT_VARIANT_TYPE_REAL as u32,
GodotString = GODOT_VARIANT_TYPE_STRING as u32,
Vector2 = GODOT_VARIANT_TYPE_VECTOR2 as u32,
Rect2 = GODOT_VARIANT_TYPE_RECT2 as u32,
Vector3 = GODOT_VARIANT_TYPE_VECTOR3 as u32,
Transform2D = GODOT_VARIANT_TYPE_TRANSFORM2D as u32,
Plane = GODOT_VARIANT_TYPE_PLANE as u32,
Quat = GODOT_VARIANT_TYPE_QUAT as u32,
Aabb = GODOT_VARIANT_TYPE_AABB as u32,
Basis = GODOT_VARIANT_TYPE_BASIS as u32,
Transform = GODOT_VARIANT_TYPE_TRANSFORM as u32,
Color = GODOT_VARIANT_TYPE_COLOR as u32,
NodePath = GODOT_VARIANT_TYPE_NODE_PATH as u32,
Rid = GODOT_VARIANT_TYPE_RID as u32,
Object = GODOT_VARIANT_TYPE_OBJECT as u32,
Dictionary = GODOT_VARIANT_TYPE_DICTIONARY as u32,
VariantArray = GODOT_VARIANT_TYPE_ARRAY as u32,
ByteArray = GODOT_VARIANT_TYPE_POOL_BYTE_ARRAY as u32,
Int32Array = GODOT_VARIANT_TYPE_POOL_INT_ARRAY as u32,
Float32Array = GODOT_VARIANT_TYPE_POOL_REAL_ARRAY as u32,
StringArray = GODOT_VARIANT_TYPE_POOL_STRING_ARRAY as u32,
Vector2Array = GODOT_VARIANT_TYPE_POOL_VECTOR2_ARRAY as u32,
Vector3Array = GODOT_VARIANT_TYPE_POOL_VECTOR3_ARRAY as u32,
ColorArray = GODOT_VARIANT_TYPE_POOL_COLOR_ARRAY as u32,
}
impl VariantType {
#[doc(hidden)]
pub fn from_sys(v: sys::godot_variant_type) -> VariantType {
unsafe { transmute(v) }
}
}
type F64 = f64;
type I64 = i64;
type Bool = bool;
impl Variant {
variant_constructors_transmute!(
pub fn from_vector2(&Vector2) -> Self as sys::godot_vector2 : godot_variant_new_vector2;
pub fn from_vector3(&Vector3) -> Self as sys::godot_vector3 : godot_variant_new_vector3;
pub fn from_quat(&Quat) -> Self as sys::godot_quat : godot_variant_new_quat;
pub fn from_plane(&Plane) -> Self as sys::godot_plane : godot_variant_new_plane;
pub fn from_rect2(&Rect2) -> Self as sys::godot_rect2 : godot_variant_new_rect2;
pub fn from_transform(&Transform) -> Self as sys::godot_transform : godot_variant_new_transform;
pub fn from_transform2d(&Transform2D) -> Self as sys::godot_transform2d : godot_variant_new_transform2d;
pub fn from_basis(&Basis) -> Self as sys::godot_basis : godot_variant_new_basis;
pub fn from_color(&Color) -> Self as sys::godot_color : godot_variant_new_color;
pub fn from_aabb(&Aabb) -> Self as sys::godot_aabb : godot_variant_new_aabb;
);
variant_constructors_wrap!(
pub fn from_rid(&Rid) -> Self as sys::godot_rid : godot_variant_new_rid;
pub fn from_node_path(&NodePath) -> Self as sys::godot_node_path : godot_variant_new_node_path;
pub fn from_godot_string(&GodotString) -> Self as sys::godot_string : godot_variant_new_string;
pub fn from_array(&VariantArray) -> Self as sys::godot_array : godot_variant_new_array;
pub fn from_byte_array(&ByteArray) -> Self as sys::godot_pool_byte_array : godot_variant_new_pool_byte_array;
pub fn from_int32_array(&Int32Array) -> Self as sys::godot_pool_int_array : godot_variant_new_pool_int_array;
pub fn from_float32_array(&Float32Array) -> Self as sys::godot_pool_real_array : godot_variant_new_pool_real_array;
pub fn from_string_array(&StringArray) -> Self as sys::godot_pool_string_array : godot_variant_new_pool_string_array;
pub fn from_vector2_array(&Vector2Array) -> Self as sys::godot_pool_vector2_array : godot_variant_new_pool_vector2_array;
pub fn from_vector3_array(&Vector3Array) -> Self as sys::godot_pool_vector3_array : godot_variant_new_pool_vector3_array;
pub fn from_color_array(&ColorArray) -> Self as sys::godot_pool_color_array : godot_variant_new_pool_color_array;
pub fn from_dictionary(&Dictionary) -> Self as sys::godot_dictionary : godot_variant_new_dictionary;
);
pub fn new() -> Self {
unsafe {
let api = get_api();
let mut dest = sys::godot_variant::default();
(api.godot_variant_new_nil)(&mut dest);
Variant(dest)
}
}
pub fn from_str<S>(s: S) -> Variant
where S: AsRef<str>
{
unsafe {
let api = get_api();
let mut dest = sys::godot_variant::default();
let val = s.as_ref();
let mut godot_s = (api.godot_string_chars_to_utf8_with_len)(val.as_ptr() as *const _, val.len() as _);
(api.godot_variant_new_string)(&mut dest, &godot_s);
(api.godot_string_destroy)(&mut godot_s);
Variant(dest)
}
}
pub fn from_object<T>(val: T) -> Variant
where T: GodotObject
{
unsafe {
let api = get_api();
let mut dest = sys::godot_variant::default();
(api.godot_variant_new_object)(&mut dest, val.to_sys());
Variant(dest)
}
}
pub fn from_i64(v: i64) -> Variant {
unsafe {
let api = get_api();
let mut dest = sys::godot_variant::default();
(api.godot_variant_new_int)(&mut dest, v);
Variant(dest)
}
}
pub fn from_u64(v: u64) -> Variant {
unsafe {
let api = get_api();
let mut dest = sys::godot_variant::default();
(api.godot_variant_new_uint)(&mut dest, v);
Variant(dest)
}
}
pub fn from_bool(v: bool) -> Variant {
unsafe {
let api = get_api();
let mut dest = sys::godot_variant::default();
(api.godot_variant_new_bool)(&mut dest, v);
Variant(dest)
}
}
variant_to_type_transmute!(
pub fn to_vector2(&self) -> Vector2 : godot_variant_as_vector2;
pub fn try_to_vector2(&self) -> Option<Vector2> : godot_variant_as_vector2;
pub fn to_vector3(&self) -> Vector3 : godot_variant_as_vector3;
pub fn try_to_vector3(&self) -> Option<Vector3> : godot_variant_as_vector3;
pub fn to_quat(&self) -> Quat : godot_variant_as_quat;
pub fn try_to_quat(&self) -> Option<Quat> : godot_variant_as_quat;
pub fn to_plane(&self) -> Plane : godot_variant_as_plane;
pub fn try_to_plane(&self) -> Option<Plane> : godot_variant_as_plane;
pub fn to_rect2(&self) -> Rect2 : godot_variant_as_rect2;
pub fn try_to_rect2(&self) -> Option<Rect2> : godot_variant_as_rect2;
pub fn to_transform(&self) -> Transform : godot_variant_as_transform;
pub fn try_to_transform(&self) -> Option<Transform> : godot_variant_as_transform;
pub fn to_transform2d(&self) -> Transform2D : godot_variant_as_transform2d;
pub fn try_to_transform2d(&self) -> Option<Transform2D> : godot_variant_as_transform2d;
pub fn to_basis(&self) -> Basis : godot_variant_as_basis;
pub fn try_to_basis(&self) -> Option<Basis> : godot_variant_as_basis;
pub fn to_color(&self) -> Color : godot_variant_as_color;
pub fn try_to_color(&self) -> Option<Color> : godot_variant_as_color;
pub fn to_aabb(&self) -> Aabb : godot_variant_as_aabb;
pub fn try_to_aabb(&self) -> Option<Aabb> : godot_variant_as_aabb;
pub fn to_f64(&self) -> F64 : godot_variant_as_real;
pub fn try_to_f64(&self) -> Option<F64> : godot_variant_as_real;
pub fn to_i64(&self) -> I64 : godot_variant_as_int;
pub fn try_to_i64(&self) -> Option<I64> : godot_variant_as_int;
pub fn to_bool(&self) -> Bool : godot_variant_as_bool;
pub fn try_to_bool(&self) -> Option<Bool> : godot_variant_as_bool;
);
variant_to_type_wrap!(
pub fn to_node_path(&self) -> NodePath : godot_variant_as_node_path;
pub fn try_to_node_path(&self) -> Option<NodePath> : godot_variant_as_node_path;
pub fn to_godot_string(&self) -> GodotString : godot_variant_as_string;
pub fn try_to_godot_string(&self) -> Option<GodotString> : godot_variant_as_string;
pub fn to_rid(&self) -> Rid : godot_variant_as_rid;
pub fn try_to_rid(&self) -> Option<Rid> : godot_variant_as_rid;
pub fn to_array(&self) -> VariantArray : godot_variant_as_array;
pub fn try_to_array(&self) -> Option<VariantArray> : godot_variant_as_array;
pub fn to_byte_array(&self) -> ByteArray : godot_variant_as_pool_byte_array;
pub fn try_to_byte_array(&self) -> Option<ByteArray> : godot_variant_as_pool_byte_array;
pub fn to_int32_array(&self) -> Int32Array : godot_variant_as_pool_int_array;
pub fn try_to_int32_array(&self) -> Option<Int32Array> : godot_variant_as_pool_int_array;
pub fn to_float32_array(&self) -> Float32Array : godot_variant_as_pool_real_array;
pub fn try_to_float32_array(&self) -> Option<Float32Array> : godot_variant_as_pool_real_array;
pub fn to_string_array(&self) -> StringArray : godot_variant_as_pool_string_array;
pub fn try_to_string_array(&self) -> Option<StringArray> : godot_variant_as_pool_string_array;
pub fn to_vector2_array(&self) -> Vector2Array : godot_variant_as_pool_vector2_array;
pub fn try_to_vector2_array(&self) -> Option<Vector2Array> : godot_variant_as_pool_vector2_array;
pub fn to_vector3_array(&self) -> Vector3Array : godot_variant_as_pool_vector3_array;
pub fn try_to_vector3_array(&self) -> Option<Vector3Array> : godot_variant_as_pool_vector3_array;
pub fn to_color_array(&self) -> ColorArray : godot_variant_as_pool_color_array;
pub fn try_to_color_array(&self) -> Option<ColorArray> : godot_variant_as_pool_color_array;
pub fn to_dictionary(&self) -> Dictionary : godot_variant_as_dictionary;
pub fn try_to_dictionary(&self) -> Option<Dictionary> : godot_variant_as_dictionary;
);
pub fn try_to_object<T>(&self) -> Option<T>
where T: GodotObject
{
use sys::godot_variant_type::*;
unsafe {
let api = get_api();
if (api.godot_variant_get_type)(&self.0) != GODOT_VARIANT_TYPE_OBJECT {
return None;
}
let obj = Object::from_sys((api.godot_variant_as_object)(&self.0));
obj.cast::<T>()
}
}
pub fn to_string(&self) -> String {
self.to_godot_string().to_string()
}
pub fn try_to_string(&self) -> Option<String> {
self.try_to_godot_string().map(|s|{ s.to_string() })
}
pub fn get_type(&self) -> VariantType {
unsafe {
VariantType::from_sys(
(get_api().godot_variant_get_type)(&self.0)
)
}
}
pub fn is_nil(&self) -> bool {
self.get_type() == VariantType::Nil
}
pub fn has_method(&self, method: &GodotString) -> bool {
unsafe {
(get_api().godot_variant_has_method)(&self.0, &method.0)
}
}
pub fn call(&mut self, method: &GodotString, args: &[Variant]) -> Result<(), ()> {
unsafe {
let api = get_api();
let mut err = sys::godot_variant_call_error::default();
if args.is_empty() {
let mut first = ::std::ptr::null() as *const sys::godot_variant;
(api.godot_variant_call)(
&mut self.0,
&method.0,
&mut first, 0,
&mut err
);
} else {
let gd_args: &[sys::godot_variant] = transmute(args);
let mut first = &gd_args[0] as *const sys::godot_variant;
(api.godot_variant_call)(
&mut self.0,
&method.0,
&mut first, args.len() as i32,
&mut err
);
}
if err.error == sys::godot_variant_call_error_error::GODOT_CALL_ERROR_CALL_OK {
Ok(())
} else {
Err(())
}
}
}
pub(crate) fn cast_ref<'l>(ptr: *const sys::godot_variant) -> &'l Variant {
unsafe { transmute(ptr) }
}
pub(crate) fn cast_mut_ref<'l>(ptr: *mut sys::godot_variant) -> &'l mut Variant {
unsafe { transmute(ptr) }
}
pub fn forget(self) -> sys::godot_variant {
let v = self.0;
forget(self);
v
}
#[doc(hidden)]
pub fn to_sys(&self) -> sys::godot_variant {
self.0
}
}
impl_basic_traits!(
for Variant as godot_variant {
Drop => godot_variant_destroy;
Clone => godot_variant_new_copy;
PartialEq => godot_variant_operator_equal;
}
);
impl Default for Variant {
fn default() -> Self { Variant::new() }
}
impl fmt::Debug for Variant {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{:?}({})", self.get_type(), self.to_string())
}
}
macro_rules! variant_from_ref {
($(impl From<&$Type:ty> : $ctor:ident;)*) => (
$(
impl<'l> From<&'l $Type> for Variant
{
fn from(val: &'l $Type) -> Variant {
Variant::$ctor(val)
}
}
)*
);
}
macro_rules! variant_from_val {
($(impl From<$Type:ty> : $ctor:ident;)*) => (
$(
impl From<$Type> for Variant
{
fn from(val: $Type) -> Variant {
Variant::$ctor(val)
}
}
)*
);
}
variant_from_val!(
impl From<i64> : from_i64;
impl From<u64> : from_u64;
impl From<bool> : from_bool;
);
variant_from_ref!(
impl From<&Vector2> : from_vector2;
impl From<&Vector3> : from_vector3;
impl From<&Quat> : from_quat;
impl From<&Plane> : from_plane;
impl From<&Rect2> : from_rect2;
impl From<&Transform> : from_transform;
impl From<&Transform2D> : from_transform2d;
impl From<&Basis> : from_basis;
impl From<&Color> : from_color;
impl From<&Aabb> : from_aabb;
impl From<&String> : from_str;
impl From<&Rid> : from_rid;
impl From<&NodePath> : from_node_path;
impl From<&GodotString> : from_godot_string;
impl From<&Dictionary> : from_dictionary;
impl From<&VariantArray> : from_array;
impl From<&ByteArray> : from_byte_array;
impl From<&Int32Array> : from_int32_array;
impl From<&Float32Array> : from_float32_array;
impl From<&Vector2Array> : from_vector2_array;
impl From<&Vector3Array> : from_vector3_array;
impl From<&ColorArray> : from_color_array;
);
impl<'l> From<&'l str> for Variant {
fn from(v: &str) -> Variant {
Variant::from_str(v)
}
}
impl <T> From<T> for Variant
where T: GodotObject
{
fn from(val: T) -> Variant {
Variant::from_object(val)
}
}
godot_test!(
test_variant_nil {
let nil = Variant::new();
assert_eq!(nil.get_type(), VariantType::Nil);
assert!(nil.is_nil());
assert!(nil.try_to_array().is_none());
assert!(nil.try_to_rid().is_none());
assert!(nil.try_to_i64().is_none());
assert!(nil.try_to_bool().is_none());
assert!(nil.try_to_aabb().is_none());
assert!(nil.try_to_vector2().is_none());
assert!(nil.try_to_basis().is_none());
assert!(!nil.has_method(&GodotString::from_str("foo")));
let clone = nil.clone();
assert!(clone == nil);
}
test_variant_i64 {
let v_42 = Variant::from_i64(42);
assert_eq!(v_42.get_type(), VariantType::I64);
assert!(!v_42.is_nil());
assert_eq!(v_42.try_to_i64(), Some(42));
assert!(v_42.try_to_f64().is_none());
assert!(v_42.try_to_array().is_none());
let v_m1 = Variant::from_i64(-1);
assert_eq!(v_m1.get_type(), VariantType::I64);
assert!(!v_m1.is_nil());
assert_eq!(v_m1.try_to_i64(), Some(-1));
assert!(v_m1.try_to_f64().is_none());
assert!(v_m1.try_to_array().is_none());
}
);