use std::future::Future;
use tokio::task_local;
use super::App;
use crate::context::OutOfScope;
use crate::error::{Result, TypedError};
task_local! {
static APP: App;
}
pub(crate) async fn run_with_app<Fut, R>(app: App, fut: Fut) -> R
where
Fut: Future<Output = R>,
{
APP.scope(app, fut).await
}
pub fn get_app() -> Result<App> {
APP
.try_with(|app| app.clone())
.map_err(|_| OutOfScope::error("get_app() called outside app scope"))
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use super::*;
use crate::container::Container;
use crate::error::Result;
#[tokio::test]
async fn test_run_with_app() {
struct Service;
async fn test_run() -> Result<Arc<Service>> {
get_app()?.get::<Service>()
}
let mut app = App::new();
app.container.bind(Service);
let service = run_with_app(app, test_run()).await;
assert!(service.is_ok());
}
#[tokio::test]
async fn test_get_app_outside() {
use crate::error::ErrorCode;
match get_app() {
Ok(_) => panic!("should return error outside app context"),
Err(err) => {
assert!(err.is_code(ErrorCode::Internal));
assert!(err.is(OutOfScope));
}
}
}
}