Skip to main content

rtb_app/
version.rs

1//! Build-time version information.
2
3use semver::Version;
4use serde::{Deserialize, Serialize};
5
6/// Version information captured at build time.
7///
8/// Populate the `version` field from `env!("CARGO_PKG_VERSION")` (the
9/// [`VersionInfo::from_env`] helper does this) and inject `commit` /
10/// `date` via your `build.rs` (the `vergen` or `built` crates are
11/// canonical).
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct VersionInfo {
14    /// Parsed semantic version.
15    pub version: Version,
16
17    /// Short commit SHA, if known at build time.
18    #[serde(default)]
19    pub commit: Option<String>,
20
21    /// ISO-8601 build timestamp, if known at build time.
22    #[serde(default)]
23    pub date: Option<String>,
24}
25
26impl VersionInfo {
27    /// Construct from a parsed semver. `commit` and `date` start unset
28    /// — add them with [`Self::with_commit`] / [`Self::with_date`].
29    #[must_use]
30    pub const fn new(version: Version) -> Self {
31        Self { version, commit: None, date: None }
32    }
33
34    /// Fluent setter for the commit SHA.
35    #[must_use]
36    pub fn with_commit(mut self, commit: impl Into<String>) -> Self {
37        self.commit = Some(commit.into());
38        self
39    }
40
41    /// Fluent setter for the build timestamp.
42    #[must_use]
43    pub fn with_date(mut self, date: impl Into<String>) -> Self {
44        self.date = Some(date.into());
45        self
46    }
47
48    /// Convenience: parse `CARGO_PKG_VERSION` with a silent fallback to
49    /// `0.0.0` when parsing fails (which in turn is flagged by
50    /// [`Self::is_development`]).
51    ///
52    /// Call this inside `fn main()` — it's evaluated per-invocation,
53    /// not per-build.
54    #[must_use]
55    pub fn from_env() -> Self {
56        let raw = env!("CARGO_PKG_VERSION");
57        let version = Version::parse(raw).unwrap_or_else(|_| Version::new(0, 0, 0));
58        Self::new(version)
59    }
60
61    /// `true` when this build is a development / pre-release build.
62    ///
63    /// Development is any of:
64    ///
65    /// * `major == 0` (pre-1.0 builds are always considered development),
66    /// * a non-empty pre-release identifier (`-alpha`, `-dev.5`, …),
67    /// * version exactly `0.0.0` (the [`Self::from_env`] fallback).
68    #[must_use]
69    pub fn is_development(&self) -> bool {
70        self.version.major == 0 || !self.version.pre.is_empty()
71    }
72}