1 use serde::Deserializer; 2 3 /// 自定义反序列化函数,用于解析表示磁盘镜像大小的值。 4 /// 5 /// 此函数支持两种输入格式: 6 /// 1. 纯数字:直接将其视为字节数。 7 /// 2. 带单位的字符串:如"1M"、"1G",其中单位支持K(千字节)、M(兆字节)、G(千兆字节)。 8 /// 9 /// 函数将输入值解析为`usize`类型,表示字节数。 10 /// 11 /// # 参数 12 /// - `deserializer`: 一个实现了`Deserializer` trait的对象,用于读取和解析输入数据。 13 /// 14 /// # 返回值 15 /// 返回一个`Result<usize, D::Error>`,其中: 16 /// - `Ok(usize)`表示解析成功,返回对应的字节数。 17 /// - `Err(D::Error)`表示解析失败,返回错误信息。 18 /// 19 /// # 错误处理 20 /// - 如果输入是非法的字符串(无法解析或单位不合法),将返回自定义错误。 21 /// - 如果输入类型既不是整数也不是字符串,将返回类型错误。 22 pub fn deserialize_size<'de, D>(deserializer: D) -> Result<usize, D::Error> 23 where 24 D: Deserializer<'de>, 25 { 26 // 使用serde的deserialize_any方法来处理不同类型的输入 27 let value = serde::de::Deserialize::deserialize(deserializer)?; 28 29 // 匹配输入值的类型,进行相应的转换 30 match value { 31 toml::Value::Integer(num) => { 32 // 如果是整数类型,直接转换成usize 33 Ok(num as usize) 34 } 35 toml::Value::String(s) => { 36 // 如果是字符串类型,解析如"1M"这样的表示 37 parse_size_from_string(&s) 38 .ok_or_else(|| serde::de::Error::custom("Invalid string for size")) 39 } 40 _ => Err(serde::de::Error::custom("Invalid type for size")), 41 } 42 } 43 44 /// Parses a size string with optional unit suffix (K, M, G) into a usize value. 45 /// 46 /// This function takes a string that represents a size, which can be a plain 47 /// number or a number followed by a unit suffix (K for kilobytes, M for megabytes, 48 /// G for gigabytes). It converts this string into an equivalent usize value in bytes. 49 /// 50 /// # Parameters 51 /// - `size_str`: A string slice that contains the size to parse. This can be a simple 52 /// numeric string or a numeric string followed by a unit ('K', 'M', 'G'). 53 /// 54 /// # Returns 55 /// An `Option<usize>` where: 56 /// - `Some(usize)` contains the parsed size in bytes if the input string is valid. 57 /// - `None` if the input string is invalid or contains an unsupported unit. 58 fn parse_size_from_string(size_str: &str) -> Option<usize> { 59 if size_str.chars().all(|c| c.is_ascii_digit()) { 60 // 如果整个字符串都是数字,直接解析返回 61 return size_str.parse::<usize>().ok(); 62 } 63 64 let mut chars = size_str.chars().rev(); 65 let unit = chars.next()?; 66 let number_str: String = chars.rev().collect(); 67 let number = number_str.parse::<usize>().ok()?; 68 69 match unit.to_ascii_uppercase() { 70 'K' => Some(number * 1024), 71 'M' => Some(number * 1024 * 1024), 72 'G' => Some(number * 1024 * 1024 * 1024), 73 _ => None, 74 } 75 } 76 77 #[cfg(test)] 78 mod tests { 79 use super::*; 80 81 #[test] 82 fn test_parse_size_from_string() { 83 // 正常情况,不带单位 84 assert_eq!(parse_size_from_string("1024"), Some(1024)); 85 86 // 正常情况,带有单位 87 assert_eq!(parse_size_from_string("1K"), Some(1024)); 88 assert_eq!(parse_size_from_string("2M"), Some(2 * 1024 * 1024)); 89 assert_eq!(parse_size_from_string("3G"), Some(3 * 1024 * 1024 * 1024)); 90 91 // 边界情况 92 assert_eq!(parse_size_from_string("0K"), Some(0)); 93 assert_eq!(parse_size_from_string("0M"), Some(0)); 94 assert_eq!(parse_size_from_string("0G"), Some(0)); 95 96 // 小写情况 97 assert_eq!(parse_size_from_string("1k"), Some(1024)); 98 assert_eq!(parse_size_from_string("2m"), Some(2 * 1024 * 1024)); 99 assert_eq!(parse_size_from_string("3g"), Some(3 * 1024 * 1024 * 1024)); 100 101 // 错误的单位 102 assert_eq!(parse_size_from_string("1T"), None); 103 assert_eq!(parse_size_from_string("2X"), None); 104 105 // 错误的数字格式 106 assert_eq!(parse_size_from_string("aK"), None); 107 assert_eq!(parse_size_from_string("1.5M"), None); 108 109 // 空字符串 110 assert_eq!(parse_size_from_string(""), None); 111 112 // 只单位没有数字 113 assert_eq!(parse_size_from_string("K"), None); 114 115 // 数字后有多余字符 116 assert_eq!(parse_size_from_string("1KextrK"), None); 117 } 118 } 119