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  /// Verify that the serialized representation of the struct has the 
26  /// correct size, including header + footer.
27  ///
28  /// Will panic for variable sized structs.
29  fn verify_fixed(stream : &Vec<u8>, 
30                  pos    : &mut usize) -> Result<(), SerializationError> {
31    if !Self::SIZE == 0 {
32      // we can panic here, since this is a conceptional logic error. If we
33      // don't panic, monsters will arise downstream.
34      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!");
35    }
36    let head_pos = seek_marker(stream, Self::HEAD, *pos)?; 
37    let tail_pos = seek_marker(stream, Self::TAIL, head_pos + Self::SIZE-2)?;
38    if tail_pos + 2 - head_pos != Self::SIZE {
39      error!("Seing {} bytes, but expecting {}", tail_pos + 2 - head_pos, Self::SIZE);
40      *pos = head_pos + 2; 
41      return Err(SerializationError::WrongByteSize);
42    }
43    *pos = head_pos + 2;
44    Ok(())
45  } 
46
47  /// Decode a serializable from a bytestream  
48  ///
49  /// # Arguments:
50  ///   * bytestream : bytes including the ones which should 
51  ///                  be decoded
52  ///   * pos        : first byte in the bytestream which is 
53  ///                  part of the expected payload
54  //fn from_bytestream<T: AsRef<[u8]>>(bytestream : T, 
55  fn from_bytestream(bytestream : &Vec<u8>,
56                     pos        : &mut usize)
57    -> Result<Self, SerializationError>
58    where Self : Sized;
59  
60  /// Decode a serializable from a bytestream. This provides 
61  /// an alternative method to get the packet. If not implemented,
62  /// it will be the same as from_bytestream.
63  ///
64  /// # Arguments:
65  ///   * bytestream : bytes including the ones which should 
66  ///                  be decoded
67  ///   * pos        : first byte in the bytestream which is 
68  ///                  part of the expected payload
69  fn from_bytestream_alt(bytestream : &Vec<u8>, 
70                         pos        : &mut usize)
71    -> Result<Self, SerializationError>
72    where Self : Sized {
73    Self::from_bytestream(bytestream, pos)
74  }
75
76  /// Encode a serializable to a bytestream  
77  /// 
78  /// This shall return a representation of the struct
79  /// in such a way that to_bytestream and from_bytestream
80  /// are inverse operations.
81  fn to_bytestream(&self) -> Vec<u8> {
82    error!("No default implementation for trait!");
83    return Vec::<u8>::new();
84  }
85}
86
87//---------------------------------------------------
88
89/// Search for a u16 bytemarker in a stream.
90///
91/// E.g. This can be an 0xAAAA indicator as a packet delimiter
92///
93/// # Arguments:
94///  
95///  * marker     : The marker to search for. Currently, only 
96///                 16bit markers are supported
97///  * bytestream : The stream to search the number in
98///  * start_pos  : Start searching from this position in 
99///                 the stream
100pub fn seek_marker<T: AsRef<[u8]>>(stream : &T, marker : u16, start_pos :usize) 
101  -> Result<usize, SerializationError> {
102  // -2 bc later on we are looking for 2 bytes!
103  let bytestream = stream.as_ref();
104  if bytestream.len() == 0 {
105    error!("Stream empty!");
106    return Err(SerializationError::StreamTooShort);
107  }
108  if start_pos  > bytestream.len() - 2 {
109    error!("Start position {} beyond stream capacity {}!", start_pos, bytestream.len() -2);
110    return Err(SerializationError::StreamTooShort);
111  }
112  let mut pos = start_pos;
113  let mut two_bytes : [u8;2]; 
114  // will find the next header
115  two_bytes = [bytestream[pos], bytestream[pos + 1]];
116  // FIXME - this should be little endian?
117  if u16::from_le_bytes(two_bytes) == marker {
118    return Ok(pos);
119  }
120  // if it is not at start pos, then traverse 
121  // the stream
122  pos += 1;
123  let mut found = false;
124  // we search for the next packet
125  for n in pos..bytestream.len() - 1 {
126    two_bytes = [bytestream[n], bytestream[n + 1]];
127    if (u16::from_le_bytes(two_bytes)) == marker {
128      pos = n;
129      found = true;
130      break;
131    }
132  }
133  if !found {
134    let delta = bytestream.len() - start_pos;
135    warn!("Can not find {} in bytestream [-{}:{}]!", marker, delta ,bytestream.len());
136    return Err(SerializationError::ValueNotFound);
137  }
138  trace!("Found {marker} at {pos}");
139  Ok(pos)
140}
141
142#[test]
143fn test_seek_marker() {
144  // just test it two times - FIXME - use a better method
145  let mut bytestream = vec![1,2,3,0xAA, 0xAA, 5, 7];
146  let mut pos = seek_marker(&bytestream, 0xaaaa, 0).unwrap();
147  assert_eq!(pos, 3);
148  
149  bytestream = vec![1,2,3,244, 16, 32, 0xaa, 0xff, 5, 7];
150  // remember byte order in vectors
151  pos = seek_marker(&bytestream, 0xffaa, 1).unwrap();
152  assert_eq!(pos, 6);
153  
154  bytestream = vec![0xaa,0xaa,3,244, 16, 32, 0xAA, 0xFF, 5, 7];
155  pos = seek_marker(&bytestream, 0xaaaa, 0).unwrap();
156  assert_eq!(pos, 0);
157}
158