1use crate::{InvalidVectorSizeError, ProtocolError};
2use bincode::{BorrowDecode, Decode, Encode};
3use serde::{Deserialize, Serialize};
4
5pub const EPOCH_KEY_OFFSET: u16 = 256;
7
8pub const MAX_EPOCH: u16 = u16::MAX - EPOCH_KEY_OFFSET;
10
11pub type EpochIndex = u16;
13
14pub const EPOCH_0: Epoch = Epoch {
15 index: 0,
16 key: [1, 0],
17};
18
19#[derive(Serialize, Clone, Eq, PartialEq, Copy, Debug)]
23#[serde(rename_all = "camelCase")]
24pub struct Epoch {
25 pub index: EpochIndex,
27
28 #[serde(skip)]
30 pub key: [u8; 2],
31}
32
33impl Default for Epoch {
34 fn default() -> Self {
35 Self::new(0).unwrap()
36 }
37}
38
39impl Epoch {
40 pub fn new(index: EpochIndex) -> Result<Self, ProtocolError> {
42 let index_with_offset = index
43 .checked_add(EPOCH_KEY_OFFSET)
44 .ok_or(ProtocolError::Overflow("stored epoch index too high"))?;
45 Ok(Self {
46 index,
47 key: index_with_offset.to_be_bytes(),
48 })
49 }
50}
51
52impl TryFrom<EpochIndex> for Epoch {
53 type Error = ProtocolError;
54
55 fn try_from(value: EpochIndex) -> Result<Self, Self::Error> {
56 Self::new(value)
57 }
58}
59
60impl TryFrom<&Vec<u8>> for Epoch {
61 type Error = ProtocolError;
62
63 fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
64 let key = value.clone().try_into().map_err(|_| {
65 ProtocolError::InvalidVectorSizeError(InvalidVectorSizeError::new(2, value.len()))
66 })?;
67 let index_with_offset = u16::from_be_bytes(key);
68 let index = index_with_offset
69 .checked_sub(EPOCH_KEY_OFFSET)
70 .ok_or(ProtocolError::Overflow("value too low, must have offset"))?;
71 Ok(Epoch { index, key })
72 }
73}
74
75impl Encode for Epoch {
76 fn encode<E: bincode::enc::Encoder>(
77 &self,
78 encoder: &mut E,
79 ) -> Result<(), bincode::error::EncodeError> {
80 self.index.encode(encoder)
81 }
82}
83
84impl<'de> Deserialize<'de> for Epoch {
85 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
86 where
87 D: serde::Deserializer<'de>,
88 {
89 #[derive(Deserialize)]
90 struct EpochData {
91 index: EpochIndex,
92 }
93
94 let data = EpochData::deserialize(deserializer)?;
95 Epoch::new(data.index).map_err(serde::de::Error::custom)
96 }
97}
98
99impl<C> Decode<C> for Epoch {
100 fn decode<D: bincode::de::Decoder<Context = C>>(
101 decoder: &mut D,
102 ) -> Result<Self, bincode::error::DecodeError> {
103 let index = EpochIndex::decode(decoder)?;
104 Epoch::new(index).map_err(|e| bincode::error::DecodeError::OtherString(e.to_string()))
105 }
106}
107
108impl<'de, C> BorrowDecode<'de, C> for Epoch {
109 fn borrow_decode<D: bincode::de::BorrowDecoder<'de, Context = C>>(
110 decoder: &mut D,
111 ) -> Result<Self, bincode::error::DecodeError> {
112 let index = EpochIndex::borrow_decode(decoder)?;
113 Epoch::new(index).map_err(|e| bincode::error::DecodeError::OtherString(e.to_string()))
114 }
115}