1use std::{fmt::Display, num::NonZeroU16, ops::RangeBounds};
5
6use crate::data::{DeserializeCopy, Deserializeable, OutOfRange, Serializeable};
7
8#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub struct Version {
12 fields: [u8; 2],
13}
14
15impl Version {
16 pub const fn from_pair_nonzero(
19 major: NonZeroU16,
20 minor: u8,
21 ) -> Result<Self, OutOfRange<NonZeroU16>> {
22 let maj = major.get();
23 if maj > 256 {
24 Err(OutOfRange(major))
25 } else {
26 Ok(Self {
27 fields: [(maj - 1) as u8, minor],
28 })
29 }
30 }
31
32 pub const fn from_pair(maj: u16, minor: u8) -> Result<Self, OutOfRange<u16>> {
35 if maj > 256 || maj == 0 {
36 Err(OutOfRange(maj))
37 } else {
38 Ok(Self {
39 fields: [(maj - 1) as u8, minor],
40 })
41 }
42 }
43
44 pub const fn from_encoded(v: u16) -> Self {
47 Self {
48 fields: v.to_be_bytes(),
49 }
50 }
51
52 pub const fn into_encoded(self) -> u16 {
55 u16::from_be_bytes(self.fields)
56 }
57
58 pub const fn origin(mut self) -> Version {
61 self.fields[0] = 0;
62 self
63 }
64
65 pub const V1_0: Version = Version::from_encoded(0);
67 pub const V256_255: Version = Version::from_encoded(!0);
69
70 pub fn same_origin(self) -> impl RangeBounds<Version> {
72 let origin = self.origin();
73 origin..=self
74 }
75
76 pub const fn minor(self) -> u8 {
79 self.fields[1]
80 }
81
82 pub const fn major(self) -> NonZeroU16 {
85 unsafe { NonZeroU16::new_unchecked((self.fields[0] as u16) + 1) }
89 }
90
91 pub const fn major_encoded(self) -> u8 {
94 self.fields[0]
95 }
96}
97
98impl Display for Version {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 f.write_fmt(format_args!("{}.{}", self.major(), self.minor()))
101 }
102}
103
104impl Serializeable for Version {
105 fn serialize<W: crate::data::DataOutput + ?Sized>(
106 &self,
107 output: &mut W,
108 ) -> std::io::Result<()> {
109 self.fields.serialize(output)
110 }
111}
112
113impl Deserializeable for Version {
114 fn deserialize<R: crate::data::DataInput + ?Sized>(
115 &mut self,
116 input: &mut R,
117 ) -> std::io::Result<()> {
118 self.fields.deserialize(input)
119 }
120}
121
122impl DeserializeCopy for Version {
123 fn deserialize_copy<R: crate::data::DataInput + ?Sized>(
124 input: &mut R,
125 ) -> std::io::Result<Self> {
126 Ok(Self {
127 fields: <[u8; 2]>::deserialize_copy(input)?,
128 })
129 }
130}