rustpatcher 0.2.2

distributed patching system for single binary applications
Documentation
use std::{fmt::Display, str::FromStr};

use anyhow::bail;
use serde::{Deserialize, Serialize};
use tracing::warn;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Version(pub i32, pub i32, pub i32);

impl Display for Version {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}.{}.{}", self.0, self.1, self.2)
    }
}

impl FromStr for Version {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<&str> = s.split('.').collect();

        if parts.len() != 3 {
            bail!("wrong version format")
        }

        let major = parts[0].parse::<i32>()?;
        let minor = parts[1].parse::<i32>()?;
        let patch = parts[2].parse::<i32>()?;

        Ok(Version(major, minor, patch))
    }
}

impl PartialOrd for Version {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Version {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        let self_sum: i128 = ((i32::MAX as i128).pow(2) * self.0 as i128)
            + ((i32::MAX as i128).pow(1) * self.1 as i128)
            + self.2 as i128;
        let other_sum: i128 = ((i32::MAX as i128).pow(2) * other.0 as i128)
            + ((i32::MAX as i128).pow(1) * other.1 as i128)
            + other.2 as i128;
        self_sum.cmp(&other_sum)
    }

    fn max(self, other: Self) -> Self
    where
        Self: Sized,
    {
        if other > self { other } else { self }
    }

    fn min(self, other: Self) -> Self
    where
        Self: Sized,
    {
        if other < self { other } else { self }
    }

    fn clamp(self, min: Self, max: Self) -> Self
    where
        Self: Sized,
    {
        assert!(min <= max);
        if self < min {
            min
        } else if self > max {
            max
        } else {
            self
        }
    }
}

impl Version {
    pub fn new(major: i32, minor: i32, patch: i32) -> Self {
        Version(major, minor, patch)
    }

    pub fn current() -> anyhow::Result<Self> {
        let v = Version::from_str(crate::embed::get_app_version());
        warn!("Current version: {:?}", v);
        v
    }
}