lxy 0.1.1

A convenient async http and RPC framework in Rust
Documentation
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
}

/// Retrieves the current app instance.
///
/// # Errors
///
/// Returns [`OutOfScope`] if called outside an app lifetime.
///
/// # Examples
///
/// ```rust
/// use lxy::{get_app, Result};
///
/// async fn handler() -> Result<()> {
///     let app = get_app()?;
///     // Access services from the app container
///     Ok(())
/// }
/// ```
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));
      }
    }
  }
}