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

Code before:
    ///
    /// 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!(
                        "failed to parse {:?} from variable {:?} as semantic version number: {:?}",
                        raw,
                        "TYPST_VERSION",
                        err,
                    ),
                }
            } else if let Some(raw) = option_env!("CARGO_PKG_VERSION") {
                match semver::Version::parse(raw) {
                    Ok(version) => Self { version, raw },
                    Err(err) => panic!(
                        "failed to parse {:?} from variable {:?} as semantic version number: {:?}",
                        raw,
                        "CARGO_PKG_VERSION",
                        err,
                    ),
                }
            } else {
                panic!("no version was specified at compile time, Typst version is unknown");
            }
        })
    }

    /// Return the Typst major version.
    pub fn major(&self) -> u64 {
        self.version.major
    }

    /// Return the Typst minor version.
    pub fn minor(&self) -> u64 {
        self.version.minor
    }

    /// Return the Typst patch version.
    pub fn patch(&self) -> u64 {
        self.version.patch
    }

    /// Return the raw, unparsed version string.
    pub fn raw(&self) -> &'static str {
        self.raw
    }
}

Review comment (refactor):
We could deduplicate this without a macro like this:
```rust
for (source), version in [
    ("TYPST_VERSION", option_env!("TYPST_VERSION")),
    ("CARGO_PKG_VERSION", option_env!("CARGO_PKG_VERSION")),
] {
  ...
}
```

Code after:
///
/// 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.
#[derive(Debug, Clone, Copy)]
pub struct TypstVersion {
    /// Typst major version number.
    major: u32,
    /// Typst minor version number.
    minor: u32,
    /// Typst patch version number.
    patch: u32,
    /// Raw, unmodified version string.
    raw: &'static str,
    /// The raw commit hash.
    commit: Option<&'static str>,
}

impl TypstVersion {
    /// Returns the Typst major version.
    pub fn major(&self) -> u32 {
        self.major
    }

    /// Returns the Typst minor version.
    pub fn minor(&self) -> u32 {
        self.minor
    }

    /// Returns the Typst patch version.
    pub fn patch(&self) -> u32 {
        self.patch
    }

    /// Returns the raw, unparsed version string.
    ///
    /// Guaranteed to conform to SemVer.
    pub fn raw(&self) -> &'static str {
        self.raw
    }

    /// Returns the commit Typst was built from, if known.
    pub fn commit(&self) -> Option<&'static str> {
        self.commit
    }
}