gondola_core/io/
serialization.rs

1//! The following file is part of gaps-online-software and published 
2//! under the GPLv3 license
3
4use crate::prelude::*;
5
6pub use crate::io::caraspace::{
7  Frameable
8};
9
10/// Encode/decode structs to `Vec::<u8>` to write to a file or
11/// send over the network
12pub trait Serialization {
13
14  /// Byte marker to mark beginning of payload
15  const HEAD: u16 = 0xAAAA;
16  /// Byte marker to mark end of payload
17  const TAIL: u16 = 0x5555;
18  /// The SIZE is the size of the serialized 
19  /// bytestream INCLUDING 4 bytes for head
20  /// and tail bytes. In case the struct does 
21  /// NOT HAVE a fixed size, SIZE will be 0
22  /// (so default value of the trait
23  const SIZE: usize = 0;
24  
25  /// Guess the size of te packet. This can be a 
26  /// preformance issue if te offset position 
27  /// is far off
28  ///
29  /// This will not advance the pos marker!
30  fn guess_size(stream : &Vec<u8>,
31                pos    : usize,
32                offset : usize)
33      -> Result<(usize,usize,usize), SerializationError> {
34    let head_pos = seek_marker(stream, Self::HEAD, pos)?; 
35    let tail_pos = seek_marker(stream, Self::TAIL, pos+ offset)?;
36    Ok((tail_pos + 2 - head_pos, head_pos, tail_pos))
37  }
38
39  /// Verify that the serialized representation of the struct has the 
40  /// correct size, including header + footer.
41  ///
42  /// Will panic for variable sized structs.
43  fn verify_fixed(stream : &Vec<u8>, 
44                  pos    : &mut usize) -> Result<(), SerializationError> {
45    if !Self::SIZE == 0 {
46      // we can panic here, since this is a conceptional logic error. If we
47      // don't panic, monsters will arise downstream.
48      panic!("Self::verify_fixed can be only used for structs with a fixed size! In case you are convinced, that your struct has indeed a fixed size, please implement trait Serialization::SIZE with the serialized size in bytes including 4 bytes for header and footer!");
49    }
50    if stream.len() < Self::SIZE {
51      return Err(SerializationError::StreamTooShort);
52    }
53    let head_pos = seek_marker(stream, Self::HEAD, *pos)?; 
54    let tail_pos = seek_marker(stream, Self::TAIL, head_pos + Self::SIZE-2)?;
55    if tail_pos + 2 - head_pos != Self::SIZE {
56      *pos = head_pos + 2; 
57      return Err(SerializationError::WrongByteSize);
58    }
59    *pos = head_pos + 2;
60    Ok(())
61  } 
62
63  /// Decode a serializable from a bytestream  
64  ///
65  /// # Arguments:
66  ///   * bytestream : bytes including the ones which should 
67  ///                  be decoded
68  ///   * pos        : first byte in the bytestream which is 
69  ///                  part of the expected payload
70  //fn from_bytestream<T: AsRef<[u8]>>(bytestream : T, 
71  fn from_bytestream(bytestream : &Vec<u8>,
72                     pos        : &mut usize)
73    -> Result<Self, SerializationError>
74    where Self : Sized;
75  
76  /// Decode a serializable from a bytestream. This provides 
77  /// an alternative method to get the packet. If not implemented,
78  /// it will be the same as from_bytestream.
79  ///
80  /// # Arguments:
81  ///   * bytestream : bytes including the ones which should 
82  ///                  be decoded
83  ///   * pos        : first byte in the bytestream which is 
84  ///                  part of the expected payload
85  fn from_bytestream_alt(bytestream : &Vec<u8>, 
86                         pos        : &mut usize)
87    -> Result<Self, SerializationError>
88    where Self : Sized {
89    Self::from_bytestream(bytestream, pos)
90  }
91
92  /// Encode a serializable to a bytestream  
93  /// 
94  /// This shall return a representation of the struct
95  /// in such a way that to_bytestream and from_bytestream
96  /// are inverse operations.
97  fn to_bytestream(&self) -> Vec<u8> {
98    error!("No default implementation for trait!");
99    return Vec::<u8>::new();
100  }
101}
102
103//---------------------------------------------------
104
105/// Search for a u16 bytemarker in a stream.
106///
107/// E.g. This can be an 0xAAAA indicator as a packet delimiter
108///
109/// # Arguments:
110///  
111///  * marker     : The marker to search for. Currently, only 
112///                 16bit markers are supported
113///  * bytestream : The stream to search the number in
114///  * start_pos  : Start searching from this position in 
115///                 the stream
116pub fn seek_marker<T: AsRef<[u8]>>(stream : &T, marker : u16, start_pos :usize) 
117  -> Result<usize, SerializationError> {
118  // -2 bc later on we are looking for 2 bytes!
119  let bytestream = stream.as_ref();
120  if bytestream.len() == 0 {
121    error!("Stream empty!");
122    return Err(SerializationError::StreamTooShort);
123  }
124  if start_pos  > bytestream.len() - 2 {
125    error!("Start position {} beyond stream capacity {}!", start_pos, bytestream.len() -2);
126    return Err(SerializationError::StreamTooShort);
127  }
128  let mut pos = start_pos;
129  let mut two_bytes : [u8;2]; 
130  // will find the next header
131  two_bytes = [bytestream[pos], bytestream[pos + 1]];
132  // FIXME - this should be little endian?
133  if u16::from_le_bytes(two_bytes) == marker {
134    return Ok(pos);
135  }
136  // if it is not at start pos, then traverse 
137  // the stream
138  pos += 1;
139  let mut found = false;
140  // we search for the next packet
141  for n in pos..bytestream.len() - 1 {
142    two_bytes = [bytestream[n], bytestream[n + 1]];
143    if (u16::from_le_bytes(two_bytes)) == marker {
144      pos = n;
145      found = true;
146      break;
147    }
148  }
149  if !found {
150    let delta = bytestream.len() - start_pos;
151    warn!("Can not find {} in bytestream [-{}:{}]!", marker, delta ,bytestream.len());
152    return Err(SerializationError::ValueNotFound);
153  }
154  trace!("Found {marker} at {pos}");
155  Ok(pos)
156}
157
158#[test]
159fn test_seek_marker() {
160  // just test it two times - FIXME - use a better method
161  let mut bytestream = vec![1,2,3,0xAA, 0xAA, 5, 7];
162  let mut pos = seek_marker(&bytestream, 0xaaaa, 0).unwrap();
163  assert_eq!(pos, 3);
164  
165  bytestream = vec![1,2,3,244, 16, 32, 0xaa, 0xff, 5, 7];
166  // remember byte order in vectors
167  pos = seek_marker(&bytestream, 0xffaa, 1).unwrap();
168  assert_eq!(pos, 6);
169  
170  bytestream = vec![0xaa,0xaa,3,244, 16, 32, 0xAA, 0xFF, 5, 7];
171  pos = seek_marker(&bytestream, 0xaaaa, 0).unwrap();
172  assert_eq!(pos, 0);
173}
174