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