1use crate::error::Error;
10use crate::PrettyPrintRecordKey;
11use bytes::{BufMut, Bytes, BytesMut};
12use libp2p::kad::Record;
13use prometheus_client::encoding::EncodeLabelValue;
14use rmp_serde::Serializer;
15use serde::{Deserialize, Serialize};
16use std::fmt::Display;
17use xor_name::XorName;
18
19#[derive(
21 EncodeLabelValue, Debug, Serialize, Deserialize, Clone, Copy, Eq, PartialEq, PartialOrd, Hash,
22)]
23pub enum DataTypes {
24 Chunk,
25 GraphEntry,
26 Pointer,
27 Scratchpad,
28}
29
30impl DataTypes {
31 pub fn get_index(&self) -> u32 {
32 match self {
33 Self::Chunk => 0,
34 Self::GraphEntry => 1,
35 Self::Pointer => 2,
36 Self::Scratchpad => 3,
37 }
38 }
39
40 pub fn from_index(index: u32) -> Option<Self> {
41 match index {
42 0 => Some(Self::Chunk),
43 1 => Some(Self::GraphEntry),
44 2 => Some(Self::Pointer),
45 3 => Some(Self::Scratchpad),
46 _ => None,
47 }
48 }
49}
50
51#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, PartialOrd, Hash)]
55pub enum ValidationType {
56 Chunk,
57 NonChunk(XorName),
58}
59
60#[derive(Debug, Serialize, Deserialize)]
61pub struct RecordHeader {
62 pub kind: RecordKind,
63}
64
65#[derive(Debug, Eq, PartialEq, Clone, Copy)]
67pub enum RecordKind {
68 DataOnly(DataTypes),
69 DataWithPayment(DataTypes),
70}
71
72pub const RECORD_KIND_PAYMENT_STARTING_INDEX: u32 = 10;
74
75impl Serialize for RecordKind {
76 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
77 where
78 S: serde::Serializer,
79 {
80 let index = match self {
81 Self::DataOnly(ref data_types) => data_types.get_index(),
82 Self::DataWithPayment(ref data_types) => {
83 RECORD_KIND_PAYMENT_STARTING_INDEX + data_types.get_index()
84 }
85 };
86 serializer.serialize_u32(index)
87 }
88}
89
90impl<'de> Deserialize<'de> for RecordKind {
91 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
92 where
93 D: serde::Deserializer<'de>,
94 {
95 let num = u32::deserialize(deserializer)?;
96 let data_type_index = if num < RECORD_KIND_PAYMENT_STARTING_INDEX {
97 num
98 } else {
99 num - RECORD_KIND_PAYMENT_STARTING_INDEX
100 };
101
102 if let Some(data_type) = DataTypes::from_index(data_type_index) {
103 if num < RECORD_KIND_PAYMENT_STARTING_INDEX {
104 Ok(Self::DataOnly(data_type))
105 } else {
106 Ok(Self::DataWithPayment(data_type))
107 }
108 } else {
109 Err(serde::de::Error::custom(format!(
110 "Unexpected index {num} for RecordKind variant",
111 )))
112 }
113 }
114}
115impl Display for RecordKind {
116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117 write!(f, "RecordKind({self:?})")
118 }
119}
120
121impl RecordHeader {
122 pub const SIZE: usize = 2;
123
124 pub fn try_serialize(self) -> Result<BytesMut, Error> {
125 let bytes = BytesMut::new();
126 let mut buf = bytes.writer();
127
128 self.serialize(&mut Serializer::new(&mut buf))
129 .map_err(|err| {
130 error!("Failed to serialized RecordHeader {self:?} with error: {err:?}");
131 Error::RecordHeaderParsingFailed
132 })?;
133
134 let b = buf.into_inner();
135
136 Ok(b)
137 }
138
139 pub fn try_deserialize(bytes: &[u8]) -> Result<Self, Error> {
140 rmp_serde::from_slice(bytes).map_err(|err| {
141 error!("Failed to deserialize RecordHeader with error: {err:?}");
142 Error::RecordHeaderParsingFailed
143 })
144 }
145
146 pub fn from_record(record: &Record) -> Result<Self, Error> {
147 if record.value.len() < RecordHeader::SIZE + 1 {
148 return Err(Error::RecordHeaderParsingFailed);
149 }
150 Self::try_deserialize(&record.value[..RecordHeader::SIZE + 1])
151 }
152
153 pub fn is_record_of_type_chunk(record: &Record) -> Result<bool, Error> {
154 let kind = Self::from_record(record)?.kind;
155 Ok(kind == RecordKind::DataOnly(DataTypes::Chunk))
156 }
157
158 pub fn get_data_type(record: &Record) -> Result<DataTypes, Error> {
159 let kind = Self::from_record(record)?.kind;
160 match kind {
161 RecordKind::DataOnly(data_type) | RecordKind::DataWithPayment(data_type) => {
162 Ok(data_type)
163 }
164 }
165 }
166}
167
168pub fn try_deserialize_record<T: serde::de::DeserializeOwned>(record: &Record) -> Result<T, Error> {
171 let bytes = if record.value.len() > RecordHeader::SIZE {
172 &record.value[RecordHeader::SIZE..]
173 } else {
174 return Err(Error::RecordParsingFailed);
175 };
176 rmp_serde::from_slice(bytes).map_err(|err| {
177 error!(
178 "Failed to deserialized record {} with error: {err:?}",
179 PrettyPrintRecordKey::from(&record.key)
180 );
181 Error::RecordParsingFailed
182 })
183}
184
185pub fn try_serialize_record<T: serde::Serialize>(
188 data: &T,
189 record_kind: RecordKind,
190) -> Result<Bytes, Error> {
191 let mut buf = RecordHeader { kind: record_kind }.try_serialize()?.writer();
192 data.serialize(&mut Serializer::new(&mut buf))
193 .map_err(|err| {
194 error!("Failed to serialized Records with error: {err:?}");
195 Error::RecordParsingFailed
196 })?;
197 let bytes = buf.into_inner();
198 Ok(bytes.freeze())
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204 use crate::error::Result;
205
206 #[test]
207 fn verify_record_header_encoded_size() -> Result<()> {
208 let chunk_with_payment = RecordHeader {
209 kind: RecordKind::DataWithPayment(DataTypes::Chunk),
210 }
211 .try_serialize()?;
212 assert_eq!(chunk_with_payment.len(), RecordHeader::SIZE);
213
214 let chunk = RecordHeader {
215 kind: RecordKind::DataOnly(DataTypes::Chunk),
216 }
217 .try_serialize()?;
218 assert_eq!(chunk.len(), RecordHeader::SIZE);
219
220 let graphentry = RecordHeader {
221 kind: RecordKind::DataOnly(DataTypes::GraphEntry),
222 }
223 .try_serialize()?;
224 assert_eq!(graphentry.len(), RecordHeader::SIZE);
225
226 let scratchpad = RecordHeader {
227 kind: RecordKind::DataOnly(DataTypes::Scratchpad),
228 }
229 .try_serialize()?;
230 assert_eq!(scratchpad.len(), RecordHeader::SIZE);
231
232 let scratchpad_with_payment = RecordHeader {
233 kind: RecordKind::DataWithPayment(DataTypes::Scratchpad),
234 }
235 .try_serialize()?;
236 assert_eq!(scratchpad_with_payment.len(), RecordHeader::SIZE);
237
238 let pointer = RecordHeader {
239 kind: RecordKind::DataOnly(DataTypes::Pointer),
240 }
241 .try_serialize()?;
242 assert_eq!(pointer.len(), RecordHeader::SIZE);
243
244 let pointer_with_payment = RecordHeader {
245 kind: RecordKind::DataWithPayment(DataTypes::Pointer),
246 }
247 .try_serialize()?;
248 assert_eq!(pointer_with_payment.len(), RecordHeader::SIZE);
249
250 Ok(())
251 }
252
253 #[test]
254 fn test_record_kind_serialization() -> Result<()> {
255 let kinds = vec![
256 RecordKind::DataOnly(DataTypes::Chunk),
257 RecordKind::DataWithPayment(DataTypes::Chunk),
258 RecordKind::DataOnly(DataTypes::GraphEntry),
259 RecordKind::DataWithPayment(DataTypes::GraphEntry),
260 RecordKind::DataOnly(DataTypes::Scratchpad),
261 RecordKind::DataWithPayment(DataTypes::Scratchpad),
262 RecordKind::DataOnly(DataTypes::Pointer),
263 RecordKind::DataWithPayment(DataTypes::Pointer),
264 ];
265
266 for kind in kinds {
267 let header = RecordHeader { kind };
268 let header2 = RecordHeader { kind };
269
270 let serialized = header.try_serialize()?;
271 let deserialized = RecordHeader::try_deserialize(&serialized)?;
272 assert_eq!(header2.kind, deserialized.kind);
273 }
274
275 Ok(())
276 }
277}