tof_dataclasses/
version.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#[cfg(feature="random")]
use crate::FromRandom;

#[cfg(feature="random")]
use rand::Rng;

use std::fmt;

#[cfg(feature = "pybindings")]
use pyo3::pyclass;

/// The Protocol version is designed in such 
/// a way that we can "hijack" an existing 
/// field, using the most significant digits.
///
/// It uses the 2 most significant bit of an u8,
/// so it should be possible to basically slap 
/// this on to anyting
#[derive(Debug, Copy, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
#[repr(u8)]
#[cfg_attr(feature = "pybindings", pyclass(eq, eq_int))]
pub enum ProtocolVersion {
  Unknown  = 0u8,
  V1       = 64u8,
  V2       = 128u8,
  V3       = 192u8,
}

impl fmt::Display for ProtocolVersion {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    let r = serde_json::to_string(self).unwrap_or(
      String::from("Error: Unknown/Incompatible verison"));
    write!(f, "<ProtocolVersion: {}>", r)
  }
}

impl ProtocolVersion {
  pub fn to_u8(&self) -> u8 {
    match self {
      ProtocolVersion::Unknown => {
        return 0;
      }
      ProtocolVersion::V1 => {
        return 64;
      }
      ProtocolVersion::V2 => {
        return 128;
      }
      ProtocolVersion::V3 => {
        return 192;
      }
    }
  }
}

impl From<u8> for ProtocolVersion {
  fn from(value: u8) -> Self {
    match value {
        0 => ProtocolVersion::Unknown,
       64 => ProtocolVersion::V1,
      128 => ProtocolVersion::V2,
      192 => ProtocolVersion::V3,
      _   => ProtocolVersion::Unknown
    }
  }
}

#[cfg(feature = "random")]
impl FromRandom for ProtocolVersion {
  
  fn from_random() -> Self {
    let choices = [
      ProtocolVersion::Unknown,
      ProtocolVersion::V1,
      ProtocolVersion::V2,
      ProtocolVersion::V3,
    ];
    let mut rng  = rand::thread_rng();
    let idx = rng.gen_range(0..choices.len());
    choices[idx]
  }
}

#[test]
#[cfg(feature = "random")]
fn test_protocol_version() {
  for _ in 0..100 {
    let pv    = ProtocolVersion::from_random();
    let pv_u8 = pv.to_u8();
    let u8_pv = ProtocolVersion::from(pv_u8);
    assert_eq!(pv, u8_pv);
  }
}