use std::{fmt::Display, sync::OnceLock};
static VERSION_INFO_PKG: OnceLock<VersionInfo> = OnceLock::new();
static VERSION_INFO_SYS: OnceLock<VersionInfo> = OnceLock::new();
#[derive(Clone)]
#[non_exhaustive]
pub struct VersionInfo {
pub major: u16,
pub minor: u16,
pub patch: u16,
pub ident: Option<String>,
}
#[derive(Clone)]
#[non_exhaustive]
pub struct FapiVersion {
pub package: VersionInfo,
pub library: VersionInfo,
}
pub fn get_version() -> FapiVersion {
const PACKAGE_VERSION: &str = env!("CARGO_PKG_VERSION", "Package version is not defined!");
FapiVersion {
package: VERSION_INFO_PKG.get_or_init(|| parse_version(PACKAGE_VERSION)).clone(),
library: VERSION_INFO_SYS.get_or_init(|| parse_version(crate::fapi_sys::TSS2_FAPI_VERSION)).clone(),
}
}
fn parse_version(version_string: &str) -> VersionInfo {
let mut tokens = version_string.splitn(4usize, ['.', '+', '-', '_']).map(str::trim_ascii);
VersionInfo {
major: tokens.next().and_then(|str| str.parse::<u16>().ok()).unwrap_or_default(),
minor: tokens.next().and_then(|str| str.parse::<u16>().ok()).unwrap_or_default(),
patch: tokens.next().and_then(|str| str.parse::<u16>().ok()).unwrap_or_default(),
ident: tokens.next().filter(|str| !str.is_empty()).map(str::to_owned),
}
}
impl Display for VersionInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(ident_str) = self.ident.as_ref() {
write!(f, "{}.{}.{}-{}", self.major, self.minor, self.patch, ident_str)
} else {
write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
}
}
}