snops_common/format/
mod.rs1use std::{
2 fmt::Display,
3 io::{Read, Write},
4};
5
6mod impl_checkpoint;
7mod impl_chrono;
8mod impl_collections;
9mod impl_containers;
10mod impl_ints;
11mod impl_json;
12mod impl_net;
13mod impl_strings;
14mod impl_tuples;
15mod packed_int;
16
17pub use packed_int::*;
18use thiserror::Error;
19
20#[derive(Debug, Error)]
21pub enum DataWriteError {
22 #[error("io error: {0}")]
24 Io(#[from] std::io::Error),
25 #[error("{0}")]
27 Custom(String),
28}
29
30#[derive(Debug, Error)]
31pub enum DataReadError {
32 #[error("io error: {0}")]
34 Io(#[from] std::io::Error),
35 #[error("utf8 error: {0}")]
37 Utf8(#[from] std::string::FromUtf8Error),
38 #[error("upgrade unavailable: {0}")]
41 UpgradeUnavailable(String),
42 #[error("invalid version: {0}")]
43 UnsupportedVersion(String),
44 #[error("{0}")]
46 Custom(String),
47}
48
49impl DataReadError {
50 pub fn unsupported(name: impl Display, expected: impl Display, found: impl Display) -> Self {
51 Self::UnsupportedVersion(format!("{name}: expected {expected}, found {found}"))
52 }
53
54 pub fn custom(error: impl Display) -> Self {
55 Self::Custom(format!("{error}"))
56 }
57}
58
59impl DataWriteError {
60 pub fn custom(error: impl Display) -> Self {
61 Self::Custom(format!("{error}"))
62 }
63}
64
65pub fn write_dataformat<W: Write, F: DataFormat>(
67 writer: &mut W,
68 data: &F,
69) -> Result<usize, DataWriteError> {
70 Ok(data.write_header(writer)? + data.write_data(writer)?)
71}
72
73pub fn read_dataformat<R: Read, F: DataFormat>(reader: &mut R) -> Result<F, DataReadError> {
75 let header = F::read_header(reader)?;
76 F::read_data(reader, &header)
77}
78
79pub type DataHeaderOf<T> = <T as DataFormat>::Header;
80
81pub trait DataFormat: Sized {
85 type Header: DataFormat + Clone;
86 const LATEST_HEADER: Self::Header;
87
88 fn write_header<W: Write>(&self, writer: &mut W) -> Result<usize, DataWriteError> {
89 Ok(Self::LATEST_HEADER.write_header(writer)? + Self::LATEST_HEADER.write_data(writer)?)
90 }
91
92 fn read_header<R: Read>(reader: &mut R) -> Result<Self::Header, DataReadError> {
93 let header_header = Self::Header::read_header(reader)?;
95 reader.read_data(&header_header)
97 }
98
99 fn write_data<W: Write>(&self, writer: &mut W) -> Result<usize, DataWriteError>;
101
102 fn read_data<R: Read>(reader: &mut R, header: &Self::Header) -> Result<Self, DataReadError>;
104
105 fn to_byte_vec(&self) -> Result<Vec<u8>, DataWriteError> {
107 let mut buf = Vec::new();
108 self.write_data(&mut buf)?;
109 Ok(buf)
110 }
111}
112
113pub trait DataFormatWriter {
114 fn write_data<F: DataFormat>(&mut self, data: &F) -> Result<usize, DataWriteError>;
115}
116
117impl<W: Write> DataFormatWriter for W {
118 fn write_data<F: DataFormat>(&mut self, data: &F) -> Result<usize, DataWriteError> {
119 data.write_data(self)
120 }
121}
122
123pub trait DataFormatReader {
124 fn read_data<F: DataFormat>(&mut self, header: &F::Header) -> Result<F, DataReadError>;
125}
126
127impl<R: Read> DataFormatReader for R {
128 fn read_data<F: DataFormat>(&mut self, header: &F::Header) -> Result<F, DataReadError> {
129 F::read_data(self, header)
130 }
131}
132
133#[macro_export]
134macro_rules! dataformat_test {
135 ($name:ident, $( $others:expr),* ) => {
136 #[test]
137 fn $name() -> Result<(), Box<dyn std::error::Error>> {
138 use snops_common::format::{write_dataformat, read_dataformat};
139
140 $(
141
142 let value = $others;
143 let mut writer = Vec::new();
144 write_dataformat(&mut writer, &value)?;
145 let mut reader = writer.as_slice();
146 let decoded = read_dataformat::<_, _>(&mut reader)?;
147 assert_eq!(value, decoded);
148 )*
149 Ok(())
150 }
151 };
152}
153
154#[cfg(test)]
155mod test {
156 use super::{read_dataformat, write_dataformat, DataFormat, DataReadError, DataWriteError};
157
158 #[test]
159 fn test_read_write() -> Result<(), Box<dyn std::error::Error>> {
160 #[derive(Debug, PartialEq)]
161 struct Test {
162 a: u8,
163 }
164
165 impl DataFormat for Test {
166 type Header = u8;
167 const LATEST_HEADER: Self::Header = 1;
168
169 fn write_data<W: std::io::prelude::Write>(
170 &self,
171 writer: &mut W,
172 ) -> Result<usize, DataWriteError> {
173 self.a.write_data(writer)
174 }
175
176 fn read_data<R: std::io::prelude::Read>(
177 reader: &mut R,
178 header: &Self::Header,
179 ) -> Result<Self, DataReadError> {
180 if *header != Self::LATEST_HEADER {
181 return Err(DataReadError::unsupported(
182 "Test",
183 Self::LATEST_HEADER,
184 *header,
185 ));
186 }
187 Ok(Test {
188 a: u8::read_data(reader, &())?,
189 })
190 }
191 }
192
193 let value = Test { a: 42 };
194 let mut writer = Vec::new();
195
196 assert_eq!(write_dataformat(&mut writer, &value)?, 2);
198 assert_eq!(writer, [1u8, 42u8]);
199
200 let mut reader = writer.as_slice();
201 let decoded = read_dataformat::<_, Test>(&mut reader)?;
202 assert_eq!(value, decoded);
203
204 assert_eq!(
205 read_dataformat::<_, Test>(&mut [1u8, 43u8].as_slice())?,
206 Test { a: 43 }
207 );
208
209 assert!(
210 read_dataformat::<_, Test>(&mut [2u8, 43u8].as_slice()).is_err(),
212 );
213
214 assert!(
215 read_dataformat::<_, Test>(&mut [1u8].as_slice()).is_err(),
217 );
218
219 Ok(())
220 }
221}