1use serde::Serialize;
2
3#[derive(Debug, Clone, Serialize)]
4pub struct StructLayout {
5 pub name: String,
6 pub size: u64,
7 pub alignment: Option<u64>,
8 pub members: Vec<MemberLayout>,
9 pub metrics: LayoutMetrics,
10 #[serde(skip_serializing_if = "Option::is_none")]
11 pub source_location: Option<SourceLocation>,
12}
13
14#[derive(Debug, Clone, Serialize)]
15pub struct MemberLayout {
16 pub name: String,
17 pub type_name: String,
18 pub offset: Option<u64>,
19 pub size: Option<u64>,
20 #[serde(skip_serializing_if = "Option::is_none")]
21 pub bit_offset: Option<u64>,
22 #[serde(skip_serializing_if = "Option::is_none")]
23 pub bit_size: Option<u64>,
24 #[serde(skip_serializing_if = "std::ops::Not::not")]
27 pub is_atomic: bool,
28}
29
30#[derive(Debug, Clone, Serialize, Default)]
31pub struct LayoutMetrics {
32 pub total_size: u64,
33 pub useful_size: u64,
34 pub padding_bytes: u64,
35 pub padding_percentage: f64,
36 pub cache_lines_spanned: u32,
37 pub cache_line_density: f64,
38 pub padding_holes: Vec<PaddingHole>,
39 #[serde(skip_serializing_if = "std::ops::Not::not")]
40 pub partial: bool,
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub false_sharing: Option<FalseSharingAnalysis>,
43}
44
45#[derive(Debug, Clone, Serialize)]
46pub struct PaddingHole {
47 pub offset: u64,
48 pub size: u64,
49 pub after_member: Option<String>,
50}
51
52#[derive(Debug, Clone, Serialize)]
53pub struct SourceLocation {
54 pub file: String,
55 pub line: u64,
56}
57
58#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
59pub struct FalseSharingWarning {
60 pub member_a: String,
61 pub member_b: String,
62 pub cache_line: u64,
63 pub gap_bytes: i64,
66}
67
68#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
69pub struct CacheLineSpanningWarning {
70 pub member: String,
71 pub type_name: String,
72 pub offset: u64,
73 pub size: u64,
74 pub start_cache_line: u64,
75 pub end_cache_line: u64,
76 pub lines_spanned: u64,
77}
78
79#[derive(Debug, Clone, Serialize, Default, PartialEq, Eq)]
80pub struct FalseSharingAnalysis {
81 pub atomic_members: Vec<AtomicMember>,
82 pub warnings: Vec<FalseSharingWarning>,
83 #[serde(skip_serializing_if = "Vec::is_empty")]
84 pub spanning_warnings: Vec<CacheLineSpanningWarning>,
85}
86
87#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
88pub struct AtomicMember {
89 pub name: String,
90 pub type_name: String,
91 pub offset: u64,
92 pub size: u64,
93 pub cache_line: u64,
94 pub end_cache_line: u64,
95 pub spans_cache_lines: bool,
96}
97
98impl StructLayout {
99 pub fn new(name: String, size: u64, alignment: Option<u64>) -> Self {
100 Self {
101 name,
102 size,
103 alignment,
104 members: Vec::new(),
105 metrics: LayoutMetrics::default(),
106 source_location: None,
107 }
108 }
109}
110
111impl MemberLayout {
112 pub fn new(name: String, type_name: String, offset: Option<u64>, size: Option<u64>) -> Self {
113 Self { name, type_name, offset, size, bit_offset: None, bit_size: None, is_atomic: false }
114 }
115
116 pub fn with_atomic(mut self, is_atomic: bool) -> Self {
117 self.is_atomic = is_atomic;
118 self
119 }
120
121 pub fn end_offset(&self) -> Option<u64> {
122 match (self.offset, self.size) {
123 (Some(off), Some(sz)) => Some(off + sz),
124 _ => None,
125 }
126 }
127}