use super::dependency::Dependency;
use super::error::DependencyError;
use super::resolved::ResolvedDependencies;
use crate::request_data::RequestData;
use http::Request;
use std::any::Any;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::sync::Arc;
pub struct ValueDependency<T: Clone + Send + Sync + 'static> {
key: String,
value: Arc<T>,
_phantom: PhantomData<T>,
}
impl<T: Clone + Send + Sync + 'static> ValueDependency<T> {
pub fn new(key: impl Into<String>, value: T) -> Self {
Self {
key: key.into(),
value: Arc::new(value),
_phantom: PhantomData,
}
}
}
impl<T: Clone + Send + Sync + 'static> Dependency for ValueDependency<T> {
fn resolve(
&self,
_request: &Request<()>,
_request_data: &RequestData,
_resolved: &ResolvedDependencies,
) -> Pin<Box<dyn Future<Output = Result<Arc<dyn Any + Send + Sync>, DependencyError>> + Send>> {
let value = Arc::clone(&self.value);
Box::pin(async move { Ok(value as Arc<dyn Any + Send + Sync>) })
}
fn key(&self) -> &str {
&self.key
}
fn depends_on(&self) -> Vec<String> {
vec![]
}
fn cacheable(&self) -> bool {
true
}
fn singleton(&self) -> bool {
true
}
}
impl<T: Clone + Send + Sync + 'static> std::fmt::Debug for ValueDependency<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ValueDependency")
.field("key", &self.key)
.field("value_type", &std::any::type_name::<T>())
.field("value", &"<T>")
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
fn make_request_data() -> RequestData {
RequestData {
path_params: Arc::new(HashMap::new()),
query_params: serde_json::Value::Null,
validated_params: None,
raw_query_params: Arc::new(HashMap::new()),
body: serde_json::Value::Null,
raw_body: None,
headers: Arc::new(HashMap::new()),
cookies: Arc::new(HashMap::new()),
method: "GET".to_string(),
path: "/".to_string(),
#[cfg(feature = "di")]
dependencies: None,
}
}
#[test]
fn test_new() {
let dep = ValueDependency::new("test", 42i32);
assert_eq!(dep.key(), "test");
}
#[test]
fn test_key() {
let dep = ValueDependency::new("my_key", "value");
assert_eq!(dep.key(), "my_key");
}
#[test]
fn test_depends_on() {
let dep = ValueDependency::new("test", 42i32);
assert_eq!(dep.depends_on(), Vec::<String>::new());
}
#[test]
fn test_cacheable() {
let dep = ValueDependency::new("test", 42i32);
assert!(dep.cacheable());
}
#[test]
fn test_singleton() {
let dep = ValueDependency::new("test", 42i32);
assert!(dep.singleton());
}
#[tokio::test]
async fn test_resolve_simple() {
let dep = ValueDependency::new("answer", 42i32);
let request = Request::builder().body(()).unwrap();
let request_data = make_request_data();
let resolved = ResolvedDependencies::new();
let result = dep.resolve(&request, &request_data, &resolved).await;
assert!(result.is_ok());
let value: Arc<i32> = result.unwrap().downcast().unwrap();
assert_eq!(*value, 42);
}
#[tokio::test]
async fn test_resolve_string() {
let dep = ValueDependency::new("message", "Hello, World!".to_string());
let request = Request::builder().body(()).unwrap();
let request_data = make_request_data();
let resolved = ResolvedDependencies::new();
let result = dep.resolve(&request, &request_data, &resolved).await;
assert!(result.is_ok());
let value: Arc<String> = result.unwrap().downcast().unwrap();
assert_eq!(*value, "Hello, World!");
}
#[tokio::test]
async fn test_resolve_concurrent() {
let dep = Arc::new(ValueDependency::new("shared", 100i32));
let request = Request::builder().body(()).unwrap();
let request_data = make_request_data();
let handles: Vec<_> = (0..10)
.map(|_| {
let dep = Arc::clone(&dep);
let req = request.clone();
let data = request_data.clone();
tokio::spawn(async move {
let resolved = ResolvedDependencies::new();
let result = dep.resolve(&req, &data, &resolved).await.unwrap();
let value: Arc<i32> = result.downcast().unwrap();
*value
})
})
.collect();
for handle in handles {
let value = handle.await.unwrap();
assert_eq!(value, 100);
}
}
#[derive(Clone, Debug, PartialEq)]
struct ComplexValue {
name: String,
count: i32,
tags: Vec<String>,
}
#[tokio::test]
async fn test_resolve_complex_type() {
let complex = ComplexValue {
name: "test".to_string(),
count: 42,
tags: vec!["tag1".to_string(), "tag2".to_string()],
};
let dep = ValueDependency::new("complex", complex.clone());
let request = Request::builder().body(()).unwrap();
let request_data = make_request_data();
let resolved = ResolvedDependencies::new();
let result = dep.resolve(&request, &request_data, &resolved).await;
assert!(result.is_ok());
let value: Arc<ComplexValue> = result.unwrap().downcast().unwrap();
assert_eq!(*value, complex);
}
#[test]
fn test_debug() {
let dep = ValueDependency::new("test", 42i32);
let debug_str = format!("{dep:?}");
assert!(debug_str.contains("ValueDependency"));
assert!(debug_str.contains("test"));
}
}