1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
45use crate::serialized_types::types::LATEST_VERSION;
6use crate::serialized_types::DEFAULT_MAX_SERIALIZED_RECORD_SIZE;
7use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
8use fprint::TypeFingerprint;
9use serde::{Deserialize, Serialize};
1011/// [Version] are themselves serializable both alone and as part
12/// of other [Versioned] structures.
13/// (For obvious recursive reasons, this structure can never be [Versioned] itself.)
14#[derive(
15 Debug, Default, Copy, Clone, Eq, PartialEq, PartialOrd, Serialize, Deserialize, TypeFingerprint,
16)]
17pub struct Version {
18/// Major version indicates structural layout/encoding changes.
19 /// Note that this is encoded as a u24.
20pub major: u32,
21/// Minor version indicates forwards compatible changes.
22 /// e.g. The addition of a layer-file index, bloom filters, file attributes or posix
23 /// features where reversion to a previous minor will simply lead to loss of these features.
24pub minor: u8,
25}
26impl std::fmt::Display for Version {
27fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28write!(f, "{}.{}", self.major, self.minor)
29 }
30}
31impl Version {
32pub fn deserialize_from<R: ?Sized>(reader: &mut R) -> anyhow::Result<Self>
33where
34R: std::io::Read,
35 {
36Ok(Version { major: reader.read_u24::<LittleEndian>()?, minor: reader.read_u8()? })
37 }
38pub fn serialize_into<W>(&self, writer: &mut W) -> anyhow::Result<()>
39where
40W: std::io::Write,
41 {
42 writer.write_u24::<LittleEndian>(self.major)?;
43 writer.write_u8(self.minor)?;
44Ok(())
45 }
46}
4748/// This trait is assigned to all versions of a versioned type and is the only means of
49/// serialization/deserialization we use.
50///
51/// It also allows versions to serialize/deserialize themselves differently on a per-version basis.
52/// Doing this here enforces consistency at a given filesystem version.
53///
54pub trait Versioned: Serialize + for<'de> Deserialize<'de> {
55fn max_serialized_size() -> u64 {
56 DEFAULT_MAX_SERIALIZED_RECORD_SIZE
57 }
5859fn deserialize_from<R: ?Sized>(reader: &mut R, _version: Version) -> anyhow::Result<Self>
60where
61R: std::io::Read,
62for<'de> Self: serde::Deserialize<'de>,
63 {
64use bincode::Options;
65let options = bincode::DefaultOptions::new()
66 .with_limit(Self::max_serialized_size())
67 .allow_trailing_bytes();
68match options.deserialize_from(reader) {
69// Strip bincode wrapping. anyhow can take std::io::Error.
70Err(e) => Err(if let bincode::ErrorKind::Io(e) = *e { e.into() } else { e.into() }),
71Ok(t) => Ok(t),
72 }
73 }
74fn serialize_into<W>(&self, writer: &mut W) -> anyhow::Result<()>
75where
76W: std::io::Write,
77Self: serde::Serialize,
78 {
79use bincode::Options;
80let options = bincode::DefaultOptions::new()
81 .with_limit(Self::max_serialized_size())
82 .allow_trailing_bytes();
83match options.serialize_into(writer, self) {
84// Strip bincode wrapping. anyhow can take std::io::Error.
85Err(e) => Err(if let bincode::ErrorKind::Io(e) = *e { e.into() } else { e.into() }),
86Ok(t) => Ok(t),
87 }
88 }
89}
9091/// This trait is only assigned to the latest version of a type and allows the type to deserialize
92/// any older versions and upgrade them to the latest format.
93pub trait VersionedLatest: Versioned + TypeFingerprint {
94/// Deserializes from a given version format and upgrades to the latest version.
95fn deserialize_from_version<R>(reader: &mut R, version: Version) -> anyhow::Result<Self>
96where
97R: std::io::Read,
98Self: Sized;
99100/// Like `deserialize_from_version` but reads Version from reader first, then uses it to
101 /// deserialize self.
102fn deserialize_with_version<R>(reader: &mut R) -> anyhow::Result<(Self, Version)>
103where
104R: std::io::Read,
105Self: Sized,
106 {
107let version = Version::deserialize_from(reader)?;
108Ok((Self::deserialize_from_version(reader, version)?, version))
109 }
110/// Like `serialize_into` but serialized Version first, then self.
111fn serialize_with_version<W>(&self, writer: &mut W) -> anyhow::Result<()>
112where
113W: std::io::Write,
114Self: Sized,
115 {
116 LATEST_VERSION.serialize_into(writer)?;
117self.serialize_into(writer)
118 }
119}