use std::sync::Arc;
use tracing::{debug, info};
#[derive(Debug, Clone, Copy)]
pub struct MemoryStats {
pub peak_memory: u64,
pub current_memory: u64,
pub allocations: u64,
pub deallocations: u64,
}
impl MemoryStats {
pub fn new() -> Self {
Self {
peak_memory: 0,
current_memory: 0,
allocations: 0,
deallocations: 0,
}
}
pub fn update_peak(&mut self, current: u64) {
if current > self.peak_memory {
self.peak_memory = current;
}
}
pub fn format_size(bytes: u64) -> String {
const UNITS: &[&str] = &["B", "KB", "MB", "GB"];
let mut size = bytes as f64;
let mut unit_idx = 0;
while size >= 1024.0 && unit_idx < UNITS.len() - 1 {
size /= 1024.0;
unit_idx += 1;
}
format!("{:.2} {}", size, UNITS[unit_idx])
}
pub fn format(&self) -> String {
format!(
"Memory: peak={}, current={}, allocations={}, deallocations={}",
Self::format_size(self.peak_memory),
Self::format_size(self.current_memory),
self.allocations,
self.deallocations
)
}
}
impl Default for MemoryStats {
fn default() -> Self {
Self::new()
}
}
pub struct StringIntern {
strings: std::sync::Mutex<std::collections::HashMap<String, Arc<str>>>,
}
impl StringIntern {
pub fn new() -> Self {
Self {
strings: std::sync::Mutex::new(std::collections::HashMap::new()),
}
}
pub fn intern(&self, s: &str) -> Arc<str> {
let mut map = self.strings.lock().unwrap();
if let Some(interned) = map.get(s) {
Arc::clone(interned)
} else {
let arc: Arc<str> = Arc::from(s);
map.insert(s.to_string(), Arc::clone(&arc));
arc
}
}
pub fn stats(&self) -> usize {
self.strings.lock().unwrap().len()
}
pub fn clear(&self) {
self.strings.lock().unwrap().clear();
}
}
impl Default for StringIntern {
fn default() -> Self {
Self::new()
}
}
pub struct ObjectPool<T> {
pool: std::sync::Mutex<Vec<T>>,
factory: Box<dyn Fn() -> T + Send + Sync>,
}
impl<T: Send + Sync + 'static> ObjectPool<T> {
pub fn new<F: Fn() -> T + Send + Sync + 'static>(factory: F) -> Self {
Self {
pool: std::sync::Mutex::new(Vec::new()),
factory: Box::new(factory),
}
}
pub fn get(&self) -> T {
let mut pool = self.pool.lock().unwrap();
pool.pop().unwrap_or_else(|| (self.factory)())
}
pub fn return_object(&self, obj: T) {
let mut pool = self.pool.lock().unwrap();
if pool.len() < 100 { pool.push(obj);
}
}
pub fn size(&self) -> usize {
self.pool.lock().unwrap().len()
}
pub fn clear(&self) {
self.pool.lock().unwrap().clear();
}
}
pub struct StreamingBuffer {
buffer: Vec<u8>,
capacity: usize,
}
impl StreamingBuffer {
pub fn new(capacity: usize) -> Self {
Self {
buffer: Vec::with_capacity(capacity),
capacity,
}
}
pub fn as_mut(&mut self) -> &mut Vec<u8> {
&mut self.buffer
}
pub fn as_ref(&self) -> &[u8] {
&self.buffer
}
pub fn clear(&mut self) {
self.buffer.clear();
}
pub fn len(&self) -> usize {
self.buffer.len()
}
pub fn is_empty(&self) -> bool {
self.buffer.is_empty()
}
pub fn capacity(&self) -> usize {
self.capacity
}
}
impl Default for StreamingBuffer {
fn default() -> Self {
Self::new(8192) }
}
pub struct MemoryOptimizationReport {
pub opportunities: Vec<String>,
pub estimated_savings: u64,
pub priority: u32,
}
impl MemoryOptimizationReport {
pub fn new() -> Self {
Self {
opportunities: Vec::new(),
estimated_savings: 0,
priority: 3,
}
}
pub fn add_opportunity(&mut self, opportunity: String, savings: u64) {
self.opportunities.push(opportunity);
self.estimated_savings += savings;
}
pub fn format(&self) -> String {
let mut result = format!(
"Memory Optimization Report\n\
Estimated Savings: {}\n\
Priority: {}/5\n\
Opportunities:\n",
MemoryStats::format_size(self.estimated_savings),
self.priority
);
for (i, opp) in self.opportunities.iter().enumerate() {
result.push_str(&format!(" {}. {}\n", i + 1, opp));
}
result
}
pub fn log(&self) {
info!("{}", self.format());
}
}
impl Default for MemoryOptimizationReport {
fn default() -> Self {
Self::new()
}
}
pub mod patterns {
use super::*;
pub fn reduce_clones() -> &'static str {
"Use references instead of cloning large data structures"
}
pub fn use_arc_for_sharing() -> &'static str {
"Use Arc for shared ownership instead of cloning"
}
pub fn stream_large_files() -> &'static str {
"Stream large files instead of loading into memory"
}
pub fn use_string_interning() -> &'static str {
"Use string interning for duplicate strings"
}
pub fn use_object_pooling() -> &'static str {
"Use object pooling for temporary objects"
}
pub fn use_compact_structures() -> &'static str {
"Use compact data structures with smaller types"
}
pub fn use_lazy_evaluation() -> &'static str {
"Use lazy evaluation with iterators"
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_memory_stats_format_size() {
assert_eq!(MemoryStats::format_size(512), "512.00 B");
assert_eq!(MemoryStats::format_size(1024), "1.00 KB");
assert_eq!(MemoryStats::format_size(1024 * 1024), "1.00 MB");
}
#[test]
fn test_string_intern() {
let intern = StringIntern::new();
let s1 = intern.intern("test");
let s2 = intern.intern("test");
assert_eq!(s1.as_ptr(), s2.as_ptr());
assert_eq!(intern.stats(), 1);
}
#[test]
fn test_object_pool() {
let pool = ObjectPool::new(Vec::<u8>::new);
let mut obj1 = pool.get();
obj1.push(1);
pool.return_object(obj1);
let obj2 = pool.get();
assert_eq!(obj2.len(), 1);
assert_eq!(pool.size(), 0);
}
#[test]
fn test_streaming_buffer() {
let mut buffer = StreamingBuffer::new(1024);
assert!(buffer.is_empty());
assert_eq!(buffer.capacity(), 1024);
buffer.as_mut().push(1);
assert_eq!(buffer.len(), 1);
buffer.clear();
assert!(buffer.is_empty());
}
#[test]
fn test_memory_optimization_report() {
let mut report = MemoryOptimizationReport::new();
report.add_opportunity("Reduce clones".to_string(), 1024 * 1024);
report.add_opportunity("Stream files".to_string(), 512 * 1024);
assert_eq!(report.opportunities.len(), 2);
assert_eq!(report.estimated_savings, 1536 * 1024);
}
}