@@ -61,34 +61,59 @@ impl LibvirtOptions {
6161 }
6262}
6363
64+ /// Convert a unit string to bytes multiplier
65+ /// Handles libvirt-style units distinguishing between decimal (KB, MB, GB - powers of 1000)
66+ /// and binary (KiB, MiB, GiB - powers of 1024) units per libvirt specification
67+ pub ( crate ) fn unit_to_bytes ( unit : & str ) -> Option < u128 > {
68+ match unit {
69+ // Binary prefixes (powers of 1024)
70+ "B" | "bytes" => Some ( 1 ) ,
71+ "k" | "K" | "KiB" => Some ( 1024 ) ,
72+ "M" | "MiB" => Some ( 1024u128 . pow ( 2 ) ) ,
73+ "G" | "GiB" => Some ( 1024u128 . pow ( 3 ) ) ,
74+ "T" | "TiB" => Some ( 1024u128 . pow ( 4 ) ) ,
75+
76+ // Decimal prefixes (powers of 1000)
77+ "KB" => Some ( 1_000 ) ,
78+ "MB" => Some ( 1_000u128 . pow ( 2 ) ) ,
79+ "GB" => Some ( 1_000u128 . pow ( 3 ) ) ,
80+ "TB" => Some ( 1_000u128 . pow ( 4 ) ) ,
81+
82+ _ => None ,
83+ }
84+ }
85+
6486/// Convert memory value with unit to megabytes (MiB)
6587/// Handles libvirt-style units distinguishing between decimal (KB, MB, GB - powers of 1000)
6688/// and binary (KiB, MiB, GiB - powers of 1024) units per libvirt specification
89+ /// Returns None if the unit is unknown or if the result overflows u32
6790pub ( crate ) fn convert_memory_to_mb ( value : u32 , unit : & str ) -> Option < u32 > {
68- // Use u128 for calculations to prevent overflow with large units like TB
6991 let value_u128 = value as u128 ;
7092 let mib_u128 = 1024 * 1024 ;
7193
72- let mb = match unit {
73- // Binary prefixes (powers of 1024), converting to MiB
74- "k" | "K" | "KiB" => value_u128 / 1024 ,
75- "M" | "MiB" => value_u128,
76- "G" | "GiB" => value_u128 * 1024 ,
77- "T" | "TiB" => value_u128 * 1024 * 1024 ,
78-
79- // Decimal prefixes (powers of 1000), converting to MiB
80- "B" | "bytes" => value_u128 / mib_u128,
81- "KB" => ( value_u128 * 1_000u128 . pow ( 1 ) ) / mib_u128,
82- "MB" => ( value_u128 * 1_000u128 . pow ( 2 ) ) / mib_u128,
83- "GB" => ( value_u128 * 1_000u128 . pow ( 3 ) ) / mib_u128,
84- "TB" => ( value_u128 * 1_000u128 . pow ( 4 ) ) / mib_u128,
85-
86- // Libvirt default is KiB for memory
87- _ => value_u128 / 1024 ,
88- } ;
94+ // Convert to bytes first, then to MiB
95+ let bytes = value_u128 * unit_to_bytes ( unit) ?;
96+ let mb = bytes / mib_u128;
97+
8998 u32:: try_from ( mb) . ok ( )
9099}
91100
101+ /// Convert memory value with unit to megabytes (MiB), returning u64
102+ /// Handles libvirt-style units distinguishing between decimal (KB, MB, GB - powers of 1000)
103+ /// and binary (KiB, MiB, GiB - powers of 1024) units per libvirt specification
104+ /// Returns None if the unit is unknown or if the result overflows u64
105+ #[ allow( dead_code) ]
106+ pub ( crate ) fn convert_to_mb_u64 ( value : u64 , unit : & str ) -> Option < u64 > {
107+ let value_u128 = value as u128 ;
108+ let mib_u128 = 1024 * 1024 ;
109+
110+ // Convert to bytes first, then to MiB
111+ let bytes = value_u128 * unit_to_bytes ( unit) ?;
112+ let mb = bytes / mib_u128;
113+
114+ u64:: try_from ( mb) . ok ( )
115+ }
116+
92117/// Parse memory value from a libvirt XML node with unit attribute
93118/// Returns the value in megabytes (MiB)
94119pub ( crate ) fn parse_memory_mb ( node : & crate :: xml_utils:: XmlNode ) -> Option < u32 > {
@@ -126,8 +151,8 @@ mod tests {
126151 assert_eq ! ( convert_memory_to_mb( 1024 , "MB" ) , Some ( 976 ) ) ;
127152 assert_eq ! ( convert_memory_to_mb( 4 , "GB" ) , Some ( 3814 ) ) ;
128153
129- // Test default/ unknown unit (defaults to KiB)
130- assert_eq ! ( convert_memory_to_mb( 4194304 , "unknown" ) , Some ( 4096 ) ) ;
154+ // Test unknown unit returns None
155+ assert_eq ! ( convert_memory_to_mb( 4194304 , "unknown" ) , None ) ;
131156 }
132157
133158 #[ test]
0 commit comments