1use crate::Result;
2use serde::{Deserialize, Serialize};
3use sysinfo::System;
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7pub enum MemoryType {
8 DDR3,
9 DDR4,
10 DDR5,
11 LPDDR3,
12 LPDDR4,
13 LPDDR5,
14 Unknown(String),
15}
16
17impl std::fmt::Display for MemoryType {
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 match self {
20 MemoryType::DDR3 => write!(f, "DDR3"),
21 MemoryType::DDR4 => write!(f, "DDR4"),
22 MemoryType::DDR5 => write!(f, "DDR5"),
23 MemoryType::LPDDR3 => write!(f, "LPDDR3"),
24 MemoryType::LPDDR4 => write!(f, "LPDDR4"),
25 MemoryType::LPDDR5 => write!(f, "LPDDR5"),
26 MemoryType::Unknown(name) => write!(f, "{name}"),
27 }
28 }
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct MemoryModule {
34 pub size_mb: u64,
36 pub memory_type: MemoryType,
38 pub speed_mhz: u32,
40 pub manufacturer: Option<String>,
42 pub part_number: Option<String>,
44 pub slot: Option<String>,
46 pub voltage: Option<f32>,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct MemoryInfo {
53 pub total_mb: u64,
55 pub available_mb: u64,
57 pub used_mb: u64,
59 pub usage_percent: f32,
61 pub modules: Vec<MemoryModule>,
63 pub channels: u32,
65 pub ecc_support: bool,
67 pub speed_mhz: u32,
69 pub bandwidth_gb_s: Option<f32>,
71 pub swap_total_mb: u64,
73 pub swap_used_mb: u64,
75}
76
77impl MemoryInfo {
78 pub fn query() -> Result<Self> {
80 let mut system = System::new_all();
81 system.refresh_memory();
82
83 let total_mb = system.total_memory() / (1024 * 1024);
84 let available_mb = system.available_memory() / (1024 * 1024);
85 let used_mb = system.used_memory() / (1024 * 1024);
86 let usage_percent = (used_mb as f32 / total_mb as f32) * 100.0;
87
88 let swap_total_mb = system.total_swap() / (1024 * 1024);
89 let swap_used_mb = system.used_swap() / (1024 * 1024);
90
91 Ok(Self {
92 total_mb,
93 available_mb,
94 used_mb,
95 usage_percent,
96 modules: Self::detect_memory_modules()?,
97 channels: Self::detect_memory_channels()?,
98 ecc_support: Self::detect_ecc_support()?,
99 speed_mhz: Self::detect_memory_speed()?,
100 bandwidth_gb_s: Self::calculate_bandwidth(),
101 swap_total_mb,
102 swap_used_mb,
103 })
104 }
105
106 pub fn total_gb(&self) -> f64 {
108 self.total_mb as f64 / 1024.0
109 }
110
111 pub fn available_gb(&self) -> f64 {
113 self.available_mb as f64 / 1024.0
114 }
115
116 pub fn used_gb(&self) -> f64 {
118 self.used_mb as f64 / 1024.0
119 }
120
121 pub fn total_mb(&self) -> u64 {
123 self.total_mb
124 }
125
126 pub fn available_mb(&self) -> u64 {
128 self.available_mb
129 }
130
131 pub fn used_mb(&self) -> u64 {
133 self.used_mb
134 }
135
136 pub fn usage_percent(&self) -> f32 {
138 self.usage_percent
139 }
140
141 pub fn modules(&self) -> &[MemoryModule] {
143 &self.modules
144 }
145
146 pub fn channels(&self) -> u32 {
148 self.channels
149 }
150
151 pub fn ecc_support(&self) -> bool {
153 self.ecc_support
154 }
155
156 pub fn speed_mhz(&self) -> u32 {
158 self.speed_mhz
159 }
160
161 pub fn bandwidth_gb_s(&self) -> Option<f32> {
163 self.bandwidth_gb_s
164 }
165
166 pub fn swap_total_gb(&self) -> f64 {
168 self.swap_total_mb as f64 / 1024.0
169 }
170
171 pub fn swap_used_gb(&self) -> f64 {
173 self.swap_used_mb as f64 / 1024.0
174 }
175
176 pub fn has_sufficient_memory(&self, required_gb: f64) -> bool {
178 self.available_gb() >= required_gb
179 }
180
181 fn detect_memory_modules() -> Result<Vec<MemoryModule>> {
182 Ok(vec![MemoryModule {
185 size_mb: 8192,
186 memory_type: MemoryType::DDR4,
187 speed_mhz: 3200,
188 manufacturer: Some("Unknown".to_string()),
189 part_number: None,
190 slot: Some("DIMM1".to_string()),
191 voltage: Some(1.35),
192 }])
193 }
194
195 fn detect_memory_channels() -> Result<u32> {
196 Ok(2) }
199
200 fn detect_ecc_support() -> Result<bool> {
201 Ok(false)
203 }
204
205 fn detect_memory_speed() -> Result<u32> {
206 Ok(3200)
208 }
209
210 fn calculate_bandwidth() -> Option<f32> {
211 Some(51.2)
214 }
215}