Skip to content

Commit

Permalink
serde support for core types & VariantDispatch
Browse files Browse the repository at this point in the history
  • Loading branch information
Waridley committed Sep 15, 2021
1 parent 831958c commit c4f699d
Show file tree
Hide file tree
Showing 22 changed files with 831 additions and 2 deletions.
3 changes: 3 additions & 0 deletions gdnative-core/Cargo.toml
Expand Up @@ -14,6 +14,7 @@ edition = "2018"
default = ["nativescript"]
gd_test = []
nativescript = ["bitflags", "parking_lot"]
serde_1 = ["serde", "serde_repr"]
type_tag_fallback = []

[dependencies]
Expand All @@ -24,6 +25,8 @@ glam = "0.18.0"
indexmap = "1.7.0"
ahash = "0.7.4"
once_cell = "1.8.0"
serde = { version = "1", features = ["derive"], optional = true }
serde_repr = { version = "0.1.7", optional = true }

gdnative-impl-proc-macros = { path = "../impl/proc_macros", version = "=0.9.3" }

Expand Down
1 change: 1 addition & 0 deletions gdnative-core/src/core_types/color.rs
Expand Up @@ -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,
Expand Down
8 changes: 8 additions & 0 deletions gdnative-core/src/core_types/error.rs
Expand Up @@ -2,6 +2,14 @@ use crate::sys;

/// Error codes used in various Godot APIs.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(
feature = "serde_repr",
derive(serde_repr::Serialize_repr, serde_repr::Deserialize_repr)
)]
#[cfg_attr(
all(feature = "serde", not(feature = "serde_repr")),
derive(serde::Serialize, serde::Deserialize)
)]
#[repr(u32)]
pub enum GodotError {
Failed = sys::godot_error_GODOT_FAILED as u32,
Expand Down
1 change: 1 addition & 0 deletions gdnative-core/src/core_types/geom/aabb.rs
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions gdnative-core/src/core_types/geom/basis.rs
Expand Up @@ -5,6 +5,7 @@ use glam::Mat3;
/// 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],
}
Expand Down
1 change: 1 addition & 0 deletions gdnative-core/src/core_types/geom/plane.rs
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions gdnative-core/src/core_types/geom/transform.rs
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion gdnative-core/src/core_types/mod.rs
Expand Up @@ -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::*;
Expand Down
57 changes: 57 additions & 0 deletions gdnative-core/src/core_types/node_path.rs
Expand Up @@ -176,3 +176,60 @@ 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<S>(&self, ser: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where
S: Serializer,
{
ser.serialize_newtype_struct("NodePath", &*self.to_string())
}
}

impl<'de> Deserialize<'de> for NodePath {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
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<E>(self, s: &str) -> Result<Self::Value, E>
where
E: Error,
{
Ok(NodePath::from_str(s))
}

fn visit_newtype_struct<D>(
self,
deserializer: D,
) -> Result<Self::Value, <D as Deserializer<'de>>::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(self)
}
}

deserializer.deserialize_newtype_struct("NodePath", NodePathVisitor)
}
}
}
1 change: 1 addition & 0 deletions gdnative-core/src/core_types/quat.rs
Expand Up @@ -3,6 +3,7 @@ use glam::EulerRot;
use std::ops::{Mul, Neg};

#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Quat {
pub x: f32,
Expand Down
2 changes: 2 additions & 0 deletions gdnative-core/src/core_types/rect2.rs
@@ -1,5 +1,7 @@
use super::Vector2;

#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Rect2 {
pub position: Vector2,
Expand Down
50 changes: 50 additions & 0 deletions gdnative-core/src/core_types/string.rs
Expand Up @@ -612,6 +612,56 @@ 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<S>(
&self,
serializer: S,
) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where
S: Serializer,
{
serializer.serialize_str(&*self.to_string())
}
}

#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for GodotString {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::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<E>(self, s: &str) -> Result<Self::Value, E>
where
E: Error,
{
Ok(GodotString::from(s))
}
}

deserializer.deserialize_str(GodotStringVisitor)
}
}
}

godot_test!(test_string {
use crate::core_types::{GodotString, Variant, VariantType, ToVariant};

Expand Down
2 changes: 2 additions & 0 deletions gdnative-core/src/core_types/transform2d.rs
@@ -1,5 +1,7 @@
use super::Vector2;

#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Transform2D {
pub x: Vector2,
Expand Down
60 changes: 60 additions & 0 deletions gdnative-core/src/core_types/typed_array.rs
Expand Up @@ -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<T: Serialize + Element> Serialize for TypedArray<T> {
#[inline]
fn serialize<S>(&self, ser: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::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<T> {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
where
D: Deserializer<'de>,
{
struct TypedArrayVisitor<T>(PhantomData<T>);
impl<'de, T: Deserialize<'de> + Element> Visitor<'de> for TypedArrayVisitor<T> {
type Value = TypedArray<T>;

fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str(std::any::type_name::<Self::Value>())
}

fn visit_seq<A>(
self,
mut seq: A,
) -> Result<Self::Value, <A as SeqAccess<'de>>::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::<T>()? {
vec.push(val);
}
Ok(Self::Value::from_vec(vec))
}
}

deserializer.deserialize_seq(TypedArrayVisitor::<T>(PhantomData))
}
}
}
32 changes: 32 additions & 0 deletions gdnative-core/src/core_types/variant.rs
Expand Up @@ -9,6 +9,9 @@ use crate::object::*;
use crate::private::{get_api, ManuallyManagedClassPlaceholder};
use crate::thread_access::*;

#[cfg(feature = "serde")]
mod serde;

// TODO: implement Debug, PartialEq, etc.

/// A `Variant` can represent many of godot's core types.
Expand Down Expand Up @@ -109,6 +112,13 @@ macro_rules! decl_variant_type {
)*
}

impl VariantType {
/// The potential names of VariantTypes. Mostly used for serialization.
pub const NAMES: &'static [&'static str] = &[
$(stringify!($variant),)*
];
}

/// Rust enum associating each primitive variant type to its value.
///
/// For `Variant`s containing objects, the original `Variant` is returned unchanged, due to
Expand All @@ -132,6 +142,19 @@ macro_rules! decl_variant_type {
}
}
}

impl<'a> From<&'a VariantDispatch> for Variant {
#[inline]
fn from(v: &'a VariantDispatch) -> Self {
match v {
$($(VariantDispatch::$variant(v) => {
let v: &$inner = v;
v.to_variant()
})?)*
_ => Variant::new()
}
}
}
}
}

Expand Down Expand Up @@ -173,6 +196,15 @@ impl VariantType {
pub fn from_sys(v: sys::godot_variant_type) -> VariantType {
unsafe { transmute(v as u32) }
}

/// The `stringify!` representation of this variant. Mostly used for serialization.
#[inline]
pub const fn name(&self) -> &'static str {
// NOTE: this assumes that the discriminants remain sequential, since any additions to the
// VariantType enum would require a breaking change anyway since it is not marked as non-exhaustive.
// See also the Deserialize implementation in the serde submodule.
Self::NAMES[*self as usize]
}
}

#[repr(u32)]
Expand Down

0 comments on commit c4f699d

Please sign in to comment.