Skip to content

Commit 5b1b1e1

Browse files
committed
libvirt: Deduplicate unit conversion logic
Clean up duplication. Assisted-by: Claude Code (Sonnet 4.5) Signed-off-by: Colin Walters <walters@verbum.org>
1 parent 164b990 commit 5b1b1e1

2 files changed

Lines changed: 46 additions & 28 deletions

File tree

crates/kit/src/libvirt/list_volumes.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -354,14 +354,7 @@ fn parse_virsh_size(size_str: &str) -> Option<u64> {
354354
let number: f64 = parts[0].parse().ok()?;
355355
let unit = parts[1];
356356

357-
let multiplier = match unit {
358-
"B" | "bytes" => 1,
359-
"KiB" | "KB" => 1024,
360-
"MiB" | "MB" => 1024 * 1024,
361-
"GiB" | "GB" => 1024 * 1024 * 1024,
362-
"TiB" | "TB" => 1024u64.pow(4),
363-
_ => return None,
364-
};
357+
let multiplier = super::unit_to_bytes(unit)?;
365358

366359
Some((number * multiplier as f64) as u64)
367360
}

crates/kit/src/libvirt/mod.rs

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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
6790
pub(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)
94119
pub(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

Comments
 (0)