xref: /DADK/dadk-config/src/rootfs/utils/size.rs (revision c6f35e8aa5fda2a3004763828fb91c7762df6087)
11ad837a4SLoGin use serde::Deserializer;
21ad837a4SLoGin 
3*c6f35e8aSLoGin use crate::rootfs::RootFSConfigFile;
4*c6f35e8aSLoGin 
51ad837a4SLoGin /// 自定义反序列化函数,用于解析表示磁盘镜像大小的值。
61ad837a4SLoGin ///
71ad837a4SLoGin /// 此函数支持两种输入格式:
81ad837a4SLoGin /// 1. 纯数字:直接将其视为字节数。
91ad837a4SLoGin /// 2. 带单位的字符串:如"1M"、"1G",其中单位支持K(千字节)、M(兆字节)、G(千兆字节)。
101ad837a4SLoGin ///
111ad837a4SLoGin /// 函数将输入值解析为`usize`类型,表示字节数。
121ad837a4SLoGin ///
131ad837a4SLoGin /// # 参数
141ad837a4SLoGin /// - `deserializer`: 一个实现了`Deserializer` trait的对象,用于读取和解析输入数据。
151ad837a4SLoGin ///
161ad837a4SLoGin /// # 返回值
171ad837a4SLoGin /// 返回一个`Result<usize, D::Error>`,其中:
181ad837a4SLoGin /// - `Ok(usize)`表示解析成功,返回对应的字节数。
191ad837a4SLoGin /// - `Err(D::Error)`表示解析失败,返回错误信息。
201ad837a4SLoGin ///
211ad837a4SLoGin /// # 错误处理
deserialize_size<'de, D>(deserializer: D) -> Result<usize, D::Error> where D: Deserializer<'de>,221ad837a4SLoGin /// - 如果输入是非法的字符串(无法解析或单位不合法),将返回自定义错误。
231ad837a4SLoGin /// - 如果输入类型既不是整数也不是字符串,将返回类型错误。
241ad837a4SLoGin pub fn deserialize_size<'de, D>(deserializer: D) -> Result<usize, D::Error>
251ad837a4SLoGin where
261ad837a4SLoGin     D: Deserializer<'de>,
271ad837a4SLoGin {
281ad837a4SLoGin     // 使用serde的deserialize_any方法来处理不同类型的输入
291ad837a4SLoGin     let value = serde::de::Deserialize::deserialize(deserializer)?;
301ad837a4SLoGin 
311ad837a4SLoGin     // 匹配输入值的类型,进行相应的转换
32*c6f35e8aSLoGin     let r = match value {
331ad837a4SLoGin         toml::Value::Integer(num) => {
341ad837a4SLoGin             // 如果是整数类型,直接转换成usize
351ad837a4SLoGin             Ok(num as usize)
361ad837a4SLoGin         }
371ad837a4SLoGin         toml::Value::String(s) => {
381ad837a4SLoGin             // 如果是字符串类型,解析如"1M"这样的表示
391ad837a4SLoGin             parse_size_from_string(&s)
401ad837a4SLoGin                 .ok_or_else(|| serde::de::Error::custom("Invalid string for size"))
411ad837a4SLoGin         }
421ad837a4SLoGin         _ => Err(serde::de::Error::custom("Invalid type for size")),
43*c6f35e8aSLoGin     };
44*c6f35e8aSLoGin 
45*c6f35e8aSLoGin     r.map(|size| (size + RootFSConfigFile::LBA_SIZE - 1) & !(RootFSConfigFile::LBA_SIZE - 1))
461ad837a4SLoGin }
471ad837a4SLoGin 
481ad837a4SLoGin /// Parses a size string with optional unit suffix (K, M, G) into a usize value.
491ad837a4SLoGin ///
501ad837a4SLoGin /// This function takes a string that represents a size, which can be a plain
511ad837a4SLoGin /// number or a number followed by a unit suffix (K for kilobytes, M for megabytes,
521ad837a4SLoGin /// G for gigabytes). It converts this string into an equivalent usize value in bytes.
531ad837a4SLoGin ///
541ad837a4SLoGin /// # Parameters
551ad837a4SLoGin /// - `size_str`: A string slice that contains the size to parse. This can be a simple
561ad837a4SLoGin ///   numeric string or a numeric string followed by a unit ('K', 'M', 'G').
571ad837a4SLoGin ///
parse_size_from_string(size_str: &str) -> Option<usize>581ad837a4SLoGin /// # Returns
591ad837a4SLoGin /// An `Option<usize>` where:
601ad837a4SLoGin /// - `Some(usize)` contains the parsed size in bytes if the input string is valid.
611ad837a4SLoGin /// - `None` if the input string is invalid or contains an unsupported unit.
621ad837a4SLoGin fn parse_size_from_string(size_str: &str) -> Option<usize> {
631ad837a4SLoGin     if size_str.chars().all(|c| c.is_ascii_digit()) {
641ad837a4SLoGin         // 如果整个字符串都是数字,直接解析返回
651ad837a4SLoGin         return size_str.parse::<usize>().ok();
661ad837a4SLoGin     }
671ad837a4SLoGin 
681ad837a4SLoGin     let mut chars = size_str.chars().rev();
691ad837a4SLoGin     let unit = chars.next()?;
701ad837a4SLoGin     let number_str: String = chars.rev().collect();
711ad837a4SLoGin     let number = number_str.parse::<usize>().ok()?;
721ad837a4SLoGin 
731ad837a4SLoGin     match unit.to_ascii_uppercase() {
741ad837a4SLoGin         'K' => Some(number * 1024),
751ad837a4SLoGin         'M' => Some(number * 1024 * 1024),
761ad837a4SLoGin         'G' => Some(number * 1024 * 1024 * 1024),
771ad837a4SLoGin         _ => None,
781ad837a4SLoGin     }
791ad837a4SLoGin }
801ad837a4SLoGin 
811ad837a4SLoGin #[cfg(test)]
test_parse_size_from_string()821ad837a4SLoGin mod tests {
831ad837a4SLoGin     use super::*;
841ad837a4SLoGin 
851ad837a4SLoGin     #[test]
861ad837a4SLoGin     fn test_parse_size_from_string() {
871ad837a4SLoGin         // 正常情况,不带单位
881ad837a4SLoGin         assert_eq!(parse_size_from_string("1024"), Some(1024));
891ad837a4SLoGin 
901ad837a4SLoGin         // 正常情况,带有单位
911ad837a4SLoGin         assert_eq!(parse_size_from_string("1K"), Some(1024));
921ad837a4SLoGin         assert_eq!(parse_size_from_string("2M"), Some(2 * 1024 * 1024));
931ad837a4SLoGin         assert_eq!(parse_size_from_string("3G"), Some(3 * 1024 * 1024 * 1024));
941ad837a4SLoGin 
951ad837a4SLoGin         // 边界情况
961ad837a4SLoGin         assert_eq!(parse_size_from_string("0K"), Some(0));
971ad837a4SLoGin         assert_eq!(parse_size_from_string("0M"), Some(0));
981ad837a4SLoGin         assert_eq!(parse_size_from_string("0G"), Some(0));
991ad837a4SLoGin 
1001ad837a4SLoGin         // 小写情况
1011ad837a4SLoGin         assert_eq!(parse_size_from_string("1k"), Some(1024));
1021ad837a4SLoGin         assert_eq!(parse_size_from_string("2m"), Some(2 * 1024 * 1024));
1031ad837a4SLoGin         assert_eq!(parse_size_from_string("3g"), Some(3 * 1024 * 1024 * 1024));
1041ad837a4SLoGin 
1051ad837a4SLoGin         // 错误的单位
1061ad837a4SLoGin         assert_eq!(parse_size_from_string("1T"), None);
1071ad837a4SLoGin         assert_eq!(parse_size_from_string("2X"), None);
1081ad837a4SLoGin 
1091ad837a4SLoGin         // 错误的数字格式
1101ad837a4SLoGin         assert_eq!(parse_size_from_string("aK"), None);
1111ad837a4SLoGin         assert_eq!(parse_size_from_string("1.5M"), None);
1121ad837a4SLoGin 
1131ad837a4SLoGin         // 空字符串
1141ad837a4SLoGin         assert_eq!(parse_size_from_string(""), None);
1151ad837a4SLoGin 
1161ad837a4SLoGin         // 只单位没有数字
1171ad837a4SLoGin         assert_eq!(parse_size_from_string("K"), None);
1181ad837a4SLoGin 
1191ad837a4SLoGin         // 数字后有多余字符
1201ad837a4SLoGin         assert_eq!(parse_size_from_string("1KextrK"), None);
1211ad837a4SLoGin     }
1221ad837a4SLoGin }
123