Repository: typst/typst
File: crates/typst-utils/src/version.rs (Rust)

Code before:
use std::sync::OnceLock;

/// Static reference to the Typst version.
///
/// Refer to [`TypstVersion::new`] for a controlled way to obtain the locks content. By wrapping
/// [`TypstVersion`] into this structure we achieve two things:
///
/// 1. We have a singleton instance, so no matter how much code uses the version information it is
///    never duplicated.
/// 2. It has a `'static` lifetime, which makes it convenient to use pretty much anywhere in the
///    code.
static TYPST_VERSION_REF: OnceLock<TypstVersion> = OnceLock::new();

/// Typst version definition.
///
/// This structure contains the current Typst version. To query the precise version number, refer
/// to the [`TypstVersion::major()`], [`TypstVersion::minor()`] and [`TypstVersion::patch()`]
/// functions. You can read the underlying, raw version string (e.g. for CLI output) with
/// [`TypstVersion::raw`].
#[derive(Debug)]
pub struct TypstVersion {
    /// Parsed Typst version according to semantic versioning.
    version: semver::Version,
    /// Raw, unmodified version string.
    raw: &'static str,
}

impl TypstVersion {
    /// Get the Typst version.
    ///
    /// The raw Typst version is read from the following environment variables in order of
    /// precedence:
    ///
    /// - `TYPST_VERSION`
    /// - `CARGO_PKG_VERSION`
    ///
    /// Once that is obtained, it is parsed into a SemVer-compatible version structure.
    ///
    /// # Panics
    ///
    /// If all the environment variables mentioned above are undefined, or if an environment
    /// variable holds a version definition that doesn't conform to SemVer.
    pub fn new() -> &'static Self {
        TYPST_VERSION_REF.get_or_init(|| {
            if let Some(raw) = option_env!("TYPST_VERSION") {
                match semver::Version::parse(raw) {
                    Ok(version) => Self { version, raw },
                    Err(err) => panic!(

Review comment (suggestion):
I think I'd directly put the major/minor/patch triple here (essentially only using semver for extracing major/minor/patch) and then we can make the type `Copy` and return it by value everywhere.

Code after:
//! Typst version information.

/// Returns the version of Typst.
///
/// The information is read from the following sources:
///
/// - For the version number: The `TYPST_VERSION` environment variable
/// - For the commit hash: The `TYPST_COMMIT_SHA` environment variable
///
/// Build tooling can set these environment variables to configure the exposed
/// information. If the environment variables are left unset, the values are
/// populated via `build.rs` from the Cargo package manifest version and the git
/// hash in the current repository (if any).
///
/// # Panics
/// If the `TYPST_VERSION` environment variable holds a version string that
/// doesn't conform to SemVer.
pub fn version() -> TypstVersion {
    *crate::singleton!(TypstVersion, {
        let raw = env!("TYPST_VERSION");
        let commit = option_env!("TYPST_COMMIT_SHA");
        match semver::Version::parse(raw) {
            Ok(version) => {
                return TypstVersion {
                    major: version.major.try_into().unwrap(),
                    minor: version.minor.try_into().unwrap(),
                    patch: version.patch.try_into().unwrap(),
                    raw,
                    commit,
                };
            }
            Err(err) => {
                panic!("failed to parse {raw:?} as semantic version number: {err:?}")
            }
        }
    })
}

/// Typst version definition.
///
/// This structure contains the current Typst version. To query the precise
/// version number, refer to the [`TypstVersion::major()`],
/// [`TypstVersion::minor()`] and [`TypstVersion::patch()`] functions. You can
/// read the underlying, raw version string (e.g., for CLI output) with
/// [`TypstVersion::raw`].
///
/// Optionally, this may also contain the hash value of the Git commit from
/// which Typst was built. However, this field may be unpopulated.