1use std::{
2 fs,
3 io::{self, Read},
4 iter::Sum,
5 ops::Add,
6 path::Path,
7};
8
9use allocative::Allocative;
10use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
11
12use crate::{Error, Result};
13
14#[derive(
20 Allocative,
21 Default,
22 Debug,
23 Clone,
24 Copy,
25 PartialEq,
26 Eq,
27 PartialOrd,
28 Ord,
29 FromBytes,
30 IntoBytes,
31 Immutable,
32 KnownLayout,
33)]
34pub struct Version(u64);
35
36impl Version {
37 pub const ZERO: Self = Self(0);
38 pub const ONE: Self = Self(1);
39 pub const TWO: Self = Self(2);
40
41 pub const fn new(v: u64) -> Self {
42 Self(v)
43 }
44
45 pub fn write(&self, path: &Path) -> Result<(), io::Error> {
46 fs::write(path, self.as_bytes())
47 }
48
49 pub fn swap_bytes(self) -> Self {
50 Self(self.0.swap_bytes())
51 }
52
53 pub fn validate(&self, path: &Path) -> Result<bool> {
59 if let Ok(prev_version) = Version::try_from(path) {
60 if prev_version != *self {
61 if prev_version.swap_bytes() == *self {
62 return Err(Error::WrongEndian);
63 }
64 return Err(Error::DifferentVersion {
65 found: prev_version,
66 expected: *self,
67 });
68 }
69
70 Ok(true)
71 } else {
72 Ok(false)
73 }
74 }
75}
76
77impl From<Version> for u64 {
78 fn from(value: Version) -> u64 {
79 value.0
80 }
81}
82
83impl From<u64> for Version {
84 fn from(value: u64) -> Self {
85 Self(value)
86 }
87}
88
89impl TryFrom<&Path> for Version {
90 type Error = Error;
91 fn try_from(value: &Path) -> Result<Self, Self::Error> {
92 let mut buf = [0; 8];
93 fs::read(value)?.as_slice().read_exact(&mut buf)?;
94 Ok(*(Self::ref_from_bytes(&buf)?))
95 }
96}
97
98impl Add<Version> for Version {
99 type Output = Self;
100 fn add(self, rhs: Version) -> Self::Output {
101 Self(self.0 + rhs.0)
102 }
103}
104
105impl Sum for Version {
106 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
107 iter.fold(Self::ZERO, Add::add)
108 }
109}