use anyhow::{bail, Context, Result};
pub trait VersionedData<'a>: Sized {
type Latest;
fn wrap_latest(latest: Self::Latest) -> Self;
fn unwrap_latest(self) -> Result<Self::Latest>;
fn deserialize_version(payload: &'a [u8], version: u16) -> Result<Self>;
fn serialize_version(self, version: u16) -> Result<Vec<u8>>;
fn deserialize_converters() -> Vec<impl Fn(Self) -> Result<Self>> {
if false {
vec![identity]
} else {
Vec::new()
}
}
fn serialize_converters() -> Vec<impl Fn(Self) -> Result<Self>> {
if false {
vec![identity]
} else {
Vec::new()
}
}
fn deserialize(payload: &'a [u8], version: u16) -> Result<Self::Latest> {
let mut data = Self::deserialize_version(payload, version)?;
let skip_count = version
.checked_sub(1)
.with_context(|| format!("proto version ({version}) must be > 0"))?;
for converter in Self::deserialize_converters()
.iter()
.skip(skip_count as usize)
{
data = converter(data)?;
}
data.unwrap_latest()
}
fn serialize(self, version: u16) -> Result<Vec<u8>> {
let mut data = self;
let converters = Self::serialize_converters();
let take_count = (converters.len() + 1)
.checked_sub(version as usize)
.with_context(|| {
format!(
"proto version ({version}) greater than latest version ({})",
converters.len() + 1
)
})?;
for converter in converters.iter().take(take_count) {
data = converter(data)?;
}
Self::serialize_version(data, version)
}
fn deserialize_with_embedded_version(payload: &'a [u8]) -> Result<Self::Latest> {
if payload.len() < 2 {
bail!("payload too short for embedded version");
}
let version = u16::from_le_bytes([payload[0], payload[1]]);
let payload = &payload[2..];
Self::deserialize(payload, version)
}
fn serialize_with_embedded_version(self, version: u16) -> Result<Vec<u8>> {
let payload = self.serialize(version)?;
let mut result = Vec::with_capacity(2 + payload.len());
result.extend_from_slice(&version.to_le_bytes());
result.extend_from_slice(&payload);
Ok(result)
}
}
pub trait OwnedVersionedData: Sized {
type Latest;
fn wrap_latest(latest: Self::Latest) -> Self;
fn unwrap_latest(self) -> Result<Self::Latest>;
fn deserialize_version(payload: &[u8], version: u16) -> Result<Self>;
fn serialize_version(self, version: u16) -> Result<Vec<u8>>;
fn deserialize_converters() -> Vec<impl Fn(Self) -> Result<Self>> {
if false {
vec![identity]
} else {
Vec::new()
}
}
fn serialize_converters() -> Vec<impl Fn(Self) -> Result<Self>> {
if false {
vec![identity]
} else {
Vec::new()
}
}
fn deserialize(payload: &[u8], version: u16) -> Result<Self::Latest> {
let mut data = Self::deserialize_version(payload, version)?;
let skip_count = version
.checked_sub(1)
.with_context(|| format!("proto version ({version}) must be > 0"))?;
for converter in Self::deserialize_converters()
.iter()
.skip(skip_count as usize)
{
data = converter(data)?;
}
data.unwrap_latest()
}
fn serialize(self, version: u16) -> Result<Vec<u8>> {
let mut data = self;
let converters = Self::serialize_converters();
let take_count = (converters.len() + 1)
.checked_sub(version as usize)
.with_context(|| {
format!(
"proto version ({version}) greater than latest version ({})",
converters.len() + 1
)
})?;
for converter in converters.iter().take(take_count) {
data = converter(data)?;
}
Self::serialize_version(data, version)
}
fn deserialize_with_embedded_version(payload: &[u8]) -> Result<Self::Latest> {
if payload.len() < 2 {
bail!("payload too short for embedded version");
}
let version = u16::from_le_bytes([payload[0], payload[1]]);
let payload = &payload[2..];
Self::deserialize(payload, version)
}
fn serialize_with_embedded_version(self, version: u16) -> Result<Vec<u8>> {
let payload = self.serialize(version)?;
let mut result = Vec::with_capacity(2 + payload.len());
result.extend_from_slice(&version.to_le_bytes());
result.extend_from_slice(&payload);
Ok(result)
}
}
fn identity<T>(v: T) -> Result<T> {
Ok(v)
}