1use bitvec::prelude::*;
2
3use crate::{helpers::num_as_bv, sizes, Error, Magic};
4
5#[derive(Debug, PartialEq)]
16pub struct Semver {
17 pub major: usize,
19 pub minor: usize,
21 pub patch: usize,
23
24 magic: Magic,
26}
27
28impl Semver {
29 pub fn new(major: usize, minor: usize, patch: usize) -> Self {
31 Self {
32 major,
33 minor,
34 patch,
35 magic: Default::default(),
36 }
37 }
38
39 pub fn from_i64(n: i64) -> Result<Self, Error> {
41 let bytes = n.to_le_bytes();
42 let bv = bytes.view_bits::<Msb0>();
43 let sizes = sizes::size_iterator(&sizes::I64_SIZES);
44 Ok(Self::from_size_iterator(&bv, sizes)?)
45 }
46
47 pub fn from_u64(n: u64) -> Result<Self, Error> {
49 let i64 = i64::from_le_bytes(n.to_le_bytes());
50 Self::from_i64(i64)
51 }
52
53 pub fn from_i32(n: i32) -> Result<Self, Error> {
55 let bytes = n.to_le_bytes();
56 let bv = bytes.view_bits::<Msb0>();
57 let sizes = sizes::size_iterator(&sizes::I32_SIZES);
58 Ok(Self::from_size_iterator(bv, sizes)?)
59 }
60
61 pub fn from_u32(n: u32) -> Result<Self, Error> {
63 let i32 = i32::from_le_bytes(n.to_le_bytes());
64 Self::from_i32(i32)
65 }
66
67 pub fn to_i32(&self) -> Result<i32, Error> {
69 let mut bv: BitArray<[u8; 4], Msb0> = BitArray::ZERO;
70 let sizes = sizes::size_iterator(&sizes::I32_SIZES);
71 self.append_with_size_iterator(&mut bv, sizes)?;
72 Ok(i32::from_le_bytes(bv.data))
73 }
74
75 pub fn to_u32(&self) -> Result<u32, Error> {
77 let val = self.to_i32()?;
78 Ok(u32::from_le_bytes(val.to_le_bytes()))
79 }
80
81 pub fn to_i64(&self) -> Result<i64, Error> {
83 let mut bv: BitArray<[u8; 8], Msb0> = BitArray::ZERO;
84 let sizes = sizes::size_iterator(&sizes::I64_SIZES);
85 self.append_with_size_iterator(&mut bv, sizes)?;
86 Ok(i64::from_le_bytes(bv.data))
87 }
88
89 pub fn to_u64(&self) -> Result<u64, Error> {
91 let val = self.to_i64()?;
92 Ok(u64::from_le_bytes(val.to_le_bytes()))
93 }
94
95 fn from_size_iterator<const SIZE: usize>(
96 bv: &BitSlice<u8, Msb0>,
97 mut sizes: sizes::SizeIterator<SIZE>,
98 ) -> Result<Self, Error> {
99 Ok(Self {
100 magic: convert_api_version(bv[sizes.next().unwrap()].load::<u64>())?,
101 major: bv[sizes.next().unwrap()].load::<usize>(),
102 minor: bv[sizes.next().unwrap()].load::<usize>(),
103 patch: bv[sizes.next().unwrap()].load::<usize>(),
104 })
105 }
106
107 fn append_with_size_iterator<const SIZE: usize, const ITER_SIZE: usize>(
108 &self,
109 bv: &mut BitArray<[u8; SIZE], Msb0>,
110 mut sizes: sizes::SizeIterator<ITER_SIZE>,
111 ) -> Result<(), Error> {
112 num_as_bv(bv, &mut sizes, Magic::default() as u64)?; num_as_bv(bv, &mut sizes, self.major as u64)?;
114 num_as_bv(bv, &mut sizes, self.minor as u64)?;
115 num_as_bv(bv, &mut sizes, self.patch as u64)?;
116 Ok(())
117 }
118}
119
120fn convert_api_version(n: u64) -> Result<Magic, Error> {
121 let api_version = match n {
122 0 => Magic::V0,
123 1 => Magic::V1,
124 2 => Magic::V2,
125 3 => Magic::V3,
126 _ => return Err(Error::UnknownMagic(n)),
127 };
128
129 match api_version {
130 Magic::V0 => (),
131 _ => return Err(Error::UnsupportedMagic(api_version)),
132 }
133
134 Ok(api_version)
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn test_roundtrips() {
143 assert_roundtrip_i32(Semver::new(254, 500, 498));
144 assert_roundtrip_i32(Semver::new(0, 0, 0));
145
146 assert_roundtrip_u32(Semver::new(254, 500, 498));
147 assert_roundtrip_u32(Semver::new(0, 0, 0));
148
149 assert_roundtrip_i64(Semver::new(65343, 64000, 65310));
150 assert_roundtrip_i64(Semver::new(0, 0, 0));
151
152 assert_roundtrip_u64(Semver::new(65343, 64000, 65310));
153 assert_roundtrip_u64(Semver::new(0, 0, 0));
154
155 let val = Semver::new(5, 230, 150).to_i32().unwrap() as u32;
156 let version = Semver::from_u32(val).unwrap();
157 assert_eq!(version, Semver::new(5, 230, 150));
158 }
159
160 #[test]
161 fn test_unsupported_api_version() {
162 let mut bv: BitArray<[u8; 4], Msb0> = BitArray::ZERO;
163 let mut iter = sizes::size_iterator(&sizes::I32_SIZES);
164 num_as_bv(&mut bv, &mut iter, Magic::V2 as u64).unwrap();
165 let val = i32::from_le_bytes(bv.data);
166
167 assert_eq!(
168 Semver::from_i32(val).unwrap_err(),
169 Error::UnsupportedMagic(Magic::V2)
170 );
171 }
172
173 #[test]
174 fn test_unknown_api_version() {
175 let mut bv: BitArray<[u8; 8], Msb0> = BitArray::ZERO;
176 let mut iter = sizes::size_iterator(&sizes::I64_SIZES);
177 num_as_bv(&mut bv, &mut iter, 13).unwrap();
178 let val = i64::from_le_bytes(bv.data);
179
180 assert_eq!(Semver::from_i64(val).unwrap_err(), Error::UnknownMagic(13));
181 }
182
183 #[test]
184 fn test_from_i32() {
185 assert_eq!(Semver::from_i32(16843009).unwrap(), test_version())
186 }
187
188 #[test]
189 fn test_from_u32() {
190 let u32 = u32::from_le_bytes(16843009i32.to_le_bytes());
191 assert_eq!(Semver::from_u32(u32).unwrap(), test_version())
192 }
193
194 #[test]
195 fn test_from_i64() {
196 assert_eq!(Semver::from_i64(21474902017).unwrap(), test_version())
197 }
198
199 #[test]
200 fn test_from_u64() {
201 let u64 = u64::from_le_bytes(21474902017i64.to_le_bytes());
202 assert_eq!(Semver::from_u64(u64).unwrap(), test_version())
203 }
204
205 #[test]
206 fn test_to_i32() {
207 let val = test_version().to_i32().unwrap();
208 assert_eq!(val, 16843009);
209 assert_eq!(&val.to_le_bytes()[..], &[0b1, 0b1, 0b1, 0b1]);
210 }
211
212 #[test]
213 fn test_to_i64() {
214 let val = test_version().to_i64().unwrap();
215 assert_eq!(
216 &val.to_le_bytes()[..],
217 &[0b1, 0b0, 0b1, 0b0, 0b101, 0b0, 0b0, 0b0]
218 );
219
220 assert_eq!(val, 21474902017);
221 }
222
223 #[test]
224 fn test_overflow_i32() {
225 assert!(Semver::new(2usize.pow(10), 2usize.pow(10), 2usize.pow(10))
226 .to_i32()
227 .is_ok());
228
229 assert_eq!(
231 Semver::new(2usize.pow(10) + 1, 0, 0).to_i32().unwrap_err(),
232 Error::Overflow
233 );
234
235 assert_eq!(
236 Semver::new(0, 2usize.pow(10) + 1, 0).to_i32().unwrap_err(),
237 Error::Overflow
238 );
239
240 assert_eq!(
241 Semver::new(0, 0, 2usize.pow(10) + 1).to_i32().unwrap_err(),
242 Error::Overflow
243 );
244 }
245
246 #[test]
247 fn test_overflow_i64() {
248 assert!(Semver::new(2usize.pow(16), 2usize.pow(16), 2usize.pow(16))
249 .to_i64()
250 .is_ok());
251
252 let overflow = 2usize.pow(16) + 1;
254
255 assert_eq!(
256 Semver::new(overflow, 0, 0).to_i64().unwrap_err(),
257 Error::Overflow
258 );
259
260 assert_eq!(
261 Semver::new(0, overflow, 0).to_i64().unwrap_err(),
262 Error::Overflow
263 );
264
265 assert_eq!(
266 Semver::new(0, 0, overflow).to_i64().unwrap_err(),
267 Error::Overflow
268 );
269 }
270
271 fn test_version() -> Semver {
272 Semver {
273 major: 1,
274 minor: 1,
275 patch: 5,
276 magic: Magic::V0,
277 }
278 }
279
280 fn assert_roundtrip_i32(ver: Semver) {
281 assert_eq!(Semver::from_i32(ver.to_i32().unwrap()).unwrap(), ver);
282 }
283
284 fn assert_roundtrip_u32(ver: Semver) {
285 assert_eq!(Semver::from_u32(ver.to_u32().unwrap()).unwrap(), ver);
286 }
287
288 fn assert_roundtrip_i64(ver: Semver) {
289 assert_eq!(Semver::from_i64(ver.to_i64().unwrap()).unwrap(), ver);
290 }
291
292 fn assert_roundtrip_u64(ver: Semver) {
293 assert_eq!(Semver::from_u64(ver.to_u64().unwrap()).unwrap(), ver);
294 }
295}