diff --git a/Cargo.toml b/Cargo.toml index 6f1e237..b126b45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,11 +29,14 @@ name = "cgmath" [features] unstable = [] default = ["rustc-serialize"] +eders = ["serde", "serde_macros"] [dependencies] num-traits = "0.1" rand = "0.3" rustc-serialize = { version = "0.3", optional = true } +serde = { version = "0.7", optional = true } +serde_macros = { version = "0.7", optional = true } [dev-dependencies] glium = "0.14.0" diff --git a/src/angle.rs b/src/angle.rs index f42cd1b..c434129 100644 --- a/src/angle.rs +++ b/src/angle.rs @@ -34,6 +34,7 @@ use num::BaseFloat; #[repr(C, packed)] #[derive(Copy, Clone, PartialEq, PartialOrd)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Rad { pub s: S } /// An angle, in degrees. @@ -42,6 +43,7 @@ pub struct Rad { pub s: S } #[repr(C, packed)] #[derive(Copy, Clone, PartialEq, PartialOrd)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Deg { pub s: S } /// Create a new angle, in radians diff --git a/src/euler.rs b/src/euler.rs index 808cac7..df72875 100644 --- a/src/euler.rs +++ b/src/euler.rs @@ -65,6 +65,7 @@ use num::BaseFloat; #[derive(Copy, Clone, Debug)] #[derive(PartialEq, Eq)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Euler { /// The angle to apply around the _x_ axis. Also known at the _pitch_. pub x: A, diff --git a/src/lib.rs b/src/lib.rs index 1e4ec98..2efb293 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,12 +50,18 @@ //! use cgmath::prelude::*; //! ``` +#![cfg_attr(feature = "eders", feature(plugin, custom_derive))] +#![cfg_attr(feature = "eders", plugin(serde_macros))] + pub extern crate num_traits; extern crate rand; #[cfg(feature = "rustc-serialize")] extern crate rustc_serialize; +#[cfg(feature = "eders")] +extern crate serde; + // Re-exports pub use approx::*; diff --git a/src/matrix.rs b/src/matrix.rs index bdddeb0..7336783 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -37,6 +37,7 @@ use vector::{Vector2, Vector3, Vector4}; #[repr(C, packed)] #[derive(Copy, Clone, PartialEq)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Matrix2 { /// The first column of the matrix. pub x: Vector2, @@ -50,6 +51,7 @@ pub struct Matrix2 { #[repr(C, packed)] #[derive(Copy, Clone, PartialEq)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Matrix3 { /// The first column of the matrix. pub x: Vector3, @@ -65,6 +67,7 @@ pub struct Matrix3 { #[repr(C, packed)] #[derive(Copy, Clone, PartialEq)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Matrix4 { /// The first column of the matrix. pub x: Vector4, diff --git a/src/point.rs b/src/point.rs index 19c2e0b..8ee8393 100644 --- a/src/point.rs +++ b/src/point.rs @@ -33,6 +33,7 @@ use vector::{Vector1, Vector2, Vector3, Vector4}; #[repr(C, packed)] #[derive(PartialEq, Eq, Copy, Clone, Hash)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Point1 { pub x: S, } @@ -43,6 +44,7 @@ pub struct Point1 { #[repr(C, packed)] #[derive(PartialEq, Eq, Copy, Clone, Hash)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Point2 { pub x: S, pub y: S, @@ -54,6 +56,7 @@ pub struct Point2 { #[repr(C, packed)] #[derive(PartialEq, Eq, Copy, Clone, Hash)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Point3 { pub x: S, pub y: S, diff --git a/src/projection.rs b/src/projection.rs index 525073b..d650aa6 100644 --- a/src/projection.rs +++ b/src/projection.rs @@ -68,6 +68,7 @@ pub fn ortho(left: S, right: S, bottom: S, top: S, near: S, far: S /// A perspective projection based on a vertical field-of-view angle. #[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct PerspectiveFov { pub fovy: Rad, pub aspect: S, @@ -135,6 +136,7 @@ impl From> for Matrix4 { /// A perspective projection with arbitrary left/right/bottom/top distances #[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Perspective { pub left: S, pub right: S, @@ -182,6 +184,7 @@ impl From> for Matrix4 { /// An orthographic projection with arbitrary left/right/bottom/top distances #[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Ortho { pub left: S, pub right: S, diff --git a/src/quaternion.rs b/src/quaternion.rs index da9fe6a..7556330 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -38,6 +38,7 @@ use vector::Vector3; #[repr(C, packed)] #[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Quaternion { /// The scalar part of the quaternion. pub s: S, diff --git a/src/rotation.rs b/src/rotation.rs index 3108af7..5b570c4 100644 --- a/src/rotation.rs +++ b/src/rotation.rs @@ -139,6 +139,7 @@ pub trait Rotation3: Rotation> /// ``` #[derive(PartialEq, Copy, Clone)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Basis2 { mat: Matrix2 } @@ -212,6 +213,7 @@ impl fmt::Debug for Basis2 { /// been restricted to a subeset of those implemented on `Matrix3`. #[derive(PartialEq, Copy, Clone)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Basis3 { mat: Matrix3 } diff --git a/src/transform.rs b/src/transform.rs index b033ab6..54a25a0 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -148,3 +148,150 @@ impl> From, R>> for Matrix4< impl> Transform2 for Decomposed, R> {} impl> Transform3 for Decomposed, R> {} + +#[cfg(feature = "eders")] +#[doc(hidden)] +mod eders_ser { + use structure::VectorSpace; + use super::Decomposed; + use serde::{self, Serialize}; + + impl Serialize for Decomposed + where V: Serialize, V::Scalar: Serialize, R: Serialize + { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: serde::Serializer + { + serializer.serialize_struct("Decomposed", DecomposedVisitor { + value: self, + state: 0, + }) + } + } + + struct DecomposedVisitor<'a, V: 'a + VectorSpace, R: 'a> { + value: &'a Decomposed, + state: u8, + } + + impl<'a, V: 'a + VectorSpace, R> serde::ser::MapVisitor for DecomposedVisitor<'a, V, R> + where V: Serialize, V::Scalar: Serialize, R: Serialize + { + fn visit(&mut self, serializer: &mut S) -> Result, S::Error> + where S: serde::Serializer + { + match self.state { + 0 => { + self.state += 1; + Ok(Some(try!(serializer.serialize_struct_elt("scale", &self.value.scale)))) + }, + 1 => { + self.state += 1; + Ok(Some(try!(serializer.serialize_struct_elt("rot", &self.value.rot)))) + }, + 2 => { + self.state += 1; + Ok(Some(try!(serializer.serialize_struct_elt("disp", &self.value.disp)))) + }, + _ => { + Ok(None) + }, + } + } + } +} + +#[cfg(feature = "eders")] +#[doc(hidden)] +mod eders_de { + use structure::VectorSpace; + use super::Decomposed; + use serde::{self, Deserialize}; + use std::marker::PhantomData; + + enum DecomposedField { + Scale, + Rot, + Disp, + } + + impl Deserialize for DecomposedField { + fn deserialize(deserializer: &mut D) -> Result + where D: serde::Deserializer + { + struct DecomposedFieldVisitor; + + impl serde::de::Visitor for DecomposedFieldVisitor { + type Value = DecomposedField; + + fn visit_str(&mut self, value: &str) -> Result + where E: serde::de::Error + { + match value { + "scale" => Ok(DecomposedField::Scale), + "rot" => Ok(DecomposedField::Rot), + "disp" => Ok(DecomposedField::Disp), + _ => Err(serde::de::Error::custom("expected scale, rot or disp")), + } + } + } + + deserializer.deserialize(DecomposedFieldVisitor) + } + } + + impl Deserialize for Decomposed + where S: Deserialize, S::Scalar: Deserialize, R: Deserialize + { + fn deserialize(deserializer: &mut D) -> Result, D::Error> + where D: serde::de::Deserializer + { + const FIELDS: &'static [&'static str] = &["scale", "rot", "disp"]; + deserializer.deserialize_struct("Decomposed", FIELDS, DecomposedVisitor(PhantomData)) + } + } + + struct DecomposedVisitor(PhantomData<(S, R)>); + + impl serde::de::Visitor for DecomposedVisitor + where S: Deserialize, S::Scalar: Deserialize, R: Deserialize + { + type Value = Decomposed; + + fn visit_map(&mut self, mut visitor: V) -> Result, V::Error> + where V: serde::de::MapVisitor + { + let mut scale = None; + let mut rot = None; + let mut disp = None; + + loop { + match try!(visitor.visit_key()) { + Some(DecomposedField::Scale) => { scale = Some(try!(visitor.visit_value())); }, + Some(DecomposedField::Rot) => { rot = Some(try!(visitor.visit_value())); }, + Some(DecomposedField::Disp) => { disp = Some(try!(visitor.visit_value())); }, + _ => { break; }, + } + } + + let scale = match scale { + Some(scale) => scale, + None => try!(visitor.missing_field("scale")), + }; + + let rot = match rot { + Some(rot) => rot, + None => try!(visitor.missing_field("rot")), + }; + + let disp = match disp { + Some(disp) => disp, + None => try!(visitor.missing_field("disp")), + }; + + try!(visitor.end()); + + Ok(Decomposed { scale: scale, rot: rot, disp: disp }) + } + } +} \ No newline at end of file diff --git a/src/vector.rs b/src/vector.rs index a0f5a82..d3c7997 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -31,6 +31,7 @@ use num::{BaseNum, BaseFloat, PartialOrd}; #[repr(C, packed)] #[derive(PartialEq, Eq, Copy, Clone, Hash)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Vector1 { /// The x component of the vector. pub x: S, @@ -42,6 +43,7 @@ pub struct Vector1 { #[repr(C, packed)] #[derive(PartialEq, Eq, Copy, Clone, Hash)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Vector2 { /// The x component of the vector. pub x: S, @@ -55,6 +57,7 @@ pub struct Vector2 { #[repr(C, packed)] #[derive(PartialEq, Eq, Copy, Clone, Hash)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Vector3 { /// The x component of the vector. pub x: S, @@ -70,6 +73,7 @@ pub struct Vector3 { #[repr(C, packed)] #[derive(PartialEq, Eq, Copy, Clone, Hash)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))] pub struct Vector4 { /// The x component of the vector. pub x: S,