use core_extensions::prelude::*;
use std::{
error,
fmt::{self, Display},
num::ParseIntError,
};
use crate::std_types::StaticStr;
#[derive(Debug, Copy, Clone, PartialEq, Eq, StableAbi)]
#[repr(C)]
#[sabi(inside_abi_stable_crate)]
pub struct VersionStrings {
pub major: StaticStr,
pub minor: StaticStr,
pub patch: StaticStr,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, StableAbi)]
#[repr(C)]
#[sabi(inside_abi_stable_crate)]
pub struct VersionNumber {
pub major: u32,
pub minor: u32,
pub patch: u32,
}
impl VersionStrings {
pub fn parsed(self) -> Result<VersionNumber, ParseVersionError> {
VersionNumber::new(self)
}
}
impl VersionNumber {
pub fn new(vn: VersionStrings) -> Result<Self, ParseVersionError> {
VersionNumber {
major: vn
.major
.parse()
.map_err(|x| ParseVersionError::new(vn, "major", x))?,
minor: vn
.minor
.parse()
.map_err(|x| ParseVersionError::new(vn, "minor", x))?,
patch: vn
.patch
.split_while(|x| '0' <= x && x <= '9')
.find(|x| x.key)
.map_or("0", |x| x.str)
.parse()
.map_err(|x| ParseVersionError::new(vn, "patch", x))?,
}
.piped(Ok)
}
pub fn is_compatible(self, library_implementor: VersionNumber) -> bool {
if self.major == 0 && library_implementor.major == 0 {
self.minor == library_implementor.minor && self.patch <= library_implementor.patch
} else {
self.major == library_implementor.major && self.minor <= library_implementor.minor
}
}
}
impl fmt::Display for VersionNumber {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
}
}
impl fmt::Display for VersionStrings {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
}
}
#[macro_export]
macro_rules! package_version_strings {
() => {{
use $crate::std_types::StaticStr;
$crate::version::VersionStrings {
major: StaticStr::new(env!("CARGO_PKG_VERSION_MAJOR")),
minor: StaticStr::new(env!("CARGO_PKG_VERSION_MINOR")),
patch: StaticStr::new(env!("CARGO_PKG_VERSION_PATCH")),
}
}};
}
#[derive(Debug, Clone, PartialEq)]
pub struct ParseVersionError {
version_strings: VersionStrings,
which_field: &'static str,
parse_error: ParseIntError,
}
impl ParseVersionError {
fn new(
version_strings: VersionStrings,
which_field: &'static str,
parse_error: ParseIntError,
) -> Self {
Self {
version_strings,
which_field,
parse_error,
}
}
pub fn version_strings(&self) -> VersionStrings {
self.version_strings
}
}
impl Display for ParseVersionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(
f,
"\nInvalid version string:'{}'\nerror at the {} field:{}",
self.version_strings, self.which_field, self.parse_error,
)
}
}
impl error::Error for ParseVersionError {}