embedded_semver/lib.rs
1//! Compact representation of semantic versions as an i32, u32 i64 or u64
2//!
3//! Limitations:
4//! * Storage format is not standards-conformant (none exists at the time of writing)
5//! * 32-bit values can represent values in range of `major/minor/patch` = `0 - 1023` (10 bits)
6//! * 64-bit values can represent values in range of `major/minor/patch` = `0 - 65535` (16 bits)
7//! * Other than major/minor/patch features (e.g pre-release) are not supported
8//!
9//! # Examples
10//!
11//! Encode a semver to an integer
12//! ```rust
13//! use embedded_semver::Semver;
14//!
15//! let version = Semver::new(1, 0, 20);
16//!
17//! let int_semver = version.to_i32().unwrap();
18//! assert_eq!(int_semver, 83886081);
19//! assert_eq!(&int_semver.to_le_bytes(), &[0b0000_0001, 0b0000_0000, 0b0000_0000, 0b0000_0101]);
20//! ```
21//!
22//! Decode an integer into a semver:
23//! ```rust
24//! # use embedded_semver::Semver;
25//! #
26//! let int_semver: i32 = 83886081;
27//!
28//! let version = Semver::from_i32(int_semver).unwrap();
29//! assert_eq!(version, Semver::new(1, 0, 20));
30//! ```
31//!
32//! # Binary format
33//!
34//! * Fields are packed with the most significant bit first (see [Msb0](https://docs.rs/bitvec/0.22.3/bitvec/order/struct.Msb0.html))
35//! * Format contains a 2-bit (on 32-bit values) and 4-bit (on 64-bit values) api version, which
36//! allows for extensibility and/or api changes in future
37//!
38//! ## 32 bits
39//! The binary format for `i32` and `u32` is represented below. Fields:
40//!
41//! * `version`: First two bits represent the API version (packed data format). Currenly 0 = V0
42//! * `major`: Next 10 bits represent major in range of 0-1023
43//! * `minor`: Next 10 bits represent minor in range of 0-1023
44//! * `patch`: Next 10 bits represent patch in range of 0-1023
45//!
46//! ```text
47//! 0 2 12 22 32
48//! ├────┴────┼┴┴┴┴┴┴┴┴┴┼┴┴┴┴┴┴┴┴┴┼┴┴┴┴┴┴┴┴┴┤
49//! │ API ver │ Major │ Minor │ Patch │
50//! │ u2 │ u10 │ u10 │ u10 │
51//! └─────────┴─────────┴─────────┴─────────┘
52//! ```
53//!
54//! ## 64 bits
55//! The binary format for `i64` and `u64` is represented below. Fields:
56//!
57//! * `version`: First four bits represent the API version (packed data format). Currenly 0 = V0
58//! * `major`: Next 16 bits represent major in range of 0-65535
59//! * `minor`: Next 16 bits represent minor in range of 0-65535
60//! * `patch`: Next 16 bits represent patch in range of 0-65535
61//! * 12 remaining bits are unused
62//!
63//! ```text
64//! 0 4 20 36 52 64
65//! ├─┴──┴─┴──┼┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┼┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┼┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┼┴┴┴┴┴┴┴┴┴┴┴┤
66//! │ API ver │ Major │ Minor │ Patch | (unused) │
67//! │ u4 │ u16 │ u16 │ u16 | u12 │
68//! └─────────┴───────────────┴─────────────────┴─────────────────┴───────────┘
69//! ```
70//!
71//! # Notes about conversions
72//!
73//! Note that the binary representations in i32 and i64 are not the same:
74//! ```rust
75//! # use embedded_semver::{Semver, Error, Magic};
76//! #
77//! let value: i32 = 16904511;
78//!
79//! assert_eq!(Semver::from_i32(value).unwrap(), Semver::new(1023, 1, 5));
80//! assert_eq!(
81//! Semver::from_i64(value as i64).unwrap_err(),
82//! Error::UnsupportedMagic(Magic::V3)
83//! );
84//! ```
85//!
86//! However, the underlying bits in u32 and i32 represent the same values:
87//! ```rust
88//! # use embedded_semver::{Semver, Error};
89//! #
90//! let value: i32 = 16843009;
91//! let bytes = value.to_le_bytes();
92//!
93//! let i32_value = i32::from_le_bytes(bytes.clone());
94//! let u32_value = u32::from_le_bytes(bytes);
95//!
96//! assert_eq!(Semver::from_i32(i32_value).unwrap(), Semver::new(1, 1, 5));
97//! assert_eq!(Semver::from_u32(u32_value).unwrap(), Semver::new(1, 1, 5));
98//! ```
99
100#![cfg_attr(not(feature = "std"), no_std)]
101
102pub mod prelude {
103 pub use crate::{Error, Magic, Semver};
104}
105
106mod error;
107mod helpers;
108mod sizes;
109mod version;
110
111pub use error::Error;
112pub use version::Semver;
113
114/// Magic number - storage format
115///
116/// Currently all operations are based on [`Magic::V0`], others are left
117/// for future extensibility.
118#[derive(Debug, PartialEq)]
119pub enum Magic {
120 // can have max 4 (2 bits)
121 V0 = 0,
122 V1 = 1,
123 V2 = 2,
124 V3 = 3,
125}
126
127impl Default for Magic {
128 fn default() -> Self {
129 Magic::V0
130 }
131}