diff --git a/gdnative-core/Cargo.toml b/gdnative-core/Cargo.toml index 3ec3384e8..7a22a0ec0 100644 --- a/gdnative-core/Cargo.toml +++ b/gdnative-core/Cargo.toml @@ -24,6 +24,7 @@ glam = "0.15.1" indexmap = "1.6.0" ahash = "0.7.0" once_cell = "1.7.2" +serde = { version = "1", default_features = false, features = ["derive"], optional = true } gdnative-impl-proc-macros = { path = "../impl/proc_macros", version = "=0.9.3" } diff --git a/gdnative-core/src/core_types/color.rs b/gdnative-core/src/core_types/color.rs index 902ca5616..97e8e55c3 100644 --- a/gdnative-core/src/core_types/color.rs +++ b/gdnative-core/src/core_types/color.rs @@ -6,6 +6,7 @@ use crate::core_types::GodotString; /// RGBA color with 32 bits floating point components. #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Color { pub r: f32, pub g: f32, diff --git a/gdnative-core/src/core_types/dictionary.rs b/gdnative-core/src/core_types/dictionary.rs index beb64dce2..ff42b51eb 100644 --- a/gdnative-core/src/core_types/dictionary.rs +++ b/gdnative-core/src/core_types/dictionary.rs @@ -544,6 +544,82 @@ where } } +#[cfg(feature = "serde")] +pub(super) mod serde { + use super::*; + use ::serde::{ + de::{MapAccess, Visitor}, + ser::SerializeMap, + Deserialize, Deserializer, Serialize, Serializer, + }; + use std::fmt::Formatter; + + impl Serialize for Dictionary { + #[inline] + fn serialize(&self, ser: S) -> Result<::Ok, ::Error> + where + S: Serializer, + { + let mut ser = ser.serialize_map(Some(self.len() as usize))?; + for (key, value) in self.iter() { + ser.serialize_entry(&key, &value)? + } + ser.end() + } + } + + pub(in super::super) struct DictionaryVisitor; + + impl<'de> Visitor<'de> for DictionaryVisitor { + type Value = Dictionary; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str("a Dictionary") + } + + fn visit_map(self, mut map: A) -> Result>::Error> + where + A: MapAccess<'de>, + { + let dict = Dictionary::new(); + while let Some((key, value)) = map.next_entry::()? { + dict.insert(key, value) + } + Ok(dict) + } + } + + impl<'de> Deserialize<'de> for Dictionary { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_map(DictionaryVisitor) + } + } + + impl<'de> Deserialize<'de> for Dictionary { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Dictionary::::deserialize(deserializer).map(Dictionary::into_shared) + } + } + + impl<'de> Deserialize<'de> for Dictionary { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Dictionary::::deserialize(deserializer).map(Dictionary::into_thread_local) + } + } +} + godot_test!(test_dictionary { use std::collections::HashSet; diff --git a/gdnative-core/src/core_types/error.rs b/gdnative-core/src/core_types/error.rs index c008dc0bb..d7ade9a44 100644 --- a/gdnative-core/src/core_types/error.rs +++ b/gdnative-core/src/core_types/error.rs @@ -2,6 +2,7 @@ use crate::sys; /// Error codes used in various Godot APIs. #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[repr(u32)] pub enum GodotError { Failed = sys::godot_error_GODOT_FAILED as u32, diff --git a/gdnative-core/src/core_types/geom/aabb.rs b/gdnative-core/src/core_types/geom/aabb.rs index 0f3508c19..0beafd202 100644 --- a/gdnative-core/src/core_types/geom/aabb.rs +++ b/gdnative-core/src/core_types/geom/aabb.rs @@ -3,6 +3,7 @@ use crate::core_types::Vector3; /// Axis-aligned bounding box. #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Aabb { pub position: Vector3, pub size: Vector3, diff --git a/gdnative-core/src/core_types/geom/basis.rs b/gdnative-core/src/core_types/geom/basis.rs index 73507f2a5..56b2ecc39 100644 --- a/gdnative-core/src/core_types/geom/basis.rs +++ b/gdnative-core/src/core_types/geom/basis.rs @@ -4,6 +4,7 @@ use core::ops::Mul; /// A 3x3 matrix. #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Basis { pub elements: [Vector3; 3], } diff --git a/gdnative-core/src/core_types/geom/plane.rs b/gdnative-core/src/core_types/geom/plane.rs index eec423f9c..19e3d8a98 100644 --- a/gdnative-core/src/core_types/geom/plane.rs +++ b/gdnative-core/src/core_types/geom/plane.rs @@ -3,6 +3,7 @@ use crate::core_types::{IsEqualApprox, Vector3}; /// Plane in hessian form. #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Plane { pub normal: Vector3, pub d: f32, diff --git a/gdnative-core/src/core_types/geom/transform.rs b/gdnative-core/src/core_types/geom/transform.rs index 251459230..6143f87c4 100644 --- a/gdnative-core/src/core_types/geom/transform.rs +++ b/gdnative-core/src/core_types/geom/transform.rs @@ -3,6 +3,7 @@ use crate::core_types::{Basis, Vector3}; /// 3D Transformation (3x4 matrix) Using basis + origin representation. #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Transform { /// The basis is a matrix containing 3 Vector3 as its columns: X axis, Y axis, and Z axis. /// These vectors can be interpreted as the basis vectors of local coordinate system diff --git a/gdnative-core/src/core_types/mod.rs b/gdnative-core/src/core_types/mod.rs index 72a3ebca5..c610a5633 100644 --- a/gdnative-core/src/core_types/mod.rs +++ b/gdnative-core/src/core_types/mod.rs @@ -43,7 +43,7 @@ pub use rid::*; pub use string::*; pub use string_array::*; pub use transform2d::*; -pub use typed_array::TypedArray; +pub use typed_array::{Element, TypedArray}; pub use variant::*; pub use variant_array::*; pub use vector2::*; diff --git a/gdnative-core/src/core_types/node_path.rs b/gdnative-core/src/core_types/node_path.rs index 260744a76..6eeba5171 100644 --- a/gdnative-core/src/core_types/node_path.rs +++ b/gdnative-core/src/core_types/node_path.rs @@ -176,3 +176,67 @@ impl fmt::Debug for NodePath { write!(f, "NodePath({})", self.to_string()) } } + +#[cfg(feature = "serde")] +mod serde { + use super::*; + use ::serde::{ + de::{Error, Visitor}, + Deserialize, Deserializer, Serialize, Serializer, + }; + use std::fmt::Formatter; + + impl Serialize for NodePath { + #[inline] + fn serialize(&self, ser: S) -> Result<::Ok, ::Error> + where + S: Serializer, + { + ser.serialize_newtype_struct("NodePath", &*self.to_string()) + } + } + + impl<'de> Deserialize<'de> for NodePath { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct NodePathVisitor; + + impl<'de> Visitor<'de> for NodePathVisitor { + type Value = NodePath; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str("a NodePath") + } + + fn visit_str(self, s: &str) -> Result + where + E: Error, + { + Ok(NodePath::from_str(s)) + } + + fn visit_string(self, s: String) -> Result + where + E: Error, + { + Ok(NodePath::from_str(&*s)) + } + + fn visit_newtype_struct( + self, + deserializer: D, + ) -> Result>::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(self) + } + } + + deserializer.deserialize_newtype_struct("NodePath", NodePathVisitor) + } + } +} diff --git a/gdnative-core/src/core_types/quat.rs b/gdnative-core/src/core_types/quat.rs index c4e36ffb9..081cd5141 100644 --- a/gdnative-core/src/core_types/quat.rs +++ b/gdnative-core/src/core_types/quat.rs @@ -1,6 +1,7 @@ use super::IsEqualApprox; #[derive(Copy, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[repr(C)] pub struct Quat { pub x: f32, diff --git a/gdnative-core/src/core_types/rect2.rs b/gdnative-core/src/core_types/rect2.rs index 1fe015688..b72fd5c07 100644 --- a/gdnative-core/src/core_types/rect2.rs +++ b/gdnative-core/src/core_types/rect2.rs @@ -1,5 +1,6 @@ use super::Vector2; +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[repr(C)] pub struct Rect2 { pub position: Vector2, diff --git a/gdnative-core/src/core_types/rid.rs b/gdnative-core/src/core_types/rid.rs index 02cf6ceaf..927ce468d 100644 --- a/gdnative-core/src/core_types/rid.rs +++ b/gdnative-core/src/core_types/rid.rs @@ -84,3 +84,39 @@ impl PartialOrd for Rid { } } } + +#[cfg(feature = "serde")] +mod serde { + use super::*; + use ::serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; + use std::fmt::Formatter; + + impl Serialize for Rid { + #[inline] + fn serialize(&self, serializer: S) -> Result<::Ok, S::Error> + where + S: Serializer, + { + serializer.serialize_unit() + } + } + + impl<'de> Deserialize<'de> for Rid { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct RidVisitor; + impl<'de> Visitor<'de> for RidVisitor { + type Value = Rid; + + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("Unit as an RID placeholder") + } + } + deserializer.deserialize_unit(RidVisitor)?; + Ok(Rid::new()) + } + } +} diff --git a/gdnative-core/src/core_types/string.rs b/gdnative-core/src/core_types/string.rs index a44ac8333..222a4d592 100644 --- a/gdnative-core/src/core_types/string.rs +++ b/gdnative-core/src/core_types/string.rs @@ -612,6 +612,55 @@ where } } +#[cfg(feature = "serde")] +mod serde { + use super::*; + use ::serde::{ + de::{Error, Visitor}, + Deserialize, Deserializer, Serialize, Serializer, + }; + use std::fmt::Formatter; + + impl Serialize for GodotString { + #[inline] + fn serialize( + &self, + serializer: S, + ) -> Result<::Ok, ::Error> + where + S: Serializer, + { + serializer.serialize_str(&*self.to_string()) + } + } + + #[cfg(feature = "serde")] + impl<'de> serde::Deserialize<'de> for GodotString { + #[inline] + fn deserialize(deserializer: D) -> Result>::Error> + where + D: Deserializer<'de>, + { + struct GodotStringVisitor; + impl<'de> Visitor<'de> for GodotStringVisitor { + type Value = GodotString; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str("a GodotString") + } + + fn visit_str(self, s: &str) -> Result + where + E: Error, + { + Ok(GodotString::from(s)) + } + } + + deserializer.deserialize_str(GodotStringVisitor) + } + } +} godot_test!(test_string { use crate::core_types::{GodotString, Variant, VariantType, ToVariant}; diff --git a/gdnative-core/src/core_types/transform2d.rs b/gdnative-core/src/core_types/transform2d.rs index a8067908e..bace0db5e 100644 --- a/gdnative-core/src/core_types/transform2d.rs +++ b/gdnative-core/src/core_types/transform2d.rs @@ -1,5 +1,6 @@ use super::Vector2; +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[repr(C)] pub struct Transform2D { pub x: Vector2, diff --git a/gdnative-core/src/core_types/typed_array.rs b/gdnative-core/src/core_types/typed_array.rs index c5b2a822b..0460c7c9e 100644 --- a/gdnative-core/src/core_types/typed_array.rs +++ b/gdnative-core/src/core_types/typed_array.rs @@ -483,3 +483,63 @@ macros::impl_typed_array_element! { mod private { pub trait Sealed {} } + +#[cfg(feature = "serde")] +mod serde { + use super::*; + use ::serde::{ + de::{SeqAccess, Visitor}, + ser::SerializeSeq, + Deserialize, Deserializer, Serialize, Serializer, + }; + use std::fmt::Formatter; + use std::marker::PhantomData; + + impl Serialize for TypedArray { + #[inline] + fn serialize(&self, ser: S) -> Result<::Ok, ::Error> + where + S: Serializer, + { + let read = self.read(); + let mut ser = ser.serialize_seq(Some(read.len()))?; + for e in read.iter() { + ser.serialize_element(e)? + } + ser.end() + } + } + + impl<'de, T: Deserialize<'de> + Element> Deserialize<'de> for TypedArray { + #[inline] + fn deserialize(deserializer: D) -> Result>::Error> + where + D: Deserializer<'de>, + { + struct TypedArrayVisitor(PhantomData); + impl<'de, T: Deserialize<'de> + Element> Visitor<'de> for TypedArrayVisitor { + type Value = TypedArray; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str(std::any::type_name::()) + } + + fn visit_seq( + self, + mut seq: A, + ) -> Result>::Error> + where + A: SeqAccess<'de>, + { + let mut vec = seq.size_hint().map_or_else(Vec::new, Vec::with_capacity); + while let Some(val) = seq.next_element::()? { + vec.push(val); + } + Ok(Self::Value::from_vec(vec)) + } + } + + deserializer.deserialize_seq(TypedArrayVisitor::(PhantomData)) + } + } +} diff --git a/gdnative-core/src/core_types/variant.rs b/gdnative-core/src/core_types/variant.rs index e6ef9aef0..d54bea0f9 100644 --- a/gdnative-core/src/core_types/variant.rs +++ b/gdnative-core/src/core_types/variant.rs @@ -103,6 +103,7 @@ macro_rules! decl_variant_type { ) => { #[repr(u32)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] + #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub enum VariantType { $( $variant = $c_const as u32, @@ -1881,6 +1882,514 @@ macro_rules! impl_variant_for_tuples { impl_variant_for_tuples!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,); +#[cfg(feature = "serde")] +pub mod serde { + use super::super::{ + dictionary::serde::DictionaryVisitor, variant_array::serde::VariantArrayVisitor, + }; + use super::*; + use ::serde::{ + de::{EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor}, + ser::SerializeMap, + Deserialize, Deserializer, Serialize, Serializer, + }; + use std::fmt::Formatter; + + impl Serialize for Variant { + #[inline] + fn serialize(&self, ser: S) -> Result<::Ok, ::Error> + where + S: Serializer, + { + match self.dispatch() { + VariantDispatch::Nil => ser.serialize_none(), + VariantDispatch::Bool(v) => ser.serialize_bool(v), + VariantDispatch::I64(v) => ser.serialize_i64(v), + VariantDispatch::F64(v) => ser.serialize_f64(v), + VariantDispatch::GodotString(v) => ser.serialize_str(&v.to_string()), + VariantDispatch::Vector2(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Vector2, &v)?; + ser.end() + } + VariantDispatch::Rect2(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Rect2, &v)?; + ser.end() + } + VariantDispatch::Vector3(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Vector3, &v)?; + ser.end() + } + VariantDispatch::Transform2D(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Transform2D, &v)?; + ser.end() + } + VariantDispatch::Plane(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Plane, &v)?; + ser.end() + } + VariantDispatch::Quat(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Quat, &v)?; + ser.end() + } + VariantDispatch::Aabb(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Aabb, &v)?; + ser.end() + } + VariantDispatch::Basis(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Basis, &v)?; + ser.end() + } + VariantDispatch::Transform(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Transform, &v)?; + ser.end() + } + VariantDispatch::Color(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Color, &v)?; + ser.end() + } + VariantDispatch::NodePath(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::NodePath, &v)?; + ser.end() + } + VariantDispatch::Rid(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Rid, &v)?; + ser.end() + } + VariantDispatch::Object(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Object, &Option::<()>::None)?; + ser.end() + } + VariantDispatch::Dictionary(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Dictionary, &v)?; + ser.end() + } + VariantDispatch::VariantArray(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::VariantArray, &v)?; + ser.end() + } + VariantDispatch::ByteArray(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::ByteArray, &v)?; + ser.end() + } + VariantDispatch::Int32Array(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Int32Array, &v)?; + ser.end() + } + VariantDispatch::Float32Array(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Float32Array, &v)?; + ser.end() + } + VariantDispatch::StringArray(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::StringArray, &v)?; + ser.end() + } + VariantDispatch::Vector2Array(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Vector2Array, &v)?; + ser.end() + } + VariantDispatch::Vector3Array(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::Vector3Array, &v)?; + ser.end() + } + VariantDispatch::ColorArray(v) => { + let mut ser = ser.serialize_map(Some(1))?; + ser.serialize_entry(&VariantType::ColorArray, &v)?; + ser.end() + } + } + } + } + + impl Serialize for VariantDispatch { + #[inline] + fn serialize(&self, ser: S) -> Result<::Ok, ::Error> + where + S: Serializer, + { + match self { + VariantDispatch::Nil => ser.serialize_unit_variant("VariantDispatch", 0, "Nil"), + VariantDispatch::Bool(v) => { + ser.serialize_newtype_variant("VariantDispatch", 0, "Bool", v) + } + VariantDispatch::I64(v) => { + ser.serialize_newtype_variant("VariantDispatch", 1, "I64", v) + } + VariantDispatch::F64(v) => { + ser.serialize_newtype_variant("VariantDispatch", 2, "F64", v) + } + VariantDispatch::GodotString(v) => { + ser.serialize_newtype_variant("VariantDispatch", 3, "GodotString", v) + } + VariantDispatch::Vector2(v) => { + ser.serialize_newtype_variant("VariantDispatch", 4, "Vector2", v) + } + VariantDispatch::Rect2(v) => { + ser.serialize_newtype_variant("VariantDispatch", 5, "Rect2", v) + } + VariantDispatch::Vector3(v) => { + ser.serialize_newtype_variant("VariantDispatch", 6, "Vector3", v) + } + VariantDispatch::Transform2D(v) => { + ser.serialize_newtype_variant("VariantDispatch", 7, "Transform2D", v) + } + VariantDispatch::Plane(v) => { + ser.serialize_newtype_variant("VariantDispatch", 8, "Plane", v) + } + VariantDispatch::Quat(v) => { + ser.serialize_newtype_variant("VariantDispatch", 9, "Quat", v) + } + VariantDispatch::Aabb(v) => { + ser.serialize_newtype_variant("VariantDispatch", 10, "Aabb", v) + } + VariantDispatch::Basis(v) => { + ser.serialize_newtype_variant("VariantDispatch", 11, "Basis", v) + } + VariantDispatch::Transform(v) => { + ser.serialize_newtype_variant("VariantDispatch", 12, "Transform", v) + } + VariantDispatch::Color(v) => { + ser.serialize_newtype_variant("VariantDispatch", 13, "Color", v) + } + VariantDispatch::NodePath(v) => { + ser.serialize_newtype_variant("VariantDispatch", 14, "NodePath", v) + } + VariantDispatch::Rid(v) => { + ser.serialize_newtype_variant("VariantDispatch", 15, "Rid", v) + } + VariantDispatch::Object(_) => { + ser.serialize_unit_variant("VariantDispatch", 16, "Object") + } + VariantDispatch::Dictionary(v) => { + ser.serialize_newtype_variant("VariantDispatch", 17, "Dictionary", v) + } + VariantDispatch::VariantArray(v) => { + ser.serialize_newtype_variant("VariantDispatch", 18, "VariantArray", v) + } + VariantDispatch::ByteArray(v) => { + ser.serialize_newtype_variant("VariantDispatch", 19, "ByteArray", v) + } + VariantDispatch::Int32Array(v) => { + ser.serialize_newtype_variant("VariantDispatch", 20, "Int32Array", v) + } + VariantDispatch::Float32Array(v) => { + ser.serialize_newtype_variant("VariantDispatch", 21, "Float32Array", v) + } + VariantDispatch::StringArray(v) => { + ser.serialize_newtype_variant("VariantDispatch", 22, "StringArray", v) + } + VariantDispatch::Vector2Array(v) => { + ser.serialize_newtype_variant("VariantDispatch", 23, "Vector2Array", v) + } + VariantDispatch::Vector3Array(v) => { + ser.serialize_newtype_variant("VariantDispatch", 24, "Vector3Array", v) + } + VariantDispatch::ColorArray(v) => { + ser.serialize_newtype_variant("VariantDispatch", 25, "ColorArray", v) + } + } + } + } + + static VARIANT_NAMES: [&str; 27] = [ + "Nil", + "Bool", + "I64", + "F64", + "GodotString", + "Vector2", + "Rect2", + "Vector3", + "Transform2D", + "Plane", + "Quat", + "Aabb", + "Basis", + "Transform", + "Color", + "NodePath", + "Rid", + "Object", + "Dictionary", + "VariantArray", + "ByteArray", + "Int32Array", + "Float32Array", + "StringArray", + "Vector2Array", + "Vector3Array", + "ColorArray", + ]; + + struct VariantDispatchVisitor; + impl<'de> Visitor<'de> for VariantDispatchVisitor { + type Value = VariantDispatch; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str("enum VariantDispatch") + } + + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + let val = data.variant()?; + Ok(match val { + (VariantType::Nil, variant) => { + variant.unit_variant()?; + VariantDispatch::Nil + } + (VariantType::Bool, variant) => VariantDispatch::Bool(variant.newtype_variant()?), + (VariantType::I64, variant) => VariantDispatch::I64(variant.newtype_variant()?), + (VariantType::F64, variant) => VariantDispatch::F64(variant.newtype_variant()?), + (VariantType::GodotString, variant) => { + VariantDispatch::GodotString(variant.newtype_variant()?) + } + (VariantType::Vector2, variant) => { + VariantDispatch::Vector2(variant.newtype_variant()?) + } + (VariantType::Rect2, variant) => VariantDispatch::Rect2(variant.newtype_variant()?), + (VariantType::Vector3, variant) => { + VariantDispatch::Vector3(variant.newtype_variant()?) + } + (VariantType::Transform2D, variant) => { + VariantDispatch::Transform2D(variant.newtype_variant()?) + } + (VariantType::Plane, variant) => VariantDispatch::Plane(variant.newtype_variant()?), + (VariantType::Quat, variant) => VariantDispatch::Quat(variant.newtype_variant()?), + (VariantType::Aabb, variant) => VariantDispatch::Aabb(variant.newtype_variant()?), + (VariantType::Basis, variant) => VariantDispatch::Basis(variant.newtype_variant()?), + (VariantType::Transform, variant) => { + VariantDispatch::Transform(variant.newtype_variant()?) + } + (VariantType::Color, variant) => VariantDispatch::Color(variant.newtype_variant()?), + (VariantType::NodePath, variant) => { + VariantDispatch::NodePath(variant.newtype_variant()?) + } + (VariantType::Rid, variant) => VariantDispatch::Rid(variant.newtype_variant()?), + (VariantType::Object, variant) => { + variant.unit_variant()?; + VariantDispatch::Object(Variant::new()) + } + (VariantType::Dictionary, variant) => { + VariantDispatch::Dictionary(variant.newtype_variant()?) + } + (VariantType::VariantArray, variant) => { + VariantDispatch::VariantArray(variant.newtype_variant()?) + } + (VariantType::ByteArray, variant) => { + VariantDispatch::ByteArray(variant.newtype_variant()?) + } + (VariantType::Int32Array, variant) => { + VariantDispatch::Int32Array(variant.newtype_variant()?) + } + (VariantType::Float32Array, variant) => { + VariantDispatch::Float32Array(variant.newtype_variant()?) + } + (VariantType::StringArray, variant) => { + VariantDispatch::StringArray(variant.newtype_variant()?) + } + (VariantType::Vector2Array, variant) => { + VariantDispatch::Vector2Array(variant.newtype_variant()?) + } + (VariantType::Vector3Array, variant) => { + VariantDispatch::Vector3Array(variant.newtype_variant()?) + } + (VariantType::ColorArray, variant) => { + VariantDispatch::ColorArray(variant.newtype_variant()?) + } + }) + } + } + + impl<'de> Deserialize<'de> for VariantDispatch { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_enum("VariantDispatch", &VARIANT_NAMES, VariantDispatchVisitor) + } + } + + struct VariantVisitor; + impl<'de> Visitor<'de> for VariantVisitor { + type Value = Variant; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str("a Variant") + } + + fn visit_bool(self, v: bool) -> Result + where + E: Error, + { + Ok(v.to_variant()) + } + + fn visit_i64(self, v: i64) -> Result + where + E: Error, + { + Ok(v.to_variant()) + } + + fn visit_i128(self, v: i128) -> Result + where + E: Error, + { + //TODO: Should this just return an error? + self.visit_i64(v as i64) + } + + fn visit_u64(self, v: u64) -> Result + where + E: Error, + { + self.visit_i64(v as i64) + } + + fn visit_u128(self, v: u128) -> Result + where + E: Error, + { + //TODO: Should this just return an error? + self.visit_i64(v as i64) + } + + fn visit_f64(self, v: f64) -> Result + where + E: Error, + { + Ok(v.to_variant()) + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + Ok(v.to_variant()) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + Ok(ByteArray::from_slice(v).to_variant()) + } + + fn visit_none(self) -> Result + where + E: Error, + { + Ok(Variant::new()) + } + + fn visit_some( + self, + deserializer: D, + ) -> Result>::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(self) + } + + fn visit_unit(self) -> Result + where + E: Error, + { + Ok(().to_variant()) + } + + fn visit_seq(self, seq: A) -> Result>::Error> + where + A: SeqAccess<'de>, + { + VariantArrayVisitor + .visit_seq(seq) + .map(VariantArray::::into_shared) + .map(|arr| arr.to_variant()) + } + + fn visit_map(self, mut map: A) -> Result>::Error> + where + A: MapAccess<'de>, + { + Ok(match map.next_key::()? { + Some(VariantType::Nil) => map.next_value::>()?.to_variant(), + Some(VariantType::Bool) => map.next_value::()?.to_variant(), + Some(VariantType::I64) => map.next_value::()?.to_variant(), + Some(VariantType::F64) => map.next_value::()?.to_variant(), + Some(VariantType::GodotString) => map.next_value::()?.to_variant(), + Some(VariantType::Vector2) => map.next_value::()?.to_variant(), + Some(VariantType::Rect2) => map.next_value::()?.to_variant(), + Some(VariantType::Vector3) => map.next_value::()?.to_variant(), + Some(VariantType::Transform2D) => map.next_value::()?.to_variant(), + Some(VariantType::Plane) => map.next_value::()?.to_variant(), + Some(VariantType::Quat) => map.next_value::()?.to_variant(), + Some(VariantType::Aabb) => map.next_value::()?.to_variant(), + Some(VariantType::Basis) => map.next_value::()?.to_variant(), + Some(VariantType::Transform) => map.next_value::()?.to_variant(), + Some(VariantType::Color) => map.next_value::()?.to_variant(), + Some(VariantType::NodePath) => map.next_value::()?.to_variant(), + Some(VariantType::Rid) => { + map.next_value::<()>()?; + Rid::new().to_variant() + } + Some(VariantType::Object) => map.next_value::>()?.to_variant(), + Some(VariantType::Dictionary) => map.next_value::()?.to_variant(), + Some(VariantType::VariantArray) => map.next_value::()?.to_variant(), + Some(VariantType::ByteArray) => map.next_value::()?.to_variant(), + Some(VariantType::Int32Array) => map.next_value::()?.to_variant(), + Some(VariantType::Float32Array) => map.next_value::()?.to_variant(), + Some(VariantType::StringArray) => map.next_value::()?.to_variant(), + Some(VariantType::Vector2Array) => map.next_value::()?.to_variant(), + Some(VariantType::Vector3Array) => map.next_value::()?.to_variant(), + Some(VariantType::ColorArray) => map.next_value::()?.to_variant(), + None => Variant::new(), + }) + } + + fn visit_newtype_struct(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(VariantVisitor) + } + } + + impl<'de> Deserialize<'de> for Variant { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(VariantVisitor) + } + } +} + godot_test!( test_variant_option { use std::marker::PhantomData; diff --git a/gdnative-core/src/core_types/variant_array.rs b/gdnative-core/src/core_types/variant_array.rs index 48870fa02..c812e716f 100644 --- a/gdnative-core/src/core_types/variant_array.rs +++ b/gdnative-core/src/core_types/variant_array.rs @@ -588,6 +588,83 @@ impl Extend for VariantArray } } +#[cfg(feature = "serde")] +pub(super) mod serde { + use super::*; + use ::serde::{ + de::{SeqAccess, Visitor}, + Deserialize, Deserializer, Serialize, Serializer, + }; + use std::fmt::Formatter; + + impl Serialize for VariantArray { + #[inline] + fn serialize( + &self, + _serializer: S, + ) -> Result<::Ok, ::Error> + where + S: Serializer, + { + todo!() + } + } + + pub(in super::super) struct VariantArrayVisitor; + + impl<'de> Visitor<'de> for VariantArrayVisitor { + type Value = VariantArray; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str("a VariantArray") + } + + fn visit_seq(self, mut seq: A) -> Result>::Error> + where + A: SeqAccess<'de>, + { + let arr = VariantArray::new(); + if let Some(size) = seq.size_hint() { + arr.resize(size as i32); + } + while let Some(val) = seq.next_element::()? { + arr.push(val) + } + Ok(arr) + } + } + + impl<'de> Deserialize<'de> for VariantArray { + #[inline] + fn deserialize(deserializer: D) -> Result>::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_seq(VariantArrayVisitor) + } + } + + impl<'de> Deserialize<'de> for VariantArray { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + VariantArray::::deserialize(deserializer).map(VariantArray::into_shared) + } + } + + impl<'de> Deserialize<'de> for VariantArray { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + VariantArray::::deserialize(deserializer).map(VariantArray::into_thread_local) + } + } +} + godot_test!(test_array { let foo = Variant::from_str("foo"); let bar = Variant::from_str("bar"); diff --git a/gdnative-core/src/core_types/vector2.rs b/gdnative-core/src/core_types/vector2.rs index b3fc7005d..dfed5886f 100644 --- a/gdnative-core/src/core_types/vector2.rs +++ b/gdnative-core/src/core_types/vector2.rs @@ -3,6 +3,7 @@ use glam::Vec2; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; #[derive(Copy, Clone, Debug, PartialEq, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[repr(C)] pub struct Vector2 { pub x: f32, diff --git a/gdnative-core/src/core_types/vector3.rs b/gdnative-core/src/core_types/vector3.rs index 578abbfc9..08721c991 100644 --- a/gdnative-core/src/core_types/vector3.rs +++ b/gdnative-core/src/core_types/vector3.rs @@ -4,6 +4,7 @@ use glam::Vec3A; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; #[derive(Copy, Clone, Debug, PartialEq, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[repr(C)] pub struct Vector3 { pub x: f32, diff --git a/gdnative/Cargo.toml b/gdnative/Cargo.toml index 0bb21ea70..56c60dc18 100644 --- a/gdnative/Cargo.toml +++ b/gdnative/Cargo.toml @@ -14,6 +14,7 @@ edition = "2018" [features] default = ["bindings"] formatted = ["gdnative-bindings/formatted", "gdnative-bindings/one_class_one_file"] +serde = ["gdnative-core/serde"] gd_test = ["gdnative-core/gd_test"] type_tag_fallback = ["gdnative-core/type_tag_fallback"]