skrillax_serde/
lib.rs

1//! `skrillax-serde` provides definitions for serialization/deserialization of
2//! data structures used in Silkroad Online.
3//!
4//! Generally, you won't be implementing the traits provided here, but will be
5//! automatically deriving these instead. We provide three traits: [Serialize],
6//! [Deserialize], and [ByteSize], for serializing, deserializing, and
7//! estimating the size respectively.
8
9pub mod error;
10mod time;
11
12use byteorder::ReadBytesExt;
13use bytes::{BufMut, BytesMut};
14pub use error::SerializationError;
15use std::io::Read;
16
17#[cfg(feature = "derive")]
18pub use skrillax_serde_derive::{ByteSize, Deserialize, Serialize};
19#[cfg(feature = "chrono")]
20pub use time::SilkroadTime;
21
22// This is necessary, because otherwise we'd need to make the user of our derive
23// traits add `use` definitions for `bytes` and `byteorder`. Which would require
24// them also to add these as dependencies of their own. Yikes.
25#[doc(hidden)]
26pub mod __internal {
27    pub use byteorder;
28    pub use bytes;
29}
30
31macro_rules! implement_primitive {
32    ($tt:ty, $read:ident) => {
33        impl Serialize for $tt {
34            fn write_to(&self, writer: &mut ::bytes::BytesMut) {
35                writer.put_slice(&self.to_le_bytes());
36            }
37        }
38
39        impl ByteSize for $tt {
40            fn byte_size(&self) -> usize {
41                std::mem::size_of::<$tt>()
42            }
43        }
44
45        impl Deserialize for $tt {
46            fn read_from<T: std::io::Read + ::byteorder::ReadBytesExt>(
47                reader: &mut T,
48            ) -> Result<Self, SerializationError> {
49                Ok(reader.$read::<::byteorder::LittleEndian>()?)
50            }
51        }
52    };
53}
54
55/// The `Serialize` trait allows an item to be serialized into a binary
56/// representation of itself, which may then be used send it off over
57/// the network. This trait requires the [ByteSize] trait to also be
58/// present in order to pre-allocate the necessary amount of space for
59/// the serialized data.
60///
61/// `Serialize` only provides one method: [Serialize::write_to]. This
62/// method is used to serialize the data and write it into the given
63/// buffer. This buffer may already contain data unrelated to this item
64/// and may have more space available for more items to follow. However,
65/// it is always at least the size provided by [ByteSize].
66pub trait Serialize: ByteSize {
67    /// Writes all bytes representing the content of the struct to the writer
68    /// output.
69    fn write_to(&self, writer: &mut BytesMut);
70
71    /// Convenience around [self.write_to] which already reserves the necessary
72    /// space.
73    fn write_to_end(&self, writer: &mut BytesMut) {
74        writer.reserve(self.byte_size());
75        self.write_to(writer);
76    }
77}
78
79/// `Deserialize` allows an item to be created from a binary representation.
80/// Given that there are many different ways such a conversion may fail, this
81/// operation will always yield a [Result]. It is not even sure that there
82/// are enough bytes available to be read for the deserialization of this
83/// item to completed successfully.
84pub trait Deserialize {
85    /// Tries to read the data contained in `reader` to create and instance of
86    /// `Self`.
87    ///
88    /// May return an error if the data did not match the expected format.
89    fn read_from<T: Read + ReadBytesExt>(reader: &mut T) -> Result<Self, SerializationError>
90    where
91        Self: Sized; // Technically, we don't care about being `Sized`, but unfortunately, Result
92                     // does.
93}
94
95/// An item having a [ByteSize] implementation specifies it has a known
96/// size, independent of if it's [Sized] or not. The size reported by
97/// [ByteSize] may sometimes not be the same as [std::mem::size_of], as
98/// alignment should not be taken into account for [ByteSize]. The size returned
99/// should not be taken as an exact value, though it should always match
100/// the final size. Assume this to be a good estimate instead.
101pub trait ByteSize {
102    /// Given the current element, provide the amounts of bytes necessary to
103    /// represent this element. This should never error and instead return
104    /// size of 0.
105    fn byte_size(&self) -> usize;
106}
107
108impl Serialize for u8 {
109    fn write_to(&self, writer: &mut BytesMut) {
110        writer.put_u8(*self);
111    }
112}
113
114impl ByteSize for u8 {
115    fn byte_size(&self) -> usize {
116        std::mem::size_of::<u8>()
117    }
118}
119
120impl Deserialize for u8 {
121    fn read_from<T: Read + ReadBytesExt>(reader: &mut T) -> Result<Self, SerializationError>
122    where
123        Self: Sized,
124    {
125        Ok(reader.read_u8()?)
126    }
127}
128
129impl Serialize for bool {
130    fn write_to(&self, writer: &mut BytesMut) {
131        let value = u8::from(*self);
132        value.write_to(writer);
133    }
134}
135
136impl ByteSize for bool {
137    fn byte_size(&self) -> usize {
138        1
139    }
140}
141
142impl Deserialize for bool {
143    fn read_from<T: Read + ReadBytesExt>(reader: &mut T) -> Result<Self, SerializationError>
144    where
145        Self: Sized,
146    {
147        Ok(reader.read_u8()? == 1)
148    }
149}
150
151implement_primitive!(u16, read_u16);
152implement_primitive!(i16, read_i16);
153implement_primitive!(u32, read_u32);
154implement_primitive!(i32, read_i32);
155implement_primitive!(u64, read_u64);
156implement_primitive!(i64, read_i64);
157implement_primitive!(f32, read_f32);
158implement_primitive!(f64, read_f64);
159
160#[cfg(test)]
161mod test {
162    use super::*;
163    use bytes::Buf;
164
165    #[test]
166    fn test_deserialize_primitive() {
167        let one = u8::read_from(&mut [1u8].reader()).expect("Should be able to read primitive");
168        assert_eq!(1, one);
169        let one =
170            u16::read_from(&mut [1u8, 0u8].reader()).expect("Should be able to read primitive");
171        assert_eq!(1, one);
172        let one = u32::read_from(&mut [1u8, 0u8, 0u8, 0u8].reader())
173            .expect("Should be able to read primitive");
174        assert_eq!(1, one);
175        let one = u64::read_from(&mut [1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8].reader())
176            .expect("Should be able to read primitive");
177        assert_eq!(1, one);
178    }
179
180    #[test]
181    fn test_deserialize_float_primitives() {
182        let result = f32::read_from(&mut [0x14, 0xAE, 0x29, 0x42].reader())
183            .expect("Should be able to read primitive");
184        assert!((42.42 - result).abs() < 0.00000001);
185        let result = f64::read_from(&mut [0xF6, 0x28, 0x5C, 0x8F, 0xC2, 0x35, 0x45, 0x40].reader())
186            .expect("Should be able to read primitive");
187        assert!((42.42 - result).abs() < 0.00000001);
188    }
189
190    #[test]
191    fn test_serialize_primitive() {
192        let mut buffer = BytesMut::new();
193        1u8.write_to_end(&mut buffer);
194        assert_eq!(&[1], buffer.freeze().as_ref());
195        let mut buffer = BytesMut::new();
196        1u16.write_to_end(&mut buffer);
197        assert_eq!(&[1, 0], buffer.freeze().as_ref());
198        let mut buffer = BytesMut::new();
199        1u32.write_to_end(&mut buffer);
200        assert_eq!(&[1, 0, 0, 0], buffer.freeze().as_ref());
201        let mut buffer = BytesMut::new();
202        1u64.write_to_end(&mut buffer);
203        assert_eq!(&[1, 0, 0, 0, 0, 0, 0, 0], buffer.freeze().as_ref());
204    }
205
206    #[test]
207    fn test_serialize_float_primitives() {
208        let mut buffer = BytesMut::new();
209        42.42f32.write_to_end(&mut buffer);
210        assert_eq!(&[0x14, 0xAE, 0x29, 0x42], buffer.freeze().as_ref());
211        let mut buffer = BytesMut::new();
212        42.42f64.write_to_end(&mut buffer);
213        assert_eq!(
214            &[0xF6, 0x28, 0x5C, 0x8F, 0xC2, 0x35, 0x45, 0x40],
215            buffer.freeze().as_ref()
216        );
217    }
218
219    #[test]
220    fn test_size_primitives() {
221        assert_eq!(1, 1u8.byte_size());
222        assert_eq!(2, 1u16.byte_size());
223        assert_eq!(4, 1u32.byte_size());
224        assert_eq!(8, 1u64.byte_size());
225        assert_eq!(4, 1.1f32.byte_size());
226        assert_eq!(8, 1.1f64.byte_size());
227    }
228}