1use crate::{
4 body::Body,
5 error::{DecodeError, DecodeErrorKind, EncodeError},
6 message::{Encode, Message, View},
7 sink::Sink,
8};
9use bytes::{Bytes, BytesMut};
10
11const HEADER_LEN: usize = 2;
13
14pub type Converter<T> = fn(T) -> anyhow::Result<T>;
16
17pub trait Versioned: Sized + 'static {
31 type Latest: Body;
32
33 const LATEST: u16;
35
36 const UPGRADES: &'static [Converter<Self>] = &[];
38
39 const DOWNGRADES: &'static [Converter<Self>] = &[];
41
42 fn wrap_latest(latest: Self::Latest) -> Self;
43
44 fn unwrap_latest(self) -> anyhow::Result<Self::Latest>;
45
46 fn decode_version(version: u16, body: Bytes) -> Result<Self, DecodeError>;
48
49 fn encode_version<S: Sink>(&self, version: u16, out: &mut S) -> Result<(), EncodeError>;
51
52 fn decode_body(body: Bytes, version: u16) -> Result<Self::Latest, DecodeError> {
54 if version == Self::LATEST {
55 return Self::Latest::from_body(body);
56 }
57 check_decode_version::<Self>(version)?;
58 let mut value = Self::decode_version(version, body)?;
59 let skip = usize::from(version) - 1;
60 for upgrade in Self::UPGRADES.iter().skip(skip) {
61 value = upgrade(value).map_err(DecodeError::conversion)?;
62 }
63 value.unwrap_latest().map_err(DecodeError::conversion)
64 }
65
66 fn open_body(
69 body: Bytes,
70 version: u16,
71 ) -> Result<View<<Self::Latest as Message>::Wire>, DecodeError>
72 where
73 Self::Latest: Message,
74 {
75 if version == Self::LATEST {
76 return Self::Latest::view(body);
77 }
78 let latest = Self::decode_body(body, version)?;
79 View::new(latest.encode_to_bytes())
80 }
81
82 fn encode_body<S: Sink>(
84 value: &Self::Latest,
85 version: u16,
86 out: &mut S,
87 ) -> Result<(), EncodeError> {
88 if version == Self::LATEST {
89 value.put_body(out);
90 return Ok(());
91 }
92 downgrade::<Self>(value, version)?.encode_version(version, out)
93 }
94
95 fn decode(bytes: Bytes) -> Result<Self::Latest, DecodeError> {
97 let (version, body) = split_header(bytes)?;
98 Self::decode_body(body, version)
99 }
100
101 fn open(bytes: Bytes) -> Result<View<<Self::Latest as Message>::Wire>, DecodeError>
103 where
104 Self::Latest: Message,
105 {
106 let (version, body) = split_header(bytes)?;
107 Self::open_body(body, version)
108 }
109
110 fn seal<S: Sink>(value: &Self::Latest, version: u16, out: &mut S) -> Result<(), EncodeError> {
112 if version == Self::LATEST {
113 out.put_u16_le(version);
114 value.put_body(out);
115 return Ok(());
116 }
117 let converted = downgrade::<Self>(value, version)?;
118 out.put_u16_le(version);
119 converted.encode_version(version, out)
120 }
121
122 fn sealed_len(value: &Self::Latest) -> usize {
126 HEADER_LEN + value.body_len()
127 }
128
129 fn seal_to_vec(value: &Self::Latest, version: u16) -> Result<Vec<u8>, EncodeError> {
131 let mut out = Vec::with_capacity(Self::sealed_len(value));
132 Self::seal(value, version, &mut out)?;
133 Ok(out)
134 }
135
136 fn seal_to_bytes(value: &Self::Latest, version: u16) -> Result<Bytes, EncodeError> {
139 let mut out = BytesMut::with_capacity(Self::sealed_len(value));
140 Self::seal(value, version, &mut out)?;
141 Ok(out.freeze())
142 }
143
144 fn seal_to_slice(
152 value: &Self::Latest,
153 version: u16,
154 out: &mut [u8],
155 ) -> Result<usize, EncodeError> {
156 if version != Self::LATEST {
157 let sealed = Self::seal_to_vec(value, version)?;
158 check_capacity(sealed.len(), out.len())?;
159 out[..sealed.len()].copy_from_slice(&sealed);
160 return Ok(sealed.len());
161 }
162
163 let needed = Self::sealed_len(value);
164 check_capacity(needed, out.len())?;
165 let mut cursor = &mut out[..needed];
166 Self::seal(value, version, &mut cursor)?;
167 Ok(needed)
168 }
169
170 fn deserialize_with_embedded_version(payload: &[u8]) -> anyhow::Result<Self::Latest> {
173 Self::decode(Bytes::copy_from_slice(payload)).map_err(decode_error)
174 }
175
176 fn serialize_with_embedded_version(
179 value: &Self::Latest,
180 version: u16,
181 ) -> anyhow::Result<Vec<u8>> {
182 Self::seal_to_vec(value, version).map_err(encode_error)
183 }
184
185 fn deserialize(payload: &[u8], version: u16) -> anyhow::Result<Self::Latest> {
188 Self::decode_body(Bytes::copy_from_slice(payload), version).map_err(decode_error)
189 }
190
191 fn serialize(value: &Self::Latest, version: u16) -> anyhow::Result<Vec<u8>> {
193 let mut out = Vec::with_capacity(value.body_len());
194 Self::encode_body(value, version, &mut out).map_err(encode_error)?;
195 Ok(out)
196 }
197}
198
199fn decode_error(error: DecodeError) -> anyhow::Error {
201 match error.into_conversion() {
202 Ok(conversion) => conversion,
203 Err(error) => error.into(),
204 }
205}
206
207fn encode_error(error: EncodeError) -> anyhow::Error {
209 match error {
210 EncodeError::Conversion(conversion) => conversion,
211 EncodeError::BufferTooSmall { .. } | EncodeError::UnsupportedVersion(_) => error.into(),
212 }
213}
214
215fn check_capacity(needed: usize, available: usize) -> Result<(), EncodeError> {
216 if needed > available {
217 return Err(EncodeError::BufferTooSmall { needed, available });
218 }
219 Ok(())
220}
221
222fn split_header(mut bytes: Bytes) -> Result<(u16, Bytes), DecodeError> {
223 if bytes.len() < HEADER_LEN {
224 return Err(DecodeError::with_detail(
225 DecodeErrorKind::Truncated,
226 bytes.len(),
227 "missing version header",
228 ));
229 }
230 let body = bytes.split_off(HEADER_LEN);
231 let version = u16::from_le_bytes([bytes[0], bytes[1]]);
232 Ok((version, body))
233}
234
235fn check_decode_version<T: Versioned>(version: u16) -> Result<(), DecodeError> {
236 if version == 0 || version > T::LATEST {
237 return Err(DecodeError::with_detail(
238 DecodeErrorKind::UnsupportedVersion,
239 0,
240 format!("version {version}, latest is {}", T::LATEST),
241 ));
242 }
243 Ok(())
244}
245
246fn downgrade<T: Versioned>(value: &T::Latest, version: u16) -> Result<T, EncodeError> {
248 if version == 0 || version > T::LATEST {
249 return Err(EncodeError::UnsupportedVersion(version));
250 }
251 let steps = usize::from(T::LATEST - version);
252 let mut converted = T::wrap_latest(value.clone());
253 for downgrade in T::DOWNGRADES.iter().take(steps) {
254 converted = downgrade(converted).map_err(EncodeError::Conversion)?;
255 }
256 Ok(converted)
257}