Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d75fdf7

Browse files
authoredSep 15, 2021
Try #743:
2 parents 831958c + c4f699d commit d75fdf7

File tree

22 files changed

+831
-2
lines changed

22 files changed

+831
-2
lines changed
 

‎gdnative-core/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ edition = "2018"
1414
default = ["nativescript"]
1515
gd_test = []
1616
nativescript = ["bitflags", "parking_lot"]
17+
serde_1 = ["serde", "serde_repr"]
1718
type_tag_fallback = []
1819

1920
[dependencies]
@@ -24,6 +25,8 @@ glam = "0.18.0"
2425
indexmap = "1.7.0"
2526
ahash = "0.7.4"
2627
once_cell = "1.8.0"
28+
serde = { version = "1", features = ["derive"], optional = true }
29+
serde_repr = { version = "0.1.7", optional = true }
2730

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

‎gdnative-core/src/core_types/color.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::core_types::GodotString;
66
/// RGBA color with 32 bits floating point components.
77
#[repr(C)]
88
#[derive(Copy, Clone, Debug, PartialEq)]
9+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
910
pub struct Color {
1011
pub r: f32,
1112
pub g: f32,

‎gdnative-core/src/core_types/error.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@ use crate::sys;
22

33
/// Error codes used in various Godot APIs.
44
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
5+
#[cfg_attr(
6+
feature = "serde_repr",
7+
derive(serde_repr::Serialize_repr, serde_repr::Deserialize_repr)
8+
)]
9+
#[cfg_attr(
10+
all(feature = "serde", not(feature = "serde_repr")),
11+
derive(serde::Serialize, serde::Deserialize)
12+
)]
513
#[repr(u32)]
614
pub enum GodotError {
715
Failed = sys::godot_error_GODOT_FAILED as u32,

‎gdnative-core/src/core_types/geom/aabb.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::core_types::Vector3;
33
/// Axis-aligned bounding box.
44
#[repr(C)]
55
#[derive(Copy, Clone, Debug, PartialEq)]
6+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
67
pub struct Aabb {
78
pub position: Vector3,
89
pub size: Vector3,

‎gdnative-core/src/core_types/geom/basis.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use glam::Mat3;
55
/// A 3x3 matrix.
66
#[repr(C)]
77
#[derive(Copy, Clone, Debug, PartialEq)]
8+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
89
pub struct Basis {
910
pub elements: [Vector3; 3],
1011
}

‎gdnative-core/src/core_types/geom/plane.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::core_types::{IsEqualApprox, Vector3};
33
/// Plane in hessian form.
44
#[repr(C)]
55
#[derive(Copy, Clone, Debug, PartialEq)]
6+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
67
pub struct Plane {
78
pub normal: Vector3,
89
pub d: f32,

‎gdnative-core/src/core_types/geom/transform.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::core_types::{Basis, Vector3};
33
/// 3D Transformation (3x4 matrix) Using basis + origin representation.
44
#[repr(C)]
55
#[derive(Copy, Clone, Debug, PartialEq)]
6+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
67
pub struct Transform {
78
/// The basis is a matrix containing 3 Vector3 as its columns: X axis, Y axis, and Z axis.
89
/// These vectors can be interpreted as the basis vectors of local coordinate system

‎gdnative-core/src/core_types/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub use rid::*;
4343
pub use string::*;
4444
pub use string_array::*;
4545
pub use transform2d::*;
46-
pub use typed_array::TypedArray;
46+
pub use typed_array::{Element, TypedArray};
4747
pub use variant::*;
4848
pub use variant_array::*;
4949
pub use vector2::*;

‎gdnative-core/src/core_types/node_path.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,60 @@ impl fmt::Debug for NodePath {
176176
write!(f, "NodePath({})", self.to_string())
177177
}
178178
}
179+
180+
#[cfg(feature = "serde")]
181+
mod serde {
182+
use super::*;
183+
use ::serde::{
184+
de::{Error, Visitor},
185+
Deserialize, Deserializer, Serialize, Serializer,
186+
};
187+
use std::fmt::Formatter;
188+
189+
impl Serialize for NodePath {
190+
#[inline]
191+
fn serialize<S>(&self, ser: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
192+
where
193+
S: Serializer,
194+
{
195+
ser.serialize_newtype_struct("NodePath", &*self.to_string())
196+
}
197+
}
198+
199+
impl<'de> Deserialize<'de> for NodePath {
200+
#[inline]
201+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
202+
where
203+
D: Deserializer<'de>,
204+
{
205+
struct NodePathVisitor;
206+
207+
impl<'de> Visitor<'de> for NodePathVisitor {
208+
type Value = NodePath;
209+
210+
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
211+
formatter.write_str("a NodePath")
212+
}
213+
214+
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
215+
where
216+
E: Error,
217+
{
218+
Ok(NodePath::from_str(s))
219+
}
220+
221+
fn visit_newtype_struct<D>(
222+
self,
223+
deserializer: D,
224+
) -> Result<Self::Value, <D as Deserializer<'de>>::Error>
225+
where
226+
D: Deserializer<'de>,
227+
{
228+
deserializer.deserialize_str(self)
229+
}
230+
}
231+
232+
deserializer.deserialize_newtype_struct("NodePath", NodePathVisitor)
233+
}
234+
}
235+
}

‎gdnative-core/src/core_types/quat.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use glam::EulerRot;
33
use std::ops::{Mul, Neg};
44

55
#[derive(Copy, Clone, Debug, PartialEq)]
6+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
67
#[repr(C)]
78
pub struct Quat {
89
pub x: f32,

‎gdnative-core/src/core_types/rect2.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use super::Vector2;
22

3+
#[derive(Copy, Clone, Debug, PartialEq)]
4+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35
#[repr(C)]
46
pub struct Rect2 {
57
pub position: Vector2,

‎gdnative-core/src/core_types/string.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,56 @@ where
612612
}
613613
}
614614

615+
#[cfg(feature = "serde")]
616+
mod serde {
617+
use super::*;
618+
use ::serde::{
619+
de::{Error, Visitor},
620+
Deserialize, Deserializer, Serialize, Serializer,
621+
};
622+
use std::fmt::Formatter;
623+
624+
impl Serialize for GodotString {
625+
#[inline]
626+
fn serialize<S>(
627+
&self,
628+
serializer: S,
629+
) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
630+
where
631+
S: Serializer,
632+
{
633+
serializer.serialize_str(&*self.to_string())
634+
}
635+
}
636+
637+
#[cfg(feature = "serde")]
638+
impl<'de> serde::Deserialize<'de> for GodotString {
639+
#[inline]
640+
fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
641+
where
642+
D: Deserializer<'de>,
643+
{
644+
struct GodotStringVisitor;
645+
impl<'de> Visitor<'de> for GodotStringVisitor {
646+
type Value = GodotString;
647+
648+
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
649+
formatter.write_str("a GodotString")
650+
}
651+
652+
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
653+
where
654+
E: Error,
655+
{
656+
Ok(GodotString::from(s))
657+
}
658+
}
659+
660+
deserializer.deserialize_str(GodotStringVisitor)
661+
}
662+
}
663+
}
664+
615665
godot_test!(test_string {
616666
use crate::core_types::{GodotString, Variant, VariantType, ToVariant};
617667

‎gdnative-core/src/core_types/transform2d.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use super::Vector2;
22

3+
#[derive(Copy, Clone, Debug, PartialEq)]
4+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35
#[repr(C)]
46
pub struct Transform2D {
57
pub x: Vector2,

‎gdnative-core/src/core_types/typed_array.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,3 +483,63 @@ macros::impl_typed_array_element! {
483483
mod private {
484484
pub trait Sealed {}
485485
}
486+
487+
#[cfg(feature = "serde")]
488+
mod serde {
489+
use super::*;
490+
use ::serde::{
491+
de::{SeqAccess, Visitor},
492+
ser::SerializeSeq,
493+
Deserialize, Deserializer, Serialize, Serializer,
494+
};
495+
use std::fmt::Formatter;
496+
use std::marker::PhantomData;
497+
498+
impl<T: Serialize + Element> Serialize for TypedArray<T> {
499+
#[inline]
500+
fn serialize<S>(&self, ser: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
501+
where
502+
S: Serializer,
503+
{
504+
let read = self.read();
505+
let mut ser = ser.serialize_seq(Some(read.len()))?;
506+
for e in read.iter() {
507+
ser.serialize_element(e)?
508+
}
509+
ser.end()
510+
}
511+
}
512+
513+
impl<'de, T: Deserialize<'de> + Element> Deserialize<'de> for TypedArray<T> {
514+
#[inline]
515+
fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
516+
where
517+
D: Deserializer<'de>,
518+
{
519+
struct TypedArrayVisitor<T>(PhantomData<T>);
520+
impl<'de, T: Deserialize<'de> + Element> Visitor<'de> for TypedArrayVisitor<T> {
521+
type Value = TypedArray<T>;
522+
523+
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
524+
formatter.write_str(std::any::type_name::<Self::Value>())
525+
}
526+
527+
fn visit_seq<A>(
528+
self,
529+
mut seq: A,
530+
) -> Result<Self::Value, <A as SeqAccess<'de>>::Error>
531+
where
532+
A: SeqAccess<'de>,
533+
{
534+
let mut vec = seq.size_hint().map_or_else(Vec::new, Vec::with_capacity);
535+
while let Some(val) = seq.next_element::<T>()? {
536+
vec.push(val);
537+
}
538+
Ok(Self::Value::from_vec(vec))
539+
}
540+
}
541+
542+
deserializer.deserialize_seq(TypedArrayVisitor::<T>(PhantomData))
543+
}
544+
}
545+
}

‎gdnative-core/src/core_types/variant.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ use crate::object::*;
99
use crate::private::{get_api, ManuallyManagedClassPlaceholder};
1010
use crate::thread_access::*;
1111

12+
#[cfg(feature = "serde")]
13+
mod serde;
14+
1215
// TODO: implement Debug, PartialEq, etc.
1316

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

115+
impl VariantType {
116+
/// The potential names of VariantTypes. Mostly used for serialization.
117+
pub const NAMES: &'static [&'static str] = &[
118+
$(stringify!($variant),)*
119+
];
120+
}
121+
112122
/// Rust enum associating each primitive variant type to its value.
113123
///
114124
/// For `Variant`s containing objects, the original `Variant` is returned unchanged, due to
@@ -132,6 +142,19 @@ macro_rules! decl_variant_type {
132142
}
133143
}
134144
}
145+
146+
impl<'a> From<&'a VariantDispatch> for Variant {
147+
#[inline]
148+
fn from(v: &'a VariantDispatch) -> Self {
149+
match v {
150+
$($(VariantDispatch::$variant(v) => {
151+
let v: &$inner = v;
152+
v.to_variant()
153+
})?)*
154+
_ => Variant::new()
155+
}
156+
}
157+
}
135158
}
136159
}
137160

@@ -173,6 +196,15 @@ impl VariantType {
173196
pub fn from_sys(v: sys::godot_variant_type) -> VariantType {
174197
unsafe { transmute(v as u32) }
175198
}
199+
200+
/// The `stringify!` representation of this variant. Mostly used for serialization.
201+
#[inline]
202+
pub const fn name(&self) -> &'static str {
203+
// NOTE: this assumes that the discriminants remain sequential, since any additions to the
204+
// VariantType enum would require a breaking change anyway since it is not marked as non-exhaustive.
205+
// See also the Deserialize implementation in the serde submodule.
206+
Self::NAMES[*self as usize]
207+
}
176208
}
177209

178210
#[repr(u32)]
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
use super::*;
2+
use ::serde::{
3+
de::{EnumAccess, Error, SeqAccess, VariantAccess, Visitor},
4+
ser::{Error as _, SerializeSeq},
5+
Deserialize, Deserializer, Serialize, Serializer,
6+
};
7+
use std::fmt::Formatter;
8+
9+
/// Custom implementation to allow using the same visitor for VariantType as well as the discriminant
10+
/// of VariantDispatch.
11+
struct VariantTypeVisitor;
12+
13+
impl<'de> Visitor<'de> for VariantTypeVisitor {
14+
type Value = VariantType;
15+
16+
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
17+
formatter.write_str("a VariantType")
18+
}
19+
20+
#[inline]
21+
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
22+
where
23+
E: Error,
24+
{
25+
if value < VariantType::NAMES.len() as u64 {
26+
Ok(VariantType::from_sys(value as sys::godot_variant_type))
27+
} else {
28+
Err(E::custom(&*format!("invalid VariantType value: {}", value)))
29+
}
30+
}
31+
32+
#[inline]
33+
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
34+
where
35+
E: Error,
36+
{
37+
for (i, &name) in VariantType::NAMES.iter().enumerate() {
38+
if name == value {
39+
return Ok(VariantType::from_sys(i as sys::godot_variant_type));
40+
}
41+
}
42+
Err(E::custom(&*format!(
43+
"invalid VariantType value: {:?}",
44+
value
45+
)))
46+
}
47+
48+
#[inline]
49+
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
50+
where
51+
E: Error,
52+
{
53+
for (i, &name) in VariantType::NAMES.iter().enumerate() {
54+
if name.as_bytes() == value {
55+
return Ok(VariantType::from_sys(i as sys::godot_variant_type));
56+
}
57+
}
58+
Err(E::custom(&*format!(
59+
"invalid VariantType value: {:?}",
60+
value
61+
)))
62+
}
63+
64+
#[inline]
65+
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
66+
where
67+
A: EnumAccess<'de>,
68+
{
69+
let (t, v) = data.variant::<VariantType>()?;
70+
v.unit_variant()?;
71+
Ok(t)
72+
}
73+
}
74+
75+
impl<'de> Deserialize<'de> for VariantType {
76+
#[inline]
77+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
78+
where
79+
D: Deserializer<'de>,
80+
{
81+
// NOTE: serde assumes that serialized indices correspond to the indices in the NAMES array.
82+
// If any non-sequential VariantType values were added in the future, this could break, but
83+
// that seems extremely unlikely, and would require a breaking change to godot-rust anyway
84+
// since VariantType is not marked as non-exhaustive.
85+
deserializer.deserialize_enum("VariantType", VariantType::NAMES, VariantTypeVisitor)
86+
}
87+
}
88+
89+
/// Enables calling `deserialize_identifier` instead of `deserialize_enum` when deserializing VariantDispatch.
90+
struct VariantDispatchDiscriminant(VariantType);
91+
92+
impl<'de> Deserialize<'de> for VariantDispatchDiscriminant {
93+
#[inline]
94+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
95+
where
96+
D: Deserializer<'de>,
97+
{
98+
deserializer
99+
.deserialize_identifier(VariantTypeVisitor)
100+
.map(Self)
101+
}
102+
}
103+
104+
/// This allows (de)serializing to/from non-self-describing formats by avoiding serializing `Variant`s
105+
// Can't just use a HashMap because VariantDispatch doesn't implement Hash, and this avoids cloning all of the entries anyway
106+
struct DictionaryDispatch(Dictionary);
107+
108+
#[derive(Serialize, Deserialize)]
109+
struct DictionaryDispatchEntry {
110+
key: VariantDispatch,
111+
value: VariantDispatch,
112+
}
113+
114+
impl<'d> Serialize for DictionaryDispatch {
115+
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
116+
where
117+
S: Serializer,
118+
{
119+
let mut ser = serializer.serialize_seq(Some(self.0.len() as usize))?;
120+
for (key, value) in self.0.iter() {
121+
ser.serialize_element(&DictionaryDispatchEntry {
122+
key: key.dispatch(),
123+
value: value.dispatch(),
124+
})?;
125+
}
126+
ser.end()
127+
}
128+
}
129+
130+
impl<'de> Deserialize<'de> for DictionaryDispatch {
131+
fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
132+
where
133+
D: Deserializer<'de>,
134+
{
135+
struct DictionaryDispatchVisitor;
136+
impl<'de> Visitor<'de> for DictionaryDispatchVisitor {
137+
type Value = DictionaryDispatch;
138+
139+
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
140+
formatter.write_str("a sequence of VariantDispatch pairs")
141+
}
142+
143+
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
144+
where
145+
A: SeqAccess<'de>,
146+
{
147+
let dict = Dictionary::new();
148+
while let Some(DictionaryDispatchEntry { key, value }) = seq.next_element()? {
149+
dict.insert(Variant::from(&key), Variant::from(&value))
150+
}
151+
Ok(DictionaryDispatch(dict.into_shared()))
152+
}
153+
}
154+
deserializer.deserialize_seq(DictionaryDispatchVisitor)
155+
}
156+
}
157+
158+
impl Serialize for VariantDispatch {
159+
#[inline]
160+
fn serialize<S>(&self, ser: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
161+
where
162+
S: Serializer,
163+
{
164+
use VariantDispatch::*;
165+
166+
const NAME: &str = "VariantDispatch";
167+
168+
macro_rules! newtype_variant {
169+
($t:expr, $v:expr) => {
170+
ser.serialize_newtype_variant(NAME, $t as u32, $t.name(), $v)
171+
};
172+
}
173+
match self {
174+
Nil => {
175+
ser.serialize_unit_variant(NAME, VariantType::Nil as u32, VariantType::Nil.name())
176+
}
177+
Bool(v) => newtype_variant!(VariantType::Bool, v),
178+
I64(v) => newtype_variant!(VariantType::I64, v),
179+
F64(v) => newtype_variant!(VariantType::F64, v),
180+
GodotString(v) => newtype_variant!(VariantType::GodotString, v),
181+
Vector2(v) => newtype_variant!(VariantType::Vector2, v),
182+
Rect2(v) => newtype_variant!(VariantType::Rect2, v),
183+
Vector3(v) => newtype_variant!(VariantType::Vector3, v),
184+
Transform2D(v) => newtype_variant!(VariantType::Transform2D, v),
185+
Plane(v) => newtype_variant!(VariantType::Plane, v),
186+
Quat(v) => newtype_variant!(VariantType::Quat, v),
187+
Aabb(v) => newtype_variant!(VariantType::Aabb, v),
188+
Basis(v) => newtype_variant!(VariantType::Basis, v),
189+
Transform(v) => newtype_variant!(VariantType::Transform, v),
190+
Color(v) => newtype_variant!(VariantType::Color, v),
191+
NodePath(v) => newtype_variant!(VariantType::NodePath, v),
192+
Rid(_) => Err(S::Error::custom("RID's cannot be persisted")),
193+
Object(_) => Err(S::Error::custom(
194+
"Serialization of Objects is not supported",
195+
)),
196+
Dictionary(v) => {
197+
newtype_variant!(VariantType::Dictionary, &DictionaryDispatch(v.new_ref()))
198+
}
199+
VariantArray(v) => {
200+
// Allows serializing to non-self-describing formats by avoiding serializing `Variant`s
201+
let vec = v.iter().map(|v| v.dispatch()).collect::<Vec<_>>();
202+
newtype_variant!(VariantType::VariantArray, &vec)
203+
}
204+
ByteArray(v) => newtype_variant!(VariantType::ByteArray, v),
205+
Int32Array(v) => newtype_variant!(VariantType::Int32Array, v),
206+
Float32Array(v) => newtype_variant!(VariantType::Float32Array, v),
207+
StringArray(v) => newtype_variant!(VariantType::StringArray, v),
208+
Vector2Array(v) => newtype_variant!(VariantType::Vector2Array, v),
209+
Vector3Array(v) => newtype_variant!(VariantType::Vector3Array, v),
210+
ColorArray(v) => newtype_variant!(VariantType::ColorArray, v),
211+
}
212+
}
213+
}
214+
215+
struct VariantDispatchVisitor;
216+
217+
impl<'de> Visitor<'de> for VariantDispatchVisitor {
218+
type Value = VariantDispatch;
219+
220+
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
221+
formatter.write_str("enum VariantDispatch")
222+
}
223+
224+
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
225+
where
226+
A: EnumAccess<'de>,
227+
{
228+
use VariantType::*;
229+
let (t, v) = data.variant::<VariantDispatchDiscriminant>()?;
230+
Ok(match t.0 {
231+
Nil => {
232+
v.unit_variant()?;
233+
VariantDispatch::Nil
234+
}
235+
Bool => VariantDispatch::Bool(v.newtype_variant()?),
236+
I64 => VariantDispatch::I64(v.newtype_variant()?),
237+
F64 => VariantDispatch::F64(v.newtype_variant()?),
238+
GodotString => VariantDispatch::GodotString(v.newtype_variant()?),
239+
Vector2 => VariantDispatch::Vector2(v.newtype_variant()?),
240+
Rect2 => VariantDispatch::Rect2(v.newtype_variant()?),
241+
Vector3 => VariantDispatch::Vector3(v.newtype_variant()?),
242+
Transform2D => VariantDispatch::Transform2D(v.newtype_variant()?),
243+
Plane => VariantDispatch::Plane(v.newtype_variant()?),
244+
Quat => VariantDispatch::Quat(v.newtype_variant()?),
245+
Aabb => VariantDispatch::Aabb(v.newtype_variant()?),
246+
Basis => VariantDispatch::Basis(v.newtype_variant()?),
247+
Transform => VariantDispatch::Transform(v.newtype_variant()?),
248+
Color => VariantDispatch::Color(v.newtype_variant()?),
249+
NodePath => VariantDispatch::NodePath(v.newtype_variant()?),
250+
Rid => return Err(A::Error::custom("Not sure how an RID got serialized")),
251+
Object => return Err(A::Error::custom("Not sure how an Object got serialized")),
252+
Dictionary => VariantDispatch::Dictionary(v.newtype_variant::<DictionaryDispatch>()?.0),
253+
VariantArray => VariantDispatch::VariantArray(
254+
v.newtype_variant::<Vec<VariantDispatch>>()?
255+
.iter()
256+
.map(Into::<Variant>::into)
257+
.collect::<variant_array::VariantArray<Unique>>()
258+
.into_shared(),
259+
),
260+
ByteArray => VariantDispatch::ByteArray(v.newtype_variant()?),
261+
Int32Array => VariantDispatch::Int32Array(v.newtype_variant()?),
262+
Float32Array => VariantDispatch::Float32Array(v.newtype_variant()?),
263+
StringArray => VariantDispatch::StringArray(v.newtype_variant()?),
264+
Vector2Array => VariantDispatch::Vector2Array(v.newtype_variant()?),
265+
Vector3Array => VariantDispatch::Vector3Array(v.newtype_variant()?),
266+
ColorArray => VariantDispatch::ColorArray(v.newtype_variant()?),
267+
})
268+
}
269+
}
270+
271+
impl<'de> Deserialize<'de> for VariantDispatch {
272+
#[inline]
273+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
274+
where
275+
D: Deserializer<'de>,
276+
{
277+
deserializer.deserialize_enum(
278+
"VariantDispatch",
279+
VariantType::NAMES,
280+
VariantDispatchVisitor,
281+
)
282+
}
283+
}

‎gdnative-core/src/core_types/vector2.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use glam::Vec2;
33
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
44

55
#[derive(Copy, Clone, Debug, PartialEq, Default)]
6+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
67
#[repr(C)]
78
pub struct Vector2 {
89
pub x: f32,

‎gdnative-core/src/core_types/vector3.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use glam::Vec3A;
44
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
55

66
#[derive(Copy, Clone, Debug, PartialEq, Default)]
7+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
78
#[repr(C)]
89
pub struct Vector3 {
910
pub x: f32,

‎gdnative/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ edition = "2018"
1414
[features]
1515
default = ["bindings"]
1616
formatted = ["gdnative-bindings/formatted", "gdnative-bindings/one_class_one_file"]
17+
serde = ["gdnative-core/serde_1"]
1718

1819
gd_test = ["gdnative-core/gd_test"]
1920
type_tag_fallback = ["gdnative-core/type_tag_fallback"]

‎test/Cargo.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ default = []
1313
type_tag_fallback = ["gdnative/type_tag_fallback"]
1414

1515
[dependencies]
16-
gdnative = { path = "../gdnative", features = ["gd_test"] }
16+
gdnative = { path = "../gdnative", features = ["gd_test", "serde"] }
1717
gdnative-derive = { path = "../gdnative-derive" }
1818
approx = "0.5.0"
19+
ron = "0.6.4"
20+
serde = "1"
21+
serde_json = "1.0.64"
22+
bincode = "1.3.3"
23+
serde_cbor = "0.11.1"
24+
serde_yaml = "0.8.17"
25+
rmp-serde = "0.15.5"

‎test/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod test_free_ub;
88
mod test_map_owned;
99
mod test_register;
1010
mod test_return_leak;
11+
mod test_serde;
1112
mod test_vararray_return;
1213
mod test_variant_call_args;
1314
mod test_variant_ops;
@@ -66,6 +67,7 @@ pub extern "C" fn run_tests(
6667
status &= test_map_owned::run_tests();
6768
status &= test_register::run_tests();
6869
status &= test_return_leak::run_tests();
70+
status &= test_serde::run_tests();
6971
status &= test_variant_call_args::run_tests();
7072
status &= test_variant_ops::run_tests();
7173
status &= test_vararray_return::run_tests();

‎test/src/test_serde.rs

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
use ::serde::{Deserialize, Serialize};
2+
use gdnative::prelude::*;
3+
4+
pub(crate) fn run_tests() -> bool {
5+
println!(" -- serde tests:");
6+
let mut status = true;
7+
8+
// All tests depend on these invariants
9+
status &= test_variant_eq();
10+
status &= test_dispatch_eq();
11+
if !status {
12+
gdnative::godot_error!(" !!!! Can't run serde tests, Foo::[to/from]_variant is broken!");
13+
return false;
14+
}
15+
16+
status &= test_ron();
17+
status &= test_json();
18+
status &= test_yaml();
19+
status &= test_cbor();
20+
status &= test_msgpack();
21+
status &= test_bincode();
22+
23+
status
24+
}
25+
26+
#[derive(Debug, PartialEq, Serialize, Deserialize, ToVariant, FromVariant)]
27+
struct Foo {
28+
some: Option<bool>,
29+
none: Option<bool>,
30+
b: bool,
31+
int: i64,
32+
float: f64,
33+
str: GodotString,
34+
vec2: Vector2,
35+
rect2: Rect2,
36+
vec3: Vector3,
37+
xform_2d: Transform2D,
38+
plane: Plane,
39+
quat: Quat,
40+
aabb: Aabb,
41+
basis: Basis,
42+
xform: Transform,
43+
color: Color,
44+
path: NodePath,
45+
// dict: Dictionary, //TODO: PartialEq
46+
// v_arr: VariantArray, //TODO: PartialEq
47+
byte_arr: ByteArray,
48+
int_arr: Int32Array,
49+
float_arr: Float32Array,
50+
str_arr: StringArray,
51+
vec2_arr: Vector2Array,
52+
vec3_arr: Vector3Array,
53+
color_arr: ColorArray,
54+
}
55+
56+
impl Foo {
57+
fn new() -> Self {
58+
Self {
59+
some: Some(true),
60+
none: None,
61+
b: false,
62+
int: 1,
63+
float: 2.0,
64+
str: "this is a GodotString".into(),
65+
vec2: Vector2::RIGHT,
66+
rect2: Rect2 {
67+
position: Vector2 { x: 46.47, y: -2.0 },
68+
size: Vector2 { x: 3.0, y: 4.8 },
69+
},
70+
vec3: Vector3::BACK,
71+
xform_2d: Transform2D {
72+
x: Vector2::RIGHT,
73+
y: Vector2::DOWN,
74+
origin: Vector2::ZERO,
75+
},
76+
plane: Plane {
77+
normal: Vector3::ONE.normalized(),
78+
d: 3.0,
79+
},
80+
quat: Quat::new(4.1, 5.2, 6.3, 7.5),
81+
aabb: Aabb {
82+
position: Vector3::new(8.2, 9.8, 10.11),
83+
size: Vector3::new(12.13, 14.15, 16.17),
84+
},
85+
basis: Basis::identity().rotated(Vector3::UP, std::f32::consts::TAU / 3.0),
86+
xform: Transform {
87+
basis: Basis::from_euler(Vector3::new(18.19, -20.21, 22.23)),
88+
origin: Vector3::new(24.25, 26.27, 28.29),
89+
},
90+
color: Color::from_rgb(0.549, 0.0, 1.0),
91+
path: "/root/Node".into(),
92+
byte_arr: ByteArray::from_slice(&[30u8, 31u8, 32u8]),
93+
int_arr: Int32Array::from_slice(&[33i32, 34i32, 35i32, 36i32]),
94+
float_arr: Float32Array::from_slice(&[37.38, 39.40]),
95+
str_arr: StringArray::from_vec(vec!["hello".into(), "world".into()]),
96+
vec2_arr: Vector2Array::from_slice(&[
97+
Vector2::UP,
98+
Vector2::UP,
99+
Vector2::DOWN,
100+
Vector2::DOWN,
101+
Vector2::LEFT,
102+
Vector2::RIGHT,
103+
Vector2::LEFT,
104+
Vector2::RIGHT,
105+
]),
106+
vec3_arr: Vector3Array::from_slice(&[
107+
Vector3::ONE * 41.0,
108+
Vector3::BACK * 42.43,
109+
Vector3::FORWARD * 44.45,
110+
]),
111+
color_arr: ColorArray::from_slice(&[Color::from_rgba(0.0, 1.0, 0.627, 0.8)]),
112+
}
113+
}
114+
}
115+
116+
/// Sanity check that a round trip through Variant preserves equality for Foo.
117+
fn test_variant_eq() -> bool {
118+
println!(" -- test_variant_eq");
119+
120+
let ok = std::panic::catch_unwind(|| {
121+
let foo = Foo::new();
122+
let variant = foo.to_variant();
123+
let result = Foo::from_variant(&variant).expect("Foo::from_variant");
124+
assert_eq!(foo, result);
125+
})
126+
.is_ok();
127+
128+
if !ok {
129+
gdnative::godot_error!(" !! Test test_variant_eq failed");
130+
}
131+
132+
ok
133+
}
134+
135+
/// Sanity check that a round trip through VariantDispatch preserves equality for Foo.
136+
fn test_dispatch_eq() -> bool {
137+
println!(" -- test_dispatch_eq");
138+
139+
let ok = std::panic::catch_unwind(|| {
140+
let foo = Foo::new();
141+
let dispatch = foo.to_variant().dispatch();
142+
let result = Foo::from_variant(&Variant::from(&dispatch)).expect("Foo from Dispatch");
143+
assert_eq!(foo, result);
144+
})
145+
.is_ok();
146+
147+
if !ok {
148+
gdnative::godot_error!(" !! Test test_dispatch_eq failed");
149+
}
150+
151+
ok
152+
}
153+
154+
fn test_ron() -> bool {
155+
println!(" -- test_ron");
156+
157+
let ok = std::panic::catch_unwind(|| {
158+
let foo = Foo::new();
159+
160+
let ron_str = ron::to_string(&foo).expect("Foo to RON str");
161+
let mut de = ron::Deserializer::from_str(ron_str.as_ref());
162+
let result = Foo::deserialize(de.as_mut().expect("deserialize Foo from RON")).unwrap();
163+
assert_eq!(foo, result);
164+
165+
let ron_disp_str = ron::to_string(&foo.to_variant().dispatch()).expect("Dispatch to RON");
166+
let mut de = ron::Deserializer::from_str(ron_disp_str.as_ref());
167+
let de = de
168+
.as_mut()
169+
.expect("disp_round_trip ron::Deserializer::from_str");
170+
let disp = VariantDispatch::deserialize(de).expect("Dispatch from RON");
171+
let result = Foo::from_variant(&Variant::from(&disp)).expect("Foo from Dispatch from RON");
172+
assert_eq!(foo, result);
173+
})
174+
.is_ok();
175+
176+
if !ok {
177+
gdnative::godot_error!(" !! Test test_ron failed");
178+
}
179+
180+
ok
181+
}
182+
183+
fn test_json() -> bool {
184+
println!(" -- test_json");
185+
186+
let ok = std::panic::catch_unwind(|| {
187+
let foo = Foo::new();
188+
189+
let json_str = serde_json::to_string(&foo).expect("Foo to JSON");
190+
let result = serde_json::from_str::<Foo>(json_str.as_ref()).expect("Foo from JSON");
191+
assert_eq!(foo, result);
192+
193+
let foo = Foo::new();
194+
let json_disp_str =
195+
serde_json::to_string(&foo.to_variant().dispatch()).expect("Foo Dispatch to JSON");
196+
let disp = serde_json::from_str::<VariantDispatch>(json_disp_str.as_ref())
197+
.expect("Dispatch from JSON");
198+
let result = Foo::from_variant(&Variant::from(&disp)).expect("Foo from Dispatch from JSON");
199+
assert_eq!(foo, result);
200+
})
201+
.is_ok();
202+
203+
if !ok {
204+
gdnative::godot_error!(" !! Test test_json failed");
205+
}
206+
207+
ok
208+
}
209+
210+
fn test_yaml() -> bool {
211+
println!(" -- test_yaml");
212+
213+
let ok = std::panic::catch_unwind(|| {
214+
let foo = Foo::new();
215+
216+
let yaml_str = serde_yaml::to_string(&foo).expect("Foo to YAML");
217+
let result = serde_yaml::from_str::<Foo>(&yaml_str).expect("Foo from YAML");
218+
assert_eq!(foo, result);
219+
220+
let yaml_str =
221+
serde_yaml::to_string(&foo.to_variant().dispatch()).expect("Dispatch to YAML");
222+
let disp = serde_yaml::from_str::<VariantDispatch>(&yaml_str).expect("Dispatch from YAML");
223+
let result = Foo::from_variant(&Variant::from(&disp)).expect("Foo from Dispatch from YAML");
224+
assert_eq!(foo, result);
225+
})
226+
.is_ok();
227+
228+
if !ok {
229+
gdnative::godot_error!(" !! Test test_yaml failed");
230+
}
231+
232+
ok
233+
}
234+
235+
fn test_cbor() -> bool {
236+
println!(" -- test_cbor");
237+
238+
let ok = std::panic::catch_unwind(|| {
239+
let foo = Foo::new();
240+
241+
let cbor_bytes = serde_cbor::to_vec(&foo).expect("Foo to CBOR");
242+
let result = serde_cbor::from_slice::<Foo>(&cbor_bytes).expect("Foo from CBOR");
243+
assert_eq!(foo, result);
244+
245+
let cbor_bytes =
246+
serde_cbor::to_vec(&foo.to_variant().dispatch()).expect("Dispatch to CBOR");
247+
let disp =
248+
serde_cbor::from_slice::<VariantDispatch>(&cbor_bytes).expect("Dispatch from CBOR");
249+
let result = Foo::from_variant(&Variant::from(&disp)).expect("Foo from Dispatch from CBOR");
250+
assert_eq!(foo, result);
251+
})
252+
.is_ok();
253+
254+
if !ok {
255+
gdnative::godot_error!(" !! Test test_cbor failed");
256+
}
257+
258+
ok
259+
}
260+
261+
fn test_msgpack() -> bool {
262+
println!(" -- test_msgpack");
263+
264+
let ok = std::panic::catch_unwind(|| {
265+
let foo = Foo::new();
266+
267+
let msgpack_bytes = rmp_serde::to_vec_named(&foo).expect("Foo to MessagePack");
268+
let result =
269+
rmp_serde::from_read_ref::<_, Foo>(&msgpack_bytes).expect("Foo from MessagePack");
270+
assert_eq!(foo, result);
271+
272+
let msgpack_disp_bytes =
273+
rmp_serde::to_vec_named(&foo.to_variant().dispatch()).expect("Dispatch to MessagePack");
274+
let disp = rmp_serde::from_read_ref::<_, VariantDispatch>(&msgpack_disp_bytes)
275+
.expect("Dispatch from MessagePack");
276+
let result =
277+
Foo::from_variant(&Variant::from(&disp)).expect("Foo from Dispatch from MessagePack");
278+
assert_eq!(foo, result);
279+
})
280+
.is_ok();
281+
282+
if !ok {
283+
gdnative::godot_error!(" !! Test test_msgpack failed");
284+
}
285+
286+
ok
287+
}
288+
289+
fn test_bincode() -> bool {
290+
println!(" -- test_bincode");
291+
292+
let ok = std::panic::catch_unwind(|| {
293+
let foo = Foo::new();
294+
295+
let bincode_bytes = bincode::serialize(&foo).expect("Foo to bincode");
296+
let result = bincode::deserialize::<Foo>(bincode_bytes.as_ref()).expect("Foo from bincode");
297+
assert_eq!(foo, result);
298+
299+
let bincode_bytes =
300+
bincode::serialize(&foo.to_variant().dispatch()).expect("Dispatch to bincode");
301+
let disp = bincode::deserialize::<VariantDispatch>(bincode_bytes.as_ref())
302+
.expect("Dispatch from bincode");
303+
let result =
304+
Foo::from_variant(&Variant::from(&disp)).expect("Foo from Dispatch from bincode");
305+
assert_eq!(foo, result);
306+
})
307+
.is_ok();
308+
309+
if !ok {
310+
gdnative::godot_error!(" !! Test test_bincode failed");
311+
}
312+
313+
ok
314+
}

0 commit comments

Comments
 (0)
Please sign in to comment.