scarb_metadata/
version_pin.rs

1use std::fmt;
2
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4
5#[cfg(doc)]
6use super::Metadata;
7
8const METADATA_VERSION: u64 = {
9    // `FromStr` is not `const`, so we do poor man's parsing ourselves here.
10    let mut bytes = env!("CARGO_PKG_VERSION_MAJOR").as_bytes();
11    let mut num = 0u64;
12    while let [ch @ b'0'..=b'9', rem @ ..] = bytes {
13        bytes = rem;
14        num *= 10;
15        num += (*ch - b'0') as u64;
16    }
17    num
18};
19
20/// A zero-sized type enforcing [`serde`] to serialize/deserialize it to a constant number
21/// representing version of [`Metadata`] schema.
22///
23/// The version number corresponds to the major version of this crate.
24#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
25pub struct VersionPin;
26
27impl VersionPin {
28    /// Get version as a number.
29    pub const fn numeric(self) -> u64 {
30        METADATA_VERSION
31    }
32
33    /// Construct this pin if `num` equals to the pinned version.
34    pub const fn from_numeric(num: u64) -> Option<Self> {
35        if num == Self.numeric() {
36            Some(Self)
37        } else {
38            None
39        }
40    }
41}
42
43impl Serialize for VersionPin {
44    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
45        s.serialize_u64(self.numeric())
46    }
47}
48
49impl<'de> Deserialize<'de> for VersionPin {
50    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<VersionPin, D::Error> {
51        use serde::de::Error;
52        let num = u64::deserialize(d)?;
53        VersionPin::from_numeric(num)
54            .ok_or_else(|| Error::custom(format!("expected metadata version {}", Self.numeric())))
55    }
56}
57
58impl From<VersionPin> for u64 {
59    fn from(pin: VersionPin) -> Self {
60        pin.numeric()
61    }
62}
63
64impl fmt::Display for VersionPin {
65    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66        write!(f, "{}", Self.numeric())
67    }
68}