use std::{fmt::Display, num::NonZeroU16, ops::RangeBounds};
use crate::data::{DeserializeCopy, Deserializeable, OutOfRange, Serializeable};
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Version {
fields: [u8; 2],
}
impl Version {
pub const fn from_pair_nonzero(
major: NonZeroU16,
minor: u8,
) -> Result<Self, OutOfRange<NonZeroU16>> {
let maj = major.get();
if maj > 256 {
Err(OutOfRange(major))
} else {
Ok(Self {
fields: [(maj - 1) as u8, minor],
})
}
}
pub const fn from_pair(maj: u16, minor: u8) -> Result<Self, OutOfRange<u16>> {
if maj > 256 || maj == 0 {
Err(OutOfRange(maj))
} else {
Ok(Self {
fields: [(maj - 1) as u8, minor],
})
}
}
pub const fn from_encoded(v: u16) -> Self {
Self {
fields: v.to_be_bytes(),
}
}
pub const fn into_encoded(self) -> u16 {
u16::from_be_bytes(self.fields)
}
pub const fn origin(mut self) -> Version {
self.fields[0] = 0;
self
}
pub const V1_0: Version = Version::from_encoded(0);
pub const V256_255: Version = Version::from_encoded(!0);
pub fn same_origin(self) -> impl RangeBounds<Version> {
let origin = self.origin();
origin..=self
}
pub const fn minor(self) -> u8 {
self.fields[1]
}
pub const fn major(self) -> NonZeroU16 {
unsafe { NonZeroU16::new_unchecked((self.fields[0] as u16) + 1) }
}
pub const fn major_encoded(self) -> u8 {
self.fields[0]
}
}
impl Display for Version {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{}.{}", self.major(), self.minor()))
}
}
impl Serializeable for Version {
fn serialize<W: crate::data::DataOutput + ?Sized>(
&self,
output: &mut W,
) -> std::io::Result<()> {
self.fields.serialize(output)
}
}
impl Deserializeable for Version {
fn deserialize<R: crate::data::DataInput + ?Sized>(
&mut self,
input: &mut R,
) -> std::io::Result<()> {
self.fields.deserialize(input)
}
}
impl DeserializeCopy for Version {
fn deserialize_copy<R: crate::data::DataInput + ?Sized>(
input: &mut R,
) -> std::io::Result<Self> {
Ok(Self {
fields: <[u8; 2]>::deserialize_copy(input)?,
})
}
}