size.rs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. use serde::Deserializer;
  2. use crate::rootfs::RootFSConfigFile;
  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. let r = match value {
  30. toml::Value::Integer(num) => {
  31. // 如果是整数类型,直接转换成usize
  32. Ok(num as usize)
  33. }
  34. toml::Value::String(s) => {
  35. // 如果是字符串类型,解析如"1M"这样的表示
  36. parse_size_from_string(&s)
  37. .ok_or_else(|| serde::de::Error::custom("Invalid string for size"))
  38. }
  39. _ => Err(serde::de::Error::custom("Invalid type for size")),
  40. };
  41. r.map(|size| (size + RootFSConfigFile::LBA_SIZE - 1) & !(RootFSConfigFile::LBA_SIZE - 1))
  42. }
  43. /// Parses a size string with optional unit suffix (K, M, G) into a usize value.
  44. ///
  45. /// This function takes a string that represents a size, which can be a plain
  46. /// number or a number followed by a unit suffix (K for kilobytes, M for megabytes,
  47. /// G for gigabytes). It converts this string into an equivalent usize value in bytes.
  48. ///
  49. /// # Parameters
  50. /// - `size_str`: A string slice that contains the size to parse. This can be a simple
  51. /// numeric string or a numeric string followed by a unit ('K', 'M', 'G').
  52. ///
  53. /// # Returns
  54. /// An `Option<usize>` where:
  55. /// - `Some(usize)` contains the parsed size in bytes if the input string is valid.
  56. /// - `None` if the input string is invalid or contains an unsupported unit.
  57. fn parse_size_from_string(size_str: &str) -> Option<usize> {
  58. if size_str.chars().all(|c| c.is_ascii_digit()) {
  59. // 如果整个字符串都是数字,直接解析返回
  60. return size_str.parse::<usize>().ok();
  61. }
  62. let mut chars = size_str.chars().rev();
  63. let unit = chars.next()?;
  64. let number_str: String = chars.rev().collect();
  65. let number = number_str.parse::<usize>().ok()?;
  66. match unit.to_ascii_uppercase() {
  67. 'K' => Some(number * 1024),
  68. 'M' => Some(number * 1024 * 1024),
  69. 'G' => Some(number * 1024 * 1024 * 1024),
  70. _ => None,
  71. }
  72. }
  73. #[cfg(test)]
  74. mod tests {
  75. use super::*;
  76. #[test]
  77. fn test_parse_size_from_string() {
  78. // 正常情况,不带单位
  79. assert_eq!(parse_size_from_string("1024"), Some(1024));
  80. // 正常情况,带有单位
  81. assert_eq!(parse_size_from_string("1K"), Some(1024));
  82. assert_eq!(parse_size_from_string("2M"), Some(2 * 1024 * 1024));
  83. assert_eq!(parse_size_from_string("3G"), Some(3 * 1024 * 1024 * 1024));
  84. // 边界情况
  85. assert_eq!(parse_size_from_string("0K"), Some(0));
  86. assert_eq!(parse_size_from_string("0M"), Some(0));
  87. assert_eq!(parse_size_from_string("0G"), Some(0));
  88. // 小写情况
  89. assert_eq!(parse_size_from_string("1k"), Some(1024));
  90. assert_eq!(parse_size_from_string("2m"), Some(2 * 1024 * 1024));
  91. assert_eq!(parse_size_from_string("3g"), Some(3 * 1024 * 1024 * 1024));
  92. // 错误的单位
  93. assert_eq!(parse_size_from_string("1T"), None);
  94. assert_eq!(parse_size_from_string("2X"), None);
  95. // 错误的数字格式
  96. assert_eq!(parse_size_from_string("aK"), None);
  97. assert_eq!(parse_size_from_string("1.5M"), None);
  98. // 空字符串
  99. assert_eq!(parse_size_from_string(""), None);
  100. // 只单位没有数字
  101. assert_eq!(parse_size_from_string("K"), None);
  102. // 数字后有多余字符
  103. assert_eq!(parse_size_from_string("1KextrK"), None);
  104. }
  105. }