Skip to content

Commit c1504d8

Browse files
committed
Move memory conversion helpers to libvirt module
The module structure was twisted and this caused dead_code they belong, as these are libvirt-specific helpers for parsing libvirt domain XML memory specifications, not generic XML utilities. Assisted-by: Claude Code Signed-off-by: Colin Walters <walters@verbum.org>
1 parent 897915f commit c1504d8

5 files changed

Lines changed: 98 additions & 95 deletions

File tree

crates/kit/src/domain_list.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,9 @@ impl DomainLister {
199199
.unwrap_or_default();
200200

201201
// Extract memory and vcpu from domain XML
202-
let memory_mb = dom.find("memory").and_then(|node| node.parse_memory_mb());
202+
let memory_mb = dom
203+
.find("memory")
204+
.and_then(|node| crate::libvirt::parse_memory_mb(node));
203205

204206
let vcpus = dom
205207
.find("vcpu")

crates/kit/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
//! bcvk library - exposes internal modules for testing
22
33
pub mod qemu_img;
4-
pub mod utils;
54
pub mod xml_utils;

crates/kit/src/libvirt/mod.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,101 @@ impl LibvirtOptions {
6161
}
6262
}
6363

64+
/// Convert memory value with unit to megabytes (MiB)
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 convert_memory_to_mb(value: u32, unit: &str) -> Option<u32> {
68+
// Use u128 for calculations to prevent overflow with large units like TB
69+
let value_u128 = value as u128;
70+
let mib_u128 = 1024 * 1024;
71+
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+
};
89+
u32::try_from(mb).ok()
90+
}
91+
92+
/// Parse memory value from a libvirt XML node with unit attribute
93+
/// Returns the value in megabytes (MiB)
94+
pub(crate) fn parse_memory_mb(node: &crate::xml_utils::XmlNode) -> Option<u32> {
95+
let value = node.text_content().parse::<u32>().ok()?;
96+
// Convert to MB based on unit attribute (default is KiB per libvirt spec)
97+
let unit = node
98+
.attributes
99+
.get("unit")
100+
.map(|s| s.as_str())
101+
.unwrap_or("KiB");
102+
convert_memory_to_mb(value, unit)
103+
}
104+
105+
#[cfg(test)]
106+
mod tests {
107+
use super::*;
108+
109+
#[test]
110+
fn test_convert_memory_to_mb() {
111+
// Test binary units (powers of 1024)
112+
assert_eq!(convert_memory_to_mb(4194304, "KiB"), Some(4096));
113+
assert_eq!(convert_memory_to_mb(2097152, "KiB"), Some(2048));
114+
assert_eq!(convert_memory_to_mb(2048, "MiB"), Some(2048));
115+
assert_eq!(convert_memory_to_mb(4096, "MiB"), Some(4096));
116+
assert_eq!(convert_memory_to_mb(4, "GiB"), Some(4096));
117+
assert_eq!(convert_memory_to_mb(2, "GiB"), Some(2048));
118+
119+
// Test short forms (binary)
120+
assert_eq!(convert_memory_to_mb(4, "G"), Some(4096));
121+
assert_eq!(convert_memory_to_mb(2048, "M"), Some(2048));
122+
assert_eq!(convert_memory_to_mb(2097152, "K"), Some(2048));
123+
124+
// Test decimal units (powers of 1000)
125+
assert_eq!(convert_memory_to_mb(1048576, "KB"), Some(1000));
126+
assert_eq!(convert_memory_to_mb(1024, "MB"), Some(976));
127+
assert_eq!(convert_memory_to_mb(4, "GB"), Some(3814));
128+
129+
// Test default/unknown unit (defaults to KiB)
130+
assert_eq!(convert_memory_to_mb(4194304, "unknown"), Some(4096));
131+
}
132+
133+
#[test]
134+
fn test_parse_memory_mb() {
135+
use crate::xml_utils::parse_xml_dom;
136+
137+
// Test KiB (default unit)
138+
let xml = r#"<memory>4194304</memory>"#;
139+
let dom = parse_xml_dom(xml).unwrap();
140+
assert_eq!(parse_memory_mb(&dom), Some(4096));
141+
142+
// Test MiB
143+
let xml = r#"<memory unit='MiB'>2048</memory>"#;
144+
let dom = parse_xml_dom(xml).unwrap();
145+
assert_eq!(parse_memory_mb(&dom), Some(2048));
146+
147+
// Test GiB
148+
let xml = r#"<memory unit='GiB'>4</memory>"#;
149+
let dom = parse_xml_dom(xml).unwrap();
150+
assert_eq!(parse_memory_mb(&dom), Some(4096));
151+
152+
// Test KB (decimal unit: 1000-based)
153+
let xml = r#"<memory unit='KB'>1048576</memory>"#;
154+
let dom = parse_xml_dom(xml).unwrap();
155+
assert_eq!(parse_memory_mb(&dom), Some(1000));
156+
}
157+
}
158+
64159
/// libvirt subcommands for managing bootc disk images and domains
65160
#[derive(Debug, Subcommand)]
66161
pub enum LibvirtSubcommands {

crates/kit/src/utils.rs

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -173,60 +173,3 @@ pub(crate) fn parse_memory_to_mb(memory_str: &str) -> Result<u32> {
173173
Err(eyre!("Memory specification cannot be empty - please provide a value like '2G', '1024M', or '512'"))
174174
}
175175
}
176-
177-
/// Convert memory value with unit to megabytes (MiB)
178-
/// Handles libvirt-style units distinguishing between decimal (KB, MB, GB - powers of 1000)
179-
/// and binary (KiB, MiB, GiB - powers of 1024) units per libvirt specification
180-
pub(crate) fn convert_memory_to_mb(value: u32, unit: &str) -> u32 {
181-
// Use u128 for calculations to prevent overflow with large units like TB
182-
let value_u128 = value as u128;
183-
let mib_u128 = 1024 * 1024;
184-
185-
let mb = match unit {
186-
// Binary prefixes (powers of 1024), converting to MiB
187-
"k" | "K" | "KiB" => value_u128 / 1024,
188-
"M" | "MiB" => value_u128,
189-
"G" | "GiB" => value_u128 * 1024,
190-
"T" | "TiB" => value_u128 * 1024 * 1024,
191-
192-
// Decimal prefixes (powers of 1000), converting to MiB
193-
"B" | "bytes" => value_u128 / mib_u128,
194-
"KB" => (value_u128 * 1_000) / mib_u128,
195-
"MB" => (value_u128 * 1_000_000) / mib_u128,
196-
"GB" => (value_u128 * 1_000_000_000) / mib_u128,
197-
"TB" => (value_u128 * 1_000_000_000_000) / mib_u128,
198-
199-
// Libvirt default is KiB for memory
200-
_ => value_u128 / 1024,
201-
};
202-
mb as u32
203-
}
204-
205-
#[cfg(test)]
206-
mod tests {
207-
use super::*;
208-
209-
#[test]
210-
fn test_convert_memory_to_mb() {
211-
// Test binary units (powers of 1024)
212-
assert_eq!(convert_memory_to_mb(4194304, "KiB"), 4096);
213-
assert_eq!(convert_memory_to_mb(2097152, "KiB"), 2048);
214-
assert_eq!(convert_memory_to_mb(2048, "MiB"), 2048);
215-
assert_eq!(convert_memory_to_mb(4096, "MiB"), 4096);
216-
assert_eq!(convert_memory_to_mb(4, "GiB"), 4096);
217-
assert_eq!(convert_memory_to_mb(2, "GiB"), 2048);
218-
219-
// Test short forms (binary)
220-
assert_eq!(convert_memory_to_mb(4, "G"), 4096);
221-
assert_eq!(convert_memory_to_mb(2048, "M"), 2048);
222-
assert_eq!(convert_memory_to_mb(2097152, "K"), 2048);
223-
224-
// Test decimal units (powers of 1000)
225-
assert_eq!(convert_memory_to_mb(1048576, "KB"), 1000);
226-
assert_eq!(convert_memory_to_mb(1024, "MB"), 976);
227-
assert_eq!(convert_memory_to_mb(4, "GB"), 3814);
228-
229-
// Test default/unknown unit (defaults to KiB)
230-
assert_eq!(convert_memory_to_mb(4194304, "unknown"), 4096);
231-
}
232-
}

crates/kit/src/xml_utils.rs

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -140,19 +140,6 @@ impl XmlNode {
140140
pub fn text_content(&self) -> &str {
141141
&self.text
142142
}
143-
144-
/// Parse memory value from an XML node with unit attribute
145-
/// Returns the value in megabytes (MB)
146-
pub fn parse_memory_mb(&self) -> Option<u32> {
147-
let value = self.text_content().parse::<u32>().ok()?;
148-
// Convert to MB based on unit attribute (default is KiB per libvirt spec)
149-
let unit = self
150-
.attributes
151-
.get("unit")
152-
.map(|s| s.as_str())
153-
.unwrap_or("KiB");
154-
Some(crate::utils::convert_memory_to_mb(value, unit))
155-
}
156143
}
157144

158145
/// Parse XML string into a simple DOM structure
@@ -383,27 +370,4 @@ mod tests {
383370
assert!(xml.contains("<custom>raw content</custom>"));
384371
assert!(xml.contains("</root>"));
385372
}
386-
387-
#[test]
388-
fn test_parse_memory_mb() {
389-
// Test KiB (default unit)
390-
let xml = r#"<memory>4194304</memory>"#;
391-
let dom = parse_xml_dom(xml).unwrap();
392-
assert_eq!(dom.parse_memory_mb(), Some(4096));
393-
394-
// Test MiB
395-
let xml = r#"<memory unit='MiB'>2048</memory>"#;
396-
let dom = parse_xml_dom(xml).unwrap();
397-
assert_eq!(dom.parse_memory_mb(), Some(2048));
398-
399-
// Test GiB
400-
let xml = r#"<memory unit='GiB'>4</memory>"#;
401-
let dom = parse_xml_dom(xml).unwrap();
402-
assert_eq!(dom.parse_memory_mb(), Some(4096));
403-
404-
// Test KB (decimal unit: 1000-based)
405-
let xml = r#"<memory unit='KB'>1048576</memory>"#;
406-
let dom = parse_xml_dom(xml).unwrap();
407-
assert_eq!(dom.parse_memory_mb(), Some(1000));
408-
}
409373
}

0 commit comments

Comments
 (0)