use crate::engine::WorldStateEngine;
use crate::query::WorldStateQuery;
use async_trait::async_trait;
use mockforge_core::middleware_traits::{self, MiddlewareResult};
use serde_json::Value;
use std::sync::Arc;
use tokio::sync::RwLock;
pub struct WorldStateMiddlewareAdapter {
inner: Arc<RwLock<WorldStateEngine>>,
}
impl WorldStateMiddlewareAdapter {
pub fn new(engine: Arc<RwLock<WorldStateEngine>>) -> Self {
Self { inner: engine }
}
pub fn from_engine(engine: WorldStateEngine) -> Self {
Self {
inner: Arc::new(RwLock::new(engine)),
}
}
pub fn inner(&self) -> &Arc<RwLock<WorldStateEngine>> {
&self.inner
}
}
#[async_trait]
impl middleware_traits::WorldStateMiddleware for WorldStateMiddlewareAdapter {
async fn snapshot(&self) -> MiddlewareResult<Value> {
let engine = self.inner.read().await;
let snapshot = engine
.create_snapshot()
.await
.map_err(|e| -> Box<dyn std::error::Error + Send + Sync> { e.to_string().into() })?;
serde_json::to_value(&snapshot)
.map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)
}
async fn query(&self, query: Value) -> MiddlewareResult<Value> {
let ws_query: WorldStateQuery = serde_json::from_value(query)
.map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
let engine = self.inner.read().await;
let result = engine
.query(&ws_query)
.await
.map_err(|e| -> Box<dyn std::error::Error + Send + Sync> { e.to_string().into() })?;
serde_json::to_value(&result)
.map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)
}
fn layers(&self) -> Vec<String> {
match self.inner.try_read() {
Ok(engine) => engine.get_layers().iter().map(|l| l.name().to_string()).collect(),
Err(_) => Vec::new(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use mockforge_core::middleware_traits::WorldStateMiddleware as WorldStateMiddlewareTrait;
#[tokio::test]
async fn test_adapter_snapshot_empty() {
let engine = WorldStateEngine::new();
let adapter = WorldStateMiddlewareAdapter::from_engine(engine);
let snapshot = adapter.snapshot().await.unwrap();
assert!(snapshot["nodes"].is_array());
assert!(snapshot["edges"].is_array());
}
#[tokio::test]
async fn test_adapter_query() {
let engine = WorldStateEngine::new();
let adapter = WorldStateMiddlewareAdapter::from_engine(engine);
let query = serde_json::json!({
"include_edges": true
});
let result = adapter.query(query).await.unwrap();
assert!(result["nodes"].is_array());
}
#[tokio::test]
async fn test_adapter_layers_empty() {
let engine = WorldStateEngine::new();
let adapter = WorldStateMiddlewareAdapter::from_engine(engine);
let layers = adapter.layers();
assert!(layers.is_empty());
}
#[tokio::test]
async fn test_adapter_as_trait_object() {
let engine = WorldStateEngine::new();
let adapter = WorldStateMiddlewareAdapter::from_engine(engine);
let trait_obj: Arc<dyn WorldStateMiddlewareTrait> = Arc::new(adapter);
let snapshot = trait_obj.snapshot().await.unwrap();
assert!(snapshot["nodes"].is_array());
}
#[tokio::test]
async fn test_adapter_invalid_query() {
let engine = WorldStateEngine::new();
let adapter = WorldStateMiddlewareAdapter::from_engine(engine);
let query = serde_json::json!(42);
let result = adapter.query(query).await;
assert!(result.is_err());
}
}