1use std::{
2 fs,
3 io::{self, Read},
4 iter::Sum,
5 ops::Add,
6 path::Path,
7};
8
9use crate::{Bytes, Error, Result, SIZE_OF_U64};
10
11#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
17#[must_use = "Version values should be used for compatibility checks"]
18pub struct Version(u64);
19
20impl Version {
21 pub const ZERO: Self = Self(0);
22 pub const ONE: Self = Self(1);
23 pub const TWO: Self = Self(2);
24
25 pub const fn new(v: u64) -> Self {
26 Self(v)
27 }
28
29 pub fn write(&self, path: &Path) -> Result<(), io::Error> {
30 fs::write(path, self.to_bytes().as_ref())
31 }
32
33 pub fn swap_bytes(self) -> Self {
34 Self(self.0.swap_bytes())
35 }
36}
37
38impl Bytes for Version {
39 type Array = [u8; size_of::<Self>()];
40
41 #[inline]
42 fn to_bytes(&self) -> Self::Array {
43 self.0.to_bytes()
44 }
45
46 #[inline]
47 fn from_bytes(bytes: &[u8]) -> Result<Self> {
48 Ok(Self(u64::from_bytes(bytes)?))
49 }
50}
51
52impl From<Version> for u64 {
53 fn from(value: Version) -> u64 {
54 value.0
55 }
56}
57
58impl From<u64> for Version {
59 fn from(value: u64) -> Self {
60 Self(value)
61 }
62}
63
64impl TryFrom<&Path> for Version {
65 type Error = Error;
66 fn try_from(value: &Path) -> Result<Self, Self::Error> {
67 let mut buf = [0; SIZE_OF_U64];
68 fs::read(value)?.as_slice().read_exact(&mut buf)?;
69 Self::from_bytes(&buf)
70 }
71}
72
73impl Add<Version> for Version {
74 type Output = Self;
75 fn add(self, rhs: Version) -> Self::Output {
76 Self(self.0 + rhs.0)
77 }
78}
79
80impl Sum for Version {
81 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
82 iter.fold(Self::ZERO, Add::add)
83 }
84}