memkit 0.2.0-beta.1

Deterministic, intent-driven memory allocation for systems requiring predictable performance
Documentation
//! Game loop example demonstrating realistic memkit usage.
//!
//! Shows how to use memkit in a typical game loop pattern with
//! systems for physics, rendering, and AI.
//!
//! Run with: `cargo run --example game_loop`

use memkit::{MkAllocator, MkConfig};
use std::time::Instant;

// Simulated game data structures
#[derive(Debug, Clone, Copy)]
struct Transform {
    position: [f32; 3],
    rotation: [f32; 4],
    scale: [f32; 3],
}

impl Default for Transform {
    fn default() -> Self {
        Self {
            position: [0.0, 0.0, 0.0],
            rotation: [0.0, 0.0, 0.0, 1.0],
            scale: [1.0, 1.0, 1.0],
        }
    }
}

#[derive(Debug, Clone, Copy)]
struct Velocity {
    linear: [f32; 3],
    angular: [f32; 3],
}

impl Default for Velocity {
    fn default() -> Self {
        Self {
            linear: [0.0, 0.0, 0.0],
            angular: [0.0, 0.0, 0.0],
        }
    }
}

const ENTITY_COUNT: usize = 1000;
const FRAME_COUNT: usize = 60;

fn main() {
    println!("=== memkit Game Loop Example ===\n");
    println!("Simulating {} entities for {} frames\n", ENTITY_COUNT, FRAME_COUNT);

    // Configure allocator for game usage
    let config = MkConfig {
        frame_arena_size: 4 * 1024 * 1024, // 4 MB per frame
        ..Default::default()
    };
    let alloc = MkAllocator::new(config);

    // Persistent game state (heap allocated, lives across frames)
    let mut transforms: Vec<Transform> = (0..ENTITY_COUNT)
        .map(|i| Transform {
            position: [i as f32 * 0.1, 0.0, 0.0],
            ..Default::default()
        })
        .collect();

    let mut velocities: Vec<Velocity> = (0..ENTITY_COUNT)
        .map(|i| Velocity {
            linear: [0.0, (i % 10) as f32 * 0.01, 0.0],
            ..Default::default()
        })
        .collect();

    let start = Instant::now();
    let mut frame_times = Vec::with_capacity(FRAME_COUNT);

    // Game loop
    for frame in 0..FRAME_COUNT {
        let frame_start = Instant::now();
        
        // Begin frame - all frame allocations from here are temporary
        alloc.begin_frame();

        // === Physics System ===
        // Use frame allocation for temporary physics data
        if let Some(mut physics_results) = alloc.frame_slice::<[f32; 3]>(ENTITY_COUNT) {
            // Calculate new positions
            for i in 0..ENTITY_COUNT {
                let dt = 1.0 / 60.0;
                physics_results[i] = [
                    transforms[i].position[0] + velocities[i].linear[0] * dt,
                    transforms[i].position[1] + velocities[i].linear[1] * dt,
                    transforms[i].position[2] + velocities[i].linear[2] * dt,
                ];
            }

            // Apply results
            for (i, result) in physics_results.iter().enumerate() {
                transforms[i].position = *result;
            }
        }

        // === AI System (with nested scope) ===
        {
            let _scope = alloc.scope();
            
            // Temporary AI decision data
            if let Some(mut decisions) = alloc.frame_slice::<u8>(ENTITY_COUNT) {
                // Simulate AI decisions
                for (i, decision) in decisions.iter_mut().enumerate() {
                    *decision = ((i + frame) % 4) as u8; // 0=idle, 1=move, 2=attack, 3=defend
                }

                // Apply decisions (just counting for demo)
                let actions: usize = decisions.iter().filter(|&&d| d > 0).count();
                if frame == 0 {
                    println!("Frame {}: {} entities taking action", frame, actions);
                }
            }
            // AI temp data freed here when scope drops
        }

        // === Render System ===
        // Prepare render data
        if let Some(mut render_transforms) = alloc.frame_slice::<Transform>(ENTITY_COUNT) {
            // Copy and potentially interpolate transforms for rendering
            for (i, rt) in render_transforms.iter_mut().enumerate() {
                *rt = transforms[i];
            }
            
            // Simulate rendering (just access the data)
            let _center: f32 = render_transforms.iter()
                .map(|t| t.position[0])
                .sum::<f32>() / ENTITY_COUNT as f32;
        }

        // End frame - instant reset
        alloc.end_frame();

        frame_times.push(frame_start.elapsed());
    }

    let total_time = start.elapsed();
    
    // Statistics
    println!("\n=== Performance ===");
    println!("Total time: {:?}", total_time);
    println!("Avg frame time: {:?}", total_time / FRAME_COUNT as u32);
    
    let min_frame = frame_times.iter().min().unwrap();
    let max_frame = frame_times.iter().max().unwrap();
    println!("Min frame: {:?}", min_frame);
    println!("Max frame: {:?}", max_frame);

    let stats = alloc.stats();
    println!("\n=== Memory ===");
    println!("Frames processed: {}", stats.frame);
    println!("Total allocated: {} bytes", stats.total_allocated);
    println!("Peak allocated: {} bytes", stats.peak_allocated);
    
    println!("\nDone!");
}