@@ -181,7 +181,6 @@ impl HugeTlbController {
181181}
182182
183183pub const HUGEPAGESIZE_DIR : & str = "/sys/kernel/mm/hugepages" ;
184- use regex:: Regex ;
185184use std:: collections:: HashMap ;
186185use std:: fs;
187186
@@ -263,37 +262,46 @@ pub fn get_decimal_abbrs() -> Vec<String> {
263262}
264263
265264fn parse_size ( s : & str , m : & HashMap < String , u128 > ) -> Result < u128 > {
266- let re = Regex :: new ( r"(?P<num>\d+)(?P<mul>[kKmMgGtTpP]?)[bB]?$" ) ;
265+ // Remove leading/trailing whitespace.
266+ let s = s. trim ( ) ;
267267
268- if re. is_err ( ) {
268+ // Remove an optional trailing 'b' or 'B'
269+ let s = if let Some ( stripped) = s. strip_suffix ( 'b' ) . or_else ( || s. strip_suffix ( 'B' ) ) {
270+ stripped
271+ } else {
272+ s
273+ } ;
274+
275+ // Ensure that the string is not empty after stripping.
276+ if s. is_empty ( ) {
269277 return Err ( Error :: new ( InvalidBytesSize ) ) ;
270278 }
271- let caps = re. unwrap ( ) . captures ( s) . unwrap ( ) ;
272279
273- let num = caps. name ( "num" ) ;
274- let size: u128 = if let Some ( num) = num {
275- let n = num. as_str ( ) . trim ( ) . parse :: < u128 > ( ) ;
276- if n. is_err ( ) {
277- return Err ( Error :: new ( InvalidBytesSize ) ) ;
278- }
279- n. unwrap ( )
280- } else {
280+ // The last character should be the multiplier letter.
281+ let last_char = s. chars ( ) . last ( ) . unwrap ( ) ;
282+ if !"kKmMgGtTpP" . contains ( last_char) {
281283 return Err ( Error :: new ( InvalidBytesSize ) ) ;
282- } ;
284+ }
283285
284- let q = caps. name ( "mul" ) ;
285- let mul: u128 = if let Some ( q) = q {
286- let t = m. get ( q. as_str ( ) ) ;
287- if let Some ( t) = t {
288- * t
289- } else {
290- return Err ( Error :: new ( InvalidBytesSize ) ) ;
291- }
292- } else {
286+ // The numeric part is everything before the multiplier letter.
287+ let num_part = & s[ ..s. len ( ) - last_char. len_utf8 ( ) ] ;
288+ if num_part. trim ( ) . is_empty ( ) {
293289 return Err ( Error :: new ( InvalidBytesSize ) ) ;
294- } ;
290+ }
291+
292+ // Parse the numeric part into a u128.
293+ let number: u128 = num_part
294+ . trim ( )
295+ . parse ( )
296+ . map_err ( |_| Error :: new ( InvalidBytesSize ) ) ?;
295297
296- Ok ( size * mul)
298+ // Look up the multiplier in the provided HashMap.
299+ let multiplier_key = last_char. to_string ( ) ;
300+ let multiplier = m
301+ . get ( & multiplier_key)
302+ . ok_or_else ( || Error :: new ( InvalidBytesSize ) ) ?;
303+
304+ Ok ( number * multiplier)
297305}
298306
299307fn custom_size ( mut size : f64 , base : f64 , m : & [ String ] ) -> String {
@@ -305,3 +313,60 @@ fn custom_size(mut size: f64, base: f64, m: &[String]) -> String {
305313
306314 format ! ( "{}{}" , size, m[ i] . as_str( ) )
307315}
316+
317+ #[ cfg( test) ]
318+ mod tests {
319+ use super :: * ;
320+
321+ #[ test]
322+ fn test_binary_size_valid ( ) {
323+ let m = get_binary_size_map ( ) ;
324+ // Valid inputs must include a multiplier letter.
325+ assert_eq ! ( parse_size( "1k" , & m) . unwrap( ) , KiB ) ;
326+ assert_eq ! ( parse_size( "2m" , & m) . unwrap( ) , 2 * MiB ) ;
327+ assert_eq ! ( parse_size( "3g" , & m) . unwrap( ) , 3 * GiB ) ;
328+ assert_eq ! ( parse_size( "4t" , & m) . unwrap( ) , 4 * TiB ) ;
329+ assert_eq ! ( parse_size( "5p" , & m) . unwrap( ) , 5 * PiB ) ;
330+ }
331+
332+ #[ test]
333+ fn test_decimal_size_valid ( ) {
334+ let m = get_decimal_size_map ( ) ;
335+ assert_eq ! ( parse_size( "1k" , & m) . unwrap( ) , KB ) ;
336+ assert_eq ! ( parse_size( "2m" , & m) . unwrap( ) , 2 * MB ) ;
337+ assert_eq ! ( parse_size( "3g" , & m) . unwrap( ) , 3 * GB ) ;
338+ assert_eq ! ( parse_size( "4t" , & m) . unwrap( ) , 4 * TB ) ;
339+ assert_eq ! ( parse_size( "5p" , & m) . unwrap( ) , 5 * PB ) ;
340+ }
341+
342+ #[ test]
343+ fn test_trailing_b_suffix ( ) {
344+ let m = get_binary_size_map ( ) ;
345+ // Trailing 'b' or 'B' should be accepted.
346+ assert_eq ! ( parse_size( "1kb" , & m) . unwrap( ) , KiB ) ;
347+ assert_eq ! ( parse_size( "2mB" , & m) . unwrap( ) , 2 * MiB ) ;
348+ }
349+
350+ #[ test]
351+ fn test_invalid_inputs ( ) {
352+ let m = get_binary_size_map ( ) ;
353+ // Missing multiplier letter results in error.
354+ assert ! ( parse_size( "1" , & m) . is_err( ) ) ;
355+ // Invalid multiplier letter.
356+ assert ! ( parse_size( "10x" , & m) . is_err( ) ) ;
357+ // Non-numeric input.
358+ assert ! ( parse_size( "abc" , & m) . is_err( ) ) ;
359+ // Only multiplier letter with no number.
360+ assert ! ( parse_size( "k" , & m) . is_err( ) ) ;
361+ // Number with an invalid trailing character.
362+ assert ! ( parse_size( "123z" , & m) . is_err( ) ) ;
363+ }
364+
365+ #[ test]
366+ fn test_uppercase_multiplier_fails ( ) {
367+ let m = get_binary_size_map ( ) ;
368+ // Although the regex matches uppercase letters, the provided map only contains lowercase keys.
369+ // Therefore, "1K" does not match any key and should produce an error.
370+ assert ! ( parse_size( "1K" , & m) . is_err( ) ) ;
371+ }
372+ }
0 commit comments