sigma_ser/
scorex_serialize.rs1use std::convert::TryInto;
2use std::io;
3
4use crate::vlq_encode;
5use crate::vlq_encode::*;
6use bounded_vec::{BoundedVec, BoundedVecOutOfBounds};
7use thiserror::Error;
8
9#[derive(Error, Eq, PartialEq, Debug, Clone)]
11pub enum ScorexSerializationError {
12 #[error("IO error: {0}")]
14 Io(String),
15 #[error("serialization not yet implemented: {0}")]
17 NotImplementedYet(&'static str),
18 #[error("serialization not supported: {0}")]
20 NotSupported(&'static str),
21 #[error("Bounds check error: {0}")]
23 TryFrom(#[from] std::num::TryFromIntError),
24 #[error("error: {0}")]
26 Misc(&'static str),
27}
28
29impl From<io::Error> for ScorexSerializationError {
30 fn from(error: io::Error) -> Self {
31 ScorexSerializationError::Io(error.to_string())
32 }
33}
34
35impl From<ScorexSerializationError> for io::Error {
36 fn from(e: ScorexSerializationError) -> Self {
37 io::Error::new(io::ErrorKind::InvalidInput, e.to_string())
38 }
39}
40
41#[derive(Error, Eq, PartialEq, Debug, Clone)]
43pub enum ScorexParsingError {
44 #[error("invalid op code: {0}")]
46 InvalidOpCode(u8),
47 #[error("not implemented op error")]
49 NotImplementedOpCode(String),
50 #[error("type parsing error, invalid type code: {0}({0:#04X})")]
52 InvalidTypeCode(u8),
53 #[error("vlq encode error: {0}")]
55 VlqEncode(#[from] vlq_encode::VlqEncodingError),
56 #[error("IO error: {0}")]
58 Io(String),
59 #[error("misc error")]
61 Misc(String),
62 #[error("parsing not yet implemented: {0}")]
64 NotImplementedYet(String),
65 #[error("Value out of bounds: {0}")]
67 ValueOutOfBounds(String),
68 #[error("Tuple items out of bounds: {0}")]
70 TupleItemsOutOfBounds(usize),
71 #[error("parsing not supported: {0}")]
73 NotSupported(&'static str),
74 #[error("serialization error: {0}")]
76 SerializationError(#[from] ScorexSerializationError),
77 #[error("Invalid item quantity for BoundedVec: {0}")]
79 BoundedVecOutOfBounds(#[from] BoundedVecOutOfBounds),
80 #[error("Bounds check error: {0}")]
82 TryFrom(#[from] std::num::TryFromIntError),
83}
84
85impl From<io::Error> for ScorexParsingError {
86 fn from(error: io::Error) -> Self {
87 ScorexParsingError::Io(error.to_string())
88 }
89}
90
91impl From<&io::Error> for ScorexParsingError {
92 fn from(error: &io::Error) -> Self {
93 ScorexParsingError::Io(error.to_string())
94 }
95}
96
97pub type ScorexSerializeResult = Result<(), ScorexSerializationError>;
99
100pub trait ScorexSerializable: Sized {
102 fn scorex_serialize<W: WriteSigmaVlqExt>(&self, w: &mut W) -> ScorexSerializeResult;
104 fn scorex_parse<R: ReadSigmaVlqExt>(r: &mut R) -> Result<Self, ScorexParsingError>;
106
107 fn scorex_serialize_bytes(&self) -> Result<Vec<u8>, ScorexSerializationError> {
109 let mut w = vec![];
110 self.scorex_serialize(&mut w)?;
111 Ok(w)
112 }
113 fn scorex_parse_bytes(mut bytes: &[u8]) -> Result<Self, ScorexParsingError> {
115 Self::scorex_parse(&mut bytes)
116 }
117}
118
119impl<T: ScorexSerializable> ScorexSerializable for Vec<T> {
120 fn scorex_serialize<W: WriteSigmaVlqExt>(&self, w: &mut W) -> ScorexSerializeResult {
121 w.put_u32(self.len() as u32)?;
122 self.iter().try_for_each(|i| i.scorex_serialize(w))
123 }
124
125 fn scorex_parse<R: ReadSigmaVlqExt>(r: &mut R) -> Result<Self, ScorexParsingError> {
126 let items_count = r.get_u32()?;
127 let mut items = Vec::with_capacity(items_count as usize);
128 for _ in 0..items_count {
129 items.push(T::scorex_parse(r)?);
130 }
131 Ok(items)
132 }
133}
134
135impl<T: ScorexSerializable, const L: usize, const U: usize> ScorexSerializable
136 for BoundedVec<T, L, U>
137{
138 fn scorex_serialize<W: WriteSigmaVlqExt>(&self, w: &mut W) -> ScorexSerializeResult {
139 self.as_vec().scorex_serialize(w)
140 }
141
142 fn scorex_parse<R: ReadSigmaVlqExt>(r: &mut R) -> Result<Self, ScorexParsingError> {
143 Ok(Vec::<T>::scorex_parse(r)?.try_into()?)
144 }
145}
146
147impl ScorexSerializable for u32 {
149 fn scorex_serialize<W: WriteSigmaVlqExt>(&self, w: &mut W) -> ScorexSerializeResult {
150 w.put_u32(*self)?;
151 Ok(())
152 }
153 fn scorex_parse<R: ReadSigmaVlqExt>(r: &mut R) -> Result<Self, ScorexParsingError> {
154 let v = r.get_u32()?;
155 Ok(v)
156 }
157}
158
159impl<T: ScorexSerializable> ScorexSerializable for Option<Box<T>> {
160 fn scorex_serialize<W: WriteSigmaVlqExt>(&self, w: &mut W) -> ScorexSerializeResult {
161 match self {
162 Some(v) => {
163 w.put_u8(1)?;
164 v.scorex_serialize(w)
165 }
166 None => Ok(w.put_u8(0)?),
167 }
168 }
169
170 fn scorex_parse<R: ReadSigmaVlqExt>(r: &mut R) -> Result<Self, ScorexParsingError> {
171 let tag = r.get_u8()?;
172 Ok(if tag != 0 {
173 Some(T::scorex_parse(r)?.into())
174 } else {
175 None
176 })
177 }
178}
179
180#[allow(clippy::expect_used)]
182pub fn scorex_serialize_roundtrip<T: ScorexSerializable>(v: &T) -> T {
183 let mut data = Vec::new();
184 v.scorex_serialize(&mut data).expect("serialization failed");
185 let reader = &mut &data[..];
186 T::scorex_parse(reader).expect("parse failed")
187}
188
189#[allow(clippy::unwrap_used)]
190#[cfg(test)]
191#[allow(clippy::panic)]
192mod test {
193 use super::*;
194 use proptest::collection::vec;
195 use proptest::prelude::*;
196
197 proptest! {
198 #[test]
199 fn u32_roundtrip(val in any::<u32>()) {
200 assert_eq!(scorex_serialize_roundtrip(&val), val);
201 }
202
203 #[test]
204 fn vec_roundtrip(val in vec(any::<u32>(), 0..255)) {
205 assert_eq!(scorex_serialize_roundtrip(&val), val);
206 }
207
208 #[test]
209 fn box_roundtrip(val in any::<Option<Box<u32>>>()) {
210 assert_eq!(scorex_serialize_roundtrip(&val), val);
211 }
212 }
213}