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 }