lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

version.rs (3500B)


      1 use crate::error::RadrootsSimplexChatProtoError;
      2 use alloc::string::{String, ToString};
      3 use core::fmt;
      4 use core::str::FromStr;
      5 
      6 pub const RADROOTS_SIMPLEX_CHAT_INITIAL_VERSION: u16 = 1;
      7 pub const RADROOTS_SIMPLEX_CHAT_COMPRESSION_VERSION: u16 = 8;
      8 pub const RADROOTS_SIMPLEX_CHAT_CURRENT_VERSION: u16 = 16;
      9 
     10 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
     11 pub struct RadrootsSimplexChatVersionRange {
     12     pub min: u16,
     13     pub max: u16,
     14 }
     15 
     16 impl RadrootsSimplexChatVersionRange {
     17     pub const fn single(version: u16) -> Self {
     18         Self {
     19             min: version,
     20             max: version,
     21         }
     22     }
     23 
     24     pub fn new(min: u16, max: u16) -> Result<Self, RadrootsSimplexChatProtoError> {
     25         if min == 0 || max == 0 || min > max {
     26             return Err(RadrootsSimplexChatProtoError::InvalidVersionRange(
     27                 alloc::format!("{min}-{max}"),
     28             ));
     29         }
     30 
     31         Ok(Self { min, max })
     32     }
     33 
     34     pub const fn supports_compression(&self) -> bool {
     35         self.max >= RADROOTS_SIMPLEX_CHAT_COMPRESSION_VERSION
     36     }
     37 }
     38 
     39 impl Default for RadrootsSimplexChatVersionRange {
     40     fn default() -> Self {
     41         Self::single(RADROOTS_SIMPLEX_CHAT_CURRENT_VERSION)
     42     }
     43 }
     44 
     45 impl fmt::Display for RadrootsSimplexChatVersionRange {
     46     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     47         if self.min == self.max {
     48             write!(f, "{}", self.min)
     49         } else {
     50             write!(f, "{}-{}", self.min, self.max)
     51         }
     52     }
     53 }
     54 
     55 impl FromStr for RadrootsSimplexChatVersionRange {
     56     type Err = RadrootsSimplexChatProtoError;
     57 
     58     fn from_str(value: &str) -> Result<Self, Self::Err> {
     59         let trimmed = value.trim();
     60         if trimmed.is_empty() {
     61             return Err(RadrootsSimplexChatProtoError::InvalidVersionRange(
     62                 String::new(),
     63             ));
     64         }
     65 
     66         if let Some((min, max)) = trimmed.split_once('-') {
     67             let min = parse_version(min, trimmed)?;
     68             let max = parse_version(max, trimmed)?;
     69             Self::new(min, max)
     70         } else {
     71             let version = parse_version(trimmed, trimmed)?;
     72             Self::new(version, version)
     73         }
     74     }
     75 }
     76 
     77 fn parse_version(value: &str, original: &str) -> Result<u16, RadrootsSimplexChatProtoError> {
     78     value
     79         .parse::<u16>()
     80         .map_err(|_| RadrootsSimplexChatProtoError::InvalidVersionRange(original.to_string()))
     81 }
     82 
     83 impl serde::Serialize for RadrootsSimplexChatVersionRange {
     84     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     85     where
     86         S: serde::Serializer,
     87     {
     88         serializer.serialize_str(&self.to_string())
     89     }
     90 }
     91 
     92 impl<'de> serde::Deserialize<'de> for RadrootsSimplexChatVersionRange {
     93     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     94     where
     95         D: serde::Deserializer<'de>,
     96     {
     97         let value = String::deserialize(deserializer)?;
     98         value.parse().map_err(serde::de::Error::custom)
     99     }
    100 }
    101 
    102 #[cfg(test)]
    103 mod tests {
    104     use super::*;
    105 
    106     #[test]
    107     fn parses_single_version() {
    108         let range = "8".parse::<RadrootsSimplexChatVersionRange>().unwrap();
    109         assert_eq!(range, RadrootsSimplexChatVersionRange::single(8));
    110         assert!(range.supports_compression());
    111     }
    112 
    113     #[test]
    114     fn parses_version_range() {
    115         let range = "1-16".parse::<RadrootsSimplexChatVersionRange>().unwrap();
    116         assert_eq!(range.min, 1);
    117         assert_eq!(range.max, 16);
    118         assert_eq!(range.to_string(), "1-16");
    119     }
    120 }