binary_io/
version.rs

1//! Support for the LCS4 version structure type
2//!
3
4use std::{fmt::Display, num::NonZeroU16, ops::RangeBounds};
5
6use crate::data::{DeserializeCopy, Deserializeable, OutOfRange, Serializeable};
7
8///
9/// A two component Version which can be encoded according to LCS4
10#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub struct Version {
12    fields: [u8; 2],
13}
14
15impl Version {
16    ///
17    /// Obtains the version from the given pair
18    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    ///
33    /// Obtains the version from the given pair
34    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    ///
45    /// Decodes the given version into the fields of the verison, according to LCS 4
46    pub const fn from_encoded(v: u16) -> Self {
47        Self {
48            fields: v.to_be_bytes(),
49        }
50    }
51
52    ///
53    /// Encodes the version into a u16, according to LCS 4.
54    pub const fn into_encoded(self) -> u16 {
55        u16::from_be_bytes(self.fields)
56    }
57
58    ///
59    /// Obtains the version with the same major component but a 0 minor component
60    pub const fn origin(mut self) -> Version {
61        self.fields[0] = 0;
62        self
63    }
64
65    /// The version 1.0, or the smallest possible version
66    pub const V1_0: Version = Version::from_encoded(0);
67    /// The version 256.255, or the largest possible version
68    pub const V256_255: Version = Version::from_encoded(!0);
69
70    /// Returns a Range of versions that include all version from the origin to the current (inclusive)
71    pub fn same_origin(self) -> impl RangeBounds<Version> {
72        let origin = self.origin();
73        origin..=self
74    }
75
76    ///
77    /// Obtains the minor field, between 0 and 255 inclusive
78    pub const fn minor(self) -> u8 {
79        self.fields[1]
80    }
81
82    ///
83    /// Obtains the major field, between 1 and 256 inclusive
84    pub const fn major(self) -> NonZeroU16 {
85        // SAFETY:
86        // 0<=self.fields[0]<256
87        // thereof 1<=self.fields[0]+1<257
88        unsafe { NonZeroU16::new_unchecked((self.fields[0] as u16) + 1) }
89    }
90
91    ///
92    /// Obtains the encoded major field, which is self.major()-1
93    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}