use std::sync::Arc;
use tokio::sync::RwLock;
use serde_json::Value;
use std::collections::HashMap;
use tracing::{debug, info, warn};
use crate::server::resource_manager::ObjectPool;
use crate::server::brp_messages::{builtin_methods, BrpRequest, BrpResponse, ComponentFilter};
use crate::server::error::Result;
fn default_brp_request() -> Box<BrpRequest> {
Box::new(BrpRequest {
method: builtin_methods::BRP_QUERY_METHOD.to_string(),
id: None,
params: Some(crate::server::brp_messages::query_params(None, true)),
})
}
fn default_brp_response() -> Box<BrpResponse> {
Box::new(BrpResponse::new(None, Ok(Value::Array(Vec::new()))))
}
fn default_brp_request_from(_existing: Box<BrpRequest>) -> Box<BrpRequest> {
default_brp_request()
}
fn default_brp_response_from(_existing: Box<BrpResponse>) -> Box<BrpResponse> {
default_brp_response()
}
pub struct GameDebugPools {
brp_request_pool: ObjectPool<Box<BrpRequest>>,
brp_response_pool: ObjectPool<Box<BrpResponse>>,
component_filter_pool: ObjectPool<Vec<ComponentFilter>>,
string_vec_pool: ObjectPool<Vec<String>>,
json_value_pool: ObjectPool<Value>,
hashmap_pool: ObjectPool<HashMap<String, Value>>,
query_result_pool: ObjectPool<Vec<Value>>,
}
impl GameDebugPools {
pub fn new() -> Self {
Self {
brp_request_pool: ObjectPool::new(
Box::new(default_brp_request),
50 ),
brp_response_pool: ObjectPool::new(
Box::new(default_brp_response),
50 ),
component_filter_pool: ObjectPool::new(
Box::new(|| Vec::with_capacity(8)),
100 ),
string_vec_pool: ObjectPool::new(
Box::new(|| Vec::with_capacity(16)),
200 ),
json_value_pool: ObjectPool::new(
Box::new(|| Value::Null),
500 ),
hashmap_pool: ObjectPool::new(
Box::new(|| HashMap::with_capacity(32)),
100 ),
query_result_pool: ObjectPool::new(
Box::new(|| Vec::with_capacity(64)),
50 ),
}
}
pub async fn get_brp_request(&self) -> Box<BrpRequest> {
let request = self.brp_request_pool.acquire().await;
default_brp_request_from(request)
}
pub async fn return_brp_request(&self, request: Box<BrpRequest>) {
self.brp_request_pool.release(request).await;
}
pub async fn get_brp_response(&self) -> Box<BrpResponse> {
let response = self.brp_response_pool.acquire().await;
default_brp_response_from(response)
}
pub async fn return_brp_response(&self, response: Box<BrpResponse>) {
self.brp_response_pool.release(response).await;
}
pub async fn get_component_filters(&self) -> Vec<ComponentFilter> {
let mut filters = self.component_filter_pool.acquire().await;
filters.clear();
filters
}
pub async fn return_component_filters(&self, filters: Vec<ComponentFilter>) {
self.component_filter_pool.release(filters).await;
}
pub async fn get_string_vec(&self) -> Vec<String> {
let mut strings = self.string_vec_pool.acquire().await;
strings.clear();
strings
}
pub async fn return_string_vec(&self, strings: Vec<String>) {
self.string_vec_pool.release(strings).await;
}
pub async fn get_json_value(&self) -> Value {
let value = self.json_value_pool.acquire().await;
Value::Null
}
pub async fn return_json_value(&self, value: Value) {
self.json_value_pool.release(value).await;
}
pub async fn get_hashmap(&self) -> HashMap<String, Value> {
let mut map = self.hashmap_pool.acquire().await;
map.clear();
map
}
pub async fn return_hashmap(&self, map: HashMap<String, Value>) {
self.hashmap_pool.release(map).await;
}
pub async fn get_query_results(&self) -> Vec<Value> {
let mut results = self.query_result_pool.acquire().await;
results.clear();
results
}
pub async fn return_query_results(&self, results: Vec<Value>) {
self.query_result_pool.release(results).await;
}
pub async fn get_pool_stats(&self) -> PoolStats {
PoolStats {
brp_request_pool_size: self.brp_request_pool.size(),
brp_response_pool_size: self.brp_response_pool.size(),
component_filter_pool_size: self.component_filter_pool.size(),
string_vec_pool_size: self.string_vec_pool.size(),
json_value_pool_size: self.json_value_pool.size(),
hashmap_pool_size: self.hashmap_pool.size(),
query_result_pool_size: self.query_result_pool.size(),
}
}
pub async fn warm_up_pools(&self) {
info!("Warming up memory pools for optimal game debugging performance");
let mut pre_allocated = Vec::new();
for _ in 0..10 {
pre_allocated.push(self.get_brp_request().await);
}
for req in pre_allocated.drain(..) {
self.return_brp_request(req).await;
}
let mut string_vecs = Vec::new();
for _ in 0..20 {
string_vecs.push(self.get_string_vec().await);
}
for vec in string_vecs {
self.return_string_vec(vec).await;
}
let mut filters = Vec::new();
for _ in 0..15 {
filters.push(self.get_component_filters().await);
}
for filter in filters {
self.return_component_filters(filter).await;
}
info!("Memory pools warmed up successfully");
}
pub async fn cleanup_pools(&self) {
info!("Cleaning up memory pools");
debug!("Pool cleanup completed");
}
}
impl Default for GameDebugPools {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct PoolStats {
pub brp_request_pool_size: usize,
pub brp_response_pool_size: usize,
pub component_filter_pool_size: usize,
pub string_vec_pool_size: usize,
pub json_value_pool_size: usize,
pub hashmap_pool_size: usize,
pub query_result_pool_size: usize,
}
impl PoolStats {
pub fn total_pooled_objects(&self) -> usize {
self.brp_request_pool_size
+ self.brp_response_pool_size
+ self.component_filter_pool_size
+ self.string_vec_pool_size
+ self.json_value_pool_size
+ self.hashmap_pool_size
+ self.query_result_pool_size
}
pub fn log_stats(&self) {
info!(
"Pool Stats - BRP Req: {}, BRP Res: {}, Filters: {}, Strings: {}, JSON: {}, Maps: {}, Results: {} (Total: {})",
self.brp_request_pool_size,
self.brp_response_pool_size,
self.component_filter_pool_size,
self.string_vec_pool_size,
self.json_value_pool_size,
self.hashmap_pool_size,
self.query_result_pool_size,
self.total_pooled_objects()
);
}
}
pub static GAME_POOLS: once_cell::sync::Lazy<GameDebugPools> =
once_cell::sync::Lazy::new(|| GameDebugPools::new());
#[macro_export]
macro_rules! with_pooled {
($pool:expr, $method:ident, $return_method:ident, $body:expr) => {{
let obj = $pool.$method().await;
let result = $body(obj);
result
}};
}
pub struct PooledGuard<T, F>
where
F: Fn(T),
{
obj: Option<T>,
return_fn: F,
}
impl<T, F> PooledGuard<T, F>
where
F: Fn(T),
{
pub fn new(obj: T, return_fn: F) -> Self {
Self {
obj: Some(obj),
return_fn,
}
}
pub fn get(&self) -> &T {
self.obj.as_ref().expect("PooledGuard used after drop")
}
pub fn get_mut(&mut self) -> &mut T {
self.obj.as_mut().expect("PooledGuard used after drop")
}
pub fn take(mut self) -> T {
self.obj.take().expect("PooledGuard used after drop")
}
}
impl<T, F> Drop for PooledGuard<T, F>
where
F: Fn(T),
{
fn drop(&mut self) {
if let Some(obj) = self.obj.take() {
(self.return_fn)(obj);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_game_debug_pools() {
let pools = GameDebugPools::new();
let mut strings = pools.get_string_vec().await;
strings.push("Transform".to_string());
strings.push("Velocity".to_string());
assert_eq!(strings.len(), 2);
pools.return_string_vec(strings).await;
let strings2 = pools.get_string_vec().await;
assert_eq!(strings2.len(), 0);
pools.return_string_vec(strings2).await;
let stats = pools.get_pool_stats().await;
let _ = stats.total_pooled_objects();
}
#[tokio::test]
async fn test_pool_warm_up() {
let pools = GameDebugPools::new();
pools.warm_up_pools().await;
let stats = pools.get_pool_stats().await;
stats.log_stats();
}
}