extern crate serde; #[macro_use] extern crate serde_derive; extern crate zlo; use serde::Deserializer; use serde::Serializer; use zlo::Infinite; use zlo::serialize; use std::fmt; // User input demo that shows how one could encode gamepad input. // In this implementation axis is simply encoded as two i8s instead of two f32s. // This incurs constant precision loss to 256 possible values per axis. An // alternative way would be to encode its length from 0 to 1, a boolean and just // one axis. This approach gives dynamic precision, at small lengths it's most // precise and drops as length gets bigger. #[derive(Serialize, Deserialize)] pub struct TinyUserInput { view_angles: [f32; 3], #[serde(serialize_with = "serialize_axis", deserialize_with = "deserialize_axis")] stick_0: [f32; 2], #[serde(serialize_with = "serialize_axis", deserialize_with = "deserialize_axis")] stick_1: [f32; 2], } #[derive(Serialize, Deserialize)] pub struct NotTinyUserInput { view_angles: [f32; 3], stick_0: [f32; 2], stick_1: [f32; 2], } fn f32_to_i8(x: f32) -> i8 { use std::i8::{MIN, MAX}; assert!(x >= -1.0 && x <= 1.0, "x out of bounds"); (x * (if x < 0.0 { MIN } else { MAX }) as f32) as i8 } fn i8_to_f32(x: i8) -> f32 { use std::i8::{MIN, MAX}; x as f32 * if x < 0 { 1.0 / MIN as f32 } else { 1.0 / MAX as f32 } } fn serialize_axis(axis: &[f32; 2], serializer: S) -> Result where S: Serializer { use serde::ser::SerializeSeq; let mut seq = serializer.serialize_seq(Some(2))?; seq.serialize_element(&f32_to_i8(axis[0]))?; seq.serialize_element(&f32_to_i8(axis[1]))?; seq.end() } fn deserialize_axis<'de, D>(deserializer: D) -> Result<[f32; 2], D::Error> where D: Deserializer<'de> { use serde::de::Visitor; use serde::de::SeqAccess; use serde::de::Error; struct AxisVisitor; impl<'de> Visitor<'de> for AxisVisitor { type Value = [f32; 2]; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "an array of two ints") } fn visit_seq(self, mut visitor: V) -> Result where V: SeqAccess<'de> { let a: i8 = visitor.next_element()?.ok_or(V::Error::invalid_length(0, &"2"))?; let b: i8 = visitor.next_element()?.ok_or(V::Error::invalid_length(1, &"2"))?; Ok([i8_to_f32(a), i8_to_f32(b)]) } } deserializer.deserialize_seq(AxisVisitor) } fn main() { let view_angles = [0.0; 3]; let stick_0 = [1.0, 0.3]; let stick_1 = [0.0, 0.9]; let tiny = TinyUserInput { view_angles, stick_0, stick_1 }; let not_tiny = NotTinyUserInput { view_angles, stick_0, stick_1 }; let a = serialize(&tiny, Infinite).unwrap(); let b = serialize(¬_tiny, Infinite).unwrap(); assert_eq!(a.len(), 8); assert_eq!(b.len(), 13); }