struct_audit/analysis/
padding.rs1use crate::types::{LayoutMetrics, PaddingHole, StructLayout};
2
3pub fn analyze_layout(layout: &mut StructLayout, cache_line_size: u32) {
4 let mut padding_holes = Vec::new();
5 let mut useful_size: u64 = 0;
6 let mut current_offset: u64 = 0;
7 let mut last_member_name: Option<String> = None;
8
9 for member in &layout.members {
10 let member_offset = match member.offset {
11 Some(o) => o,
12 None => continue,
13 };
14
15 let member_size = match member.size {
16 Some(s) => s,
17 None => {
18 last_member_name = Some(member.name.clone());
19 continue;
20 }
21 };
22
23 if member_offset > current_offset {
24 let gap_size = member_offset - current_offset;
25 padding_holes.push(PaddingHole {
26 offset: current_offset,
27 size: gap_size,
28 after_member: last_member_name.clone(),
29 });
30 }
31
32 useful_size += member_size;
33 current_offset = member_offset + member_size;
34 last_member_name = Some(member.name.clone());
35 }
36
37 if current_offset < layout.size {
38 let tail_padding = layout.size - current_offset;
39 padding_holes.push(PaddingHole {
40 offset: current_offset,
41 size: tail_padding,
42 after_member: last_member_name,
43 });
44 }
45
46 let padding_bytes: u64 = padding_holes.iter().map(|h| h.size).sum();
47 let padding_percentage =
48 if layout.size > 0 { (padding_bytes as f64 / layout.size as f64) * 100.0 } else { 0.0 };
49
50 let cache_line_size_u64 = cache_line_size as u64;
51 let cache_lines_spanned =
52 if layout.size > 0 { layout.size.div_ceil(cache_line_size_u64) as u32 } else { 0 };
53
54 let total_cache_bytes = cache_lines_spanned as u64 * cache_line_size_u64;
55 let cache_line_density = if total_cache_bytes > 0 {
56 (useful_size as f64 / total_cache_bytes as f64) * 100.0
57 } else {
58 0.0
59 };
60
61 layout.metrics = LayoutMetrics {
62 total_size: layout.size,
63 useful_size,
64 padding_bytes,
65 padding_percentage,
66 cache_lines_spanned,
67 cache_line_density,
68 padding_holes,
69 };
70}