caraspace/
frame.rs

1//! A sclerite is the individual (frame) unit which can hold
2//! multiple packets
3//!
4use std::collections::HashMap;
5use std::fmt;
6
7#[cfg(feature="pybindings")]
8use pyo3::pyclass;
9
10use crate::parsers::*;
11use crate::serialization::*;
12use crate::errors::*;
13
14#[cfg(feature="random")]
15use crate::FromRandom;
16
17#[cfg(feature="random")]
18use rand::Rng;
19
20
21
22//// Hash function to generate a u16 value based on the name of the variant
23//const fn simple_hash(s: &str) -> u16 {
24//    let mut hash: u16 = 0;
25//    let mut i = 0;
26//    while i < s.len() {
27//        hash = hash.wrapping_add(s.as_bytes()[i] as u16);
28//        i += 1;
29//    }
30//    hash
31//}
32
33// FIXME - this is something for the furutre. Work on a macro system
34// The macro system should allow to register any type with the caraspace
35// library. Not sure if that is possible.
36////// Declare a macro that checks for duplicates in an enum definition
37//macro_rules! caraspace_register_types {
38//  ( $($variant:ident),* $(,)? ) => {
39//      #[cfg_attr(feature = "pybindings", pyclass)]
40//      #[derive(Debug, Copy, Clone, PartialEq)]
41//      #[repr(u16)]
42//      enum CRFrameObject2 {
43//        $(
44//            $variant = simple_hash(stringify!($variant)),
45//        )*
46//      }
47//  };
48//
49//  // This helper macro will trigger a compile-time error if the same variant is found twice
50//  (@check_duplicate CRFrameObjectType2:ident { $($existing_variant:ident),* }, $duplicate:ident) => {
51//    $(
52//      compile_error!(concat!("The following type has already been registered with the caraspace system: ", stringify!($duplicate)));
53//    )*
54//  };
55//
56//  // Detects duplicates by calling the helper macro to check against previous variants
57//  (CRFrameObjectType2:ident { $($existing_variant:ident),*, $duplicate:ident, $($rest:ident),* $(,)? }) => {
58//      define_enum!(@check_duplicate CRFrameObjectType2 { $($existing_variant),* }, $duplicate);
59//      define_enum!($enum_name { $($existing_variant),*, $duplicate, $($rest),* });
60//  };
61//}
62//
63//macro_rules! caraspace_register {
64//  ( $(($t:ty, $variant:ident)),* $((,),)? ) => {
65//  //($t:ty,  $variant:ident) => {
66//    #[cfg_attr(feature = "pybindings", pyclass)]
67//    #[derive(Debug, Copy, Clone, PartialEq)]
68//    #[repr(u16)]
69//    enum CRFrameObjectType2 {
70//      $(
71//          $variant = simple_hash(stringify!($variant)),
72//      )*
73//    }
74//    pub trait Frameable2 {
75//      const CRFRAMEOBJECT_TYPE : CRFrameObjectType2;
76//    }
77//    $(
78//    impl Frameable2 for $t {
79//      const CRFRAMEOBJECT_TYPE : CRFrameObjectType2 = CRFrameObjectType2::$variant;
80//    }
81//    )*
82//  };
83//}
84//
85//struct foo {}
86//struct bar {}
87//
88////caraspace_register_types!(FOO, BAR);
89//caraspace_register!((foo, Unknown), (bar, BAR));
90
91
92/// The Caraspace object type determines the 
93/// kind of object we are able to put in 
94/// a frame and ultimate (de)serialzie
95#[cfg_attr(feature = "pybindings", pyclass(eq, eq_int))]
96#[derive(Debug, Copy, Clone, PartialEq)]
97#[repr(u8)]
98pub enum CRFrameObjectType {
99  Unknown          =  0u8,
100  TofPacket        = 10u8,
101  TelemetryPacket  = 20u8,
102}
103
104impl CRFrameObjectType {
105  pub fn to_string(&self) -> String {
106    match self {
107      CRFrameObjectType::Unknown         => {return String::from("Unknown");},
108      CRFrameObjectType::TofPacket       => {return String::from("TofPacket");},
109      CRFrameObjectType::TelemetryPacket => {return String::from("TelemetryPacket");}
110    }
111  }
112
113  pub fn to_u8(&self) -> u8 {
114    match self {
115      CRFrameObjectType::Unknown         => {return  0;},
116      CRFrameObjectType::TofPacket       => {return 10;},
117      CRFrameObjectType::TelemetryPacket => {return 20;},
118    }
119  }
120}
121
122impl From<u8> for CRFrameObjectType {
123  fn from(value: u8) -> Self {
124    match value {
125      0   => CRFrameObjectType::Unknown,
126      10  => CRFrameObjectType::TofPacket,
127      20  => CRFrameObjectType::TelemetryPacket,
128       _  => CRFrameObjectType::Unknown
129    }
130  }
131}
132
133impl fmt::Display for CRFrameObjectType {
134  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135    let repr = self.to_string();
136    write!(f, "<CRFrameObjectType : {}>", repr)
137  }
138}
139
140#[cfg(feature = "random")]
141impl FromRandom for CRFrameObjectType {
142
143  fn from_random() -> Self {
144    let choices = [
145      CRFrameObjectType::Unknown,
146      CRFrameObjectType::TofPacket,
147      CRFrameObjectType::TelemetryPacket,
148    ];
149    let mut rng  = rand::thread_rng();
150    let idx = rng.gen_range(0..choices.len());
151    choices[idx]
152  }
153}
154
155
156/// A Caraspace object, that can be stored
157/// within a frame.
158///
159/// _For the connaiseur: This is basically a 
160/// TofPacket on steroids_
161///
162///
163#[derive(Debug, Clone)]
164pub struct CRFrameObject {
165  pub version : u8,
166  pub ftype   : CRFrameObjectType,
167  /// serialized representation of the 
168  /// content object
169  pub payload : Vec<u8>,
170}
171
172impl CRFrameObject {
173  pub fn new() -> Self {
174    Self {
175      version : 0,
176      ftype   : CRFrameObjectType::Unknown,
177      payload : Vec::<u8>::new(),
178    }
179  }
180
181  ///// The type of this object, which implicitly 
182  ///// defines (de)serialization rules
183  //pub fn get_ftype(&self) -> CRFrameObjectType {
184  //  self.ftype
185  //}
186
187  /// Size of the serialized object, including
188  /// header and footer in bytes
189  pub fn size(&self) -> usize {
190    let size = self.payload.len() + 2 + 4; 
191    size
192  }
193
194  /// Unpack the TofPacket and return its content
195  pub fn extract<T>(&self) -> Result<T, CRSerializationError>
196    where T: Frameable + CRSerializeable {
197    if T::CRFRAMEOBJECT_TYPE != self.ftype {
198      error!("This bytestream is not for a {} packet!", self.ftype);
199      return Err(CRSerializationError::IncorrectPacketType);
200    }
201    let unpacked : T = T::deserialize(&self.payload, &mut 0)?;
202    Ok(unpacked)
203  }
204}
205
206impl CRSerializeable for CRFrameObject {
207  
208  /// Decode a serializable from a bytestream  
209  fn deserialize(stream : &Vec<u8>, 
210                 pos    : &mut usize)
211    -> Result<Self, CRSerializationError>
212    where Self : Sized {
213    if stream.len() < 2 {
214      return Err(CRSerializationError::HeadInvalid {});
215    }
216    let head = parse_u16(stream, pos);
217    if Self::CRHEAD != head {
218      error!("Packet does not start with CRHEAD signature");
219      return Err(CRSerializationError::HeadInvalid {});
220    }
221      let mut f_obj    = CRFrameObject::new();
222      f_obj.version    = parse_u8(stream, pos);
223      let ftype        = parse_u8(stream, pos);
224      f_obj.ftype      = CRFrameObjectType::from(ftype);
225      let payload_size = parse_u32(stream, pos);
226      *pos += payload_size as usize; 
227      let tail = parse_u16(stream, pos);
228      if Self::CRTAIL != tail {
229        error!("Packet does not end with CRTAIL signature");
230        return Err(CRSerializationError::TailInvalid {});
231      }
232      *pos -= 2; // for tail parsing
233      *pos -= payload_size as usize;
234      f_obj.payload.extend_from_slice(&stream[*pos..*pos+payload_size as usize]);
235      Ok(f_obj)
236  }
237  
238  /// Encode a serializable to a bytestream  
239  fn serialize(&self) -> Vec<u8> {
240    let mut stream = Vec::<u8>::new();
241    stream.extend_from_slice(&Self::CRHEAD.to_le_bytes());
242    stream.push(self.version);
243    stream.push(self.ftype.to_u8());
244    let size = self.payload.len() as u32;
245    stream.extend_from_slice(&size.to_le_bytes());
246    stream.extend_from_slice(&self.payload.as_slice());
247    stream.extend_from_slice(&Self::CRTAIL.to_le_bytes());
248    stream
249  }
250}
251
252impl fmt::Display for CRFrameObject {
253  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
254    let p_len = self.payload.len();
255    write!(f, "<CRFrameObject: type {:?}, payload [ {} {} {} {} .. {} {} {} {}] of size {} >",
256           self.ftype,
257           self.payload[0], self.payload[1], self.payload[2], self.payload[3],
258           self.payload[p_len-4], self.payload[p_len-3], self.payload[p_len - 2], self.payload[p_len-1], p_len ) 
259  }
260}
261
262
263
264/// Allows to pack a certain structure within 
265/// a CRFrameObject
266pub trait Frameable {
267  const CRFRAMEOBJECT_TYPE : CRFrameObjectType;
268
269  /// Wrap myself in a TofPacket
270  fn pack(&self) -> CRFrameObject 
271    where Self: CRSerializeable {
272    let mut cr     = CRFrameObject::new();
273    cr.payload     = self.serialize();
274    cr.ftype       = Self::CRFRAMEOBJECT_TYPE;
275    //cr.size        = cr.payload.len();
276    cr
277  }
278}
279
280/// The central data container of the 
281/// caraspace suite. 
282///
283/// A CRFrame can hold multiple CRFrameObjects
284/// and is basically a little sclerite of 
285/// the entire skeleton.
286#[derive(Debug, Clone)]
287pub struct CRFrame {
288  // the index holds name, position in frame as well as the type of 
289  // object stored in the frame
290  // FIXME - this needs to be HashMap<&str, (u64, CRFrameObjectType)>
291  pub index       : HashMap<String, (u64, CRFrameObjectType)>,
292  pub bytestorage : Vec<u8>,
293}
294
295impl CRFrame {
296  
297  pub fn new() -> Self {
298    Self {
299      index       : HashMap::<String, (u64, CRFrameObjectType)>::new(),
300      bytestorage : Vec::<u8>::new(),
301    }
302  }
303
304  pub fn serialize_index(&self) -> Vec<u8> {
305    let mut s_index  = Vec::<u8>::new();
306    // more than 255 frame items are not supported
307    let idx_size = self.index.len() as u8;
308    s_index.push(idx_size);
309    for k in &self.index {
310      let mut s_name  = Self::string_to_bytes(k.0.clone());
311      let s_pos   = k.1.0.to_le_bytes();
312      s_index.append(&mut s_name);
313      s_index.extend_from_slice(&s_pos);
314      s_index.push(k.1.1.to_u8());
315    }
316    s_index
317  }
318
319  /// Get the timestamp from the actual telemetry packet in the frame
320  fn get_timestamp(&self) -> u64 {
321    return 0
322  }
323
324  fn string_to_bytes(value : String) -> Vec<u8> {
325    let mut stream  = Vec::<u8>::new();
326    let mut payload = value.into_bytes();
327    let string_size = payload.len() as u16; // limit size
328    stream.extend_from_slice(&string_size.to_le_bytes());
329    stream.append(&mut payload);
330    stream
331  }
332
333
334  pub fn parse_index(stream : &Vec<u8>, pos : &mut usize) -> HashMap<String, (u64, CRFrameObjectType)> {
335    let idx_size = parse_u8(stream, pos);
336    //println!("Found index of size {idx_size}");
337    let mut index    = HashMap::<String, (u64, CRFrameObjectType)>::new();
338    for _ in 0..idx_size as usize {
339      let name    = parse_string(stream, pos);
340      let obj_pos = parse_u64(stream, pos);
341      let obj_t   = CRFrameObjectType::from(stream[*pos]);
342      *pos += 1;
343      //println!("-- {} {} {}", name, obj_pos, obj_t);
344      index.insert(name, (obj_pos, obj_t));
345    }
346    index
347  }
348
349  /// Delete a CRFrameObject by this name from the frame
350  ///
351  /// To delete multiple objects, delete calls can be 
352  /// chained
353  /// 
354  /// # Arguments:
355  ///   * name : The name of the FrameObject to delte 
356  ///            (must be in index)
357  ///
358  /// # Returns:
359  ///   A complete copy of self, without the given object.
360  pub fn delete(&self, name : &str) -> Result<CRFrame, CRSerializationError> {
361    if !self.has(name) {
362      error!("There is no object with name {} in this frame!", name);
363      return Err(CRSerializationError::ObjectNotFound);
364    }
365    let mut new_frame = CRFrame::new();
366    for objname in self.index.keys() {
367      if objname == name {
368        continue;
369      }
370      let obj = self.get_fobject(&objname)?;
371      new_frame.put_fobject(obj, objname.clone());
372    }
373    Ok(new_frame)
374  }
375
376
377  /// Store any eligible object in the frame
378  ///
379  /// Eligible object must implement the "Frameable" trait
380  pub fn put<T: CRSerializeable + Frameable>(&mut self, object : T, name : String) {
381    let f_object = object.pack();
382    self.put_fobject(f_object, name);
383  }
384
385  fn put_fobject(&mut self, object : CRFrameObject, name : String) {
386    let pos    = self.bytestorage.len() as u64;
387    self.index.insert(name, (pos, object.ftype));
388    let mut stream = object.serialize();
389    //self.put_stream(&mut stream, name);
390    //let pos    = self.bytestorage.len();
391    //self.index.insert(name, pos);
392    self.bytestorage.append(&mut stream);
393  }
394
395  /// Check if the frame contains an object with the given name
396  ///
397  /// # Arguments:
398  ///   * name : The name of the object as it appears in the index
399  pub fn has(&self, name : &str) -> bool {
400    self.index.contains_key(name)
401  }
402  //pub fn put_stream(&mut self, stream : &mut Vec<u8>, name : String) {
403  //  let pos    = self.bytestorage.len();
404  //  self.index.insert(name, pos);
405  //  self.bytestorage.append(stream);
406  //}
407
408  pub fn get_fobject(&self, name : &str) -> Result<CRFrameObject, CRSerializationError> {
409    let mut pos    : usize;
410    match self.index.get(name) {
411      None => {
412        error!("There is no object with name {} in this frame!", name);
413        return Err(CRSerializationError::ObjectNotFound);
414      }
415      Some(meta)  => {
416        //lookup = meta;
417        pos   = meta.0 as usize;
418      }
419    }
420    let cr_object = CRFrameObject::deserialize(&self.bytestorage, &mut pos)?;
421    Ok(cr_object)
422  }
423
424  pub fn get<T : CRSerializeable + Frameable>(&self, name : String) -> Result<T, CRSerializationError> {
425    
426    //let mut lookup : (usize, CRFrameObjectType);
427    let mut pos    : usize;
428    match self.index.get(&name) {
429      None => {
430        return Err(CRSerializationError::ValueNotFound);
431      }
432      Some(meta)  => {
433        //lookup = meta;
434        pos   = meta.0 as usize;
435      }
436    }
437    let cr_object = CRFrameObject::deserialize(&self.bytestorage, &mut pos)?;
438    let result    = cr_object.extract::<T>()?;
439    Ok(result)
440  }
441
442  /// A verbose display of the frame content
443  pub fn show_frame(&self) -> String {
444    let mut repr = String::from("");
445    for k in &self.index {
446      repr += &(format!("\n -- {}@{}:{} --", k.0, k.1.0, k.1.1));
447      //match k.1.1 {
448      //  CRFrameObjectType::TelemetryPacket => {
449      //    repr += &(format!("\n -- -- {}", self.get<TelemetryPacket>
450      //  }
451      //  CRFrameObjectType::TofPacket => {
452      //  }
453      //}
454    }
455    repr 
456  }
457}
458
459impl CRSerializeable for CRFrame {
460  /// Decode a serializable from a bytestream  
461  fn deserialize(stream : &Vec<u8>, 
462                 pos    : &mut usize)
463    -> Result<Self, CRSerializationError> {
464    if stream.len() < 2 {
465      return Err(CRSerializationError::HeadInvalid {});
466    }
467    let head = parse_u16(stream, pos);
468    if Self::CRHEAD != head {
469      error!("FrameObject does not start with HEAD signature");
470      return Err(CRSerializationError::HeadInvalid {});
471    }
472    let fr_size   = parse_u64(stream, pos) as usize; 
473    *pos += fr_size as usize;
474    let tail = parse_u16(stream, pos);
475    if Self::CRTAIL != tail {
476      error!("FrameObject does not end with TAIL signature");
477      return Err(CRSerializationError::TailInvalid {});
478    }
479    *pos -= fr_size - 2; // wind back
480    let mut frame = CRFrame::new();
481    let size    = parse_u64(stream, pos) as usize;
482    frame.index = Self::parse_index(stream, pos);
483    frame.bytestorage = stream[*pos..*pos + size].to_vec();
484    Ok(frame)
485  }
486  
487  /// Encode a serializable to a bytestream  
488  fn serialize(&self) -> Vec<u8> {
489    let mut stream  = Vec::<u8>::new();
490    stream.extend_from_slice(&Self::CRHEAD.to_le_bytes());
491    let mut s_index = self.serialize_index();
492    //let idx_size    = s_index.len() as u64;
493    let size = self.bytestorage.len() as u64 + s_index.len() as u64;
494    //println!("Will store frame with {size} bytes!");
495    stream.extend_from_slice(&size.to_le_bytes());
496    stream.append(&mut s_index);
497    stream.extend_from_slice(&self.bytestorage.as_slice());
498    stream.extend_from_slice(&Self::CRTAIL.to_le_bytes());
499    stream
500  }
501}
502
503impl fmt::Display for CRFrame {
504  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
505    let mut repr = String::from("<CRFrame : ");
506    repr += &self.show_frame();
507    repr += "\n>";
508    write!(f, "{}", repr)
509  }
510}
511