Documentation
use std::sync::Arc;

use tokio::task::futures::TaskLocalFuture;

use crate::{
	error::ServiceNotFoundError,
	scope::{Scope, ScopeProvider},
};

tokio::task_local! {
	static TASK_SCOPE: Arc<Scope>;
}

pub struct TaskScopeProvider;

impl super::ScopeDefault for TaskScopeProvider {
	fn initialize(_scope: Arc<Scope>) { unreachable!() }

	fn update(_scope: Arc<Scope>) { unreachable!() }
}

impl TaskScopeProvider {
	pub fn initialize_async<F>(scope: Scope, fut: F) -> TaskLocalFuture<Arc<Scope>, F>
	where
		F: Future,
	{
		TASK_SCOPE.scope(Arc::new(scope), fut)
	}

	pub fn initialize_sync<F, R>(scope: Scope, fun: F) -> R
	where
		F: FnOnce() -> R,
	{
		TASK_SCOPE.sync_scope(Arc::new(scope), fun)
	}

	pub fn update_async<F>(scope: Scope, fut: F) -> TaskLocalFuture<Arc<Scope>, F>
	where
		F: Future,
	{
		TASK_SCOPE.scope(Arc::new(scope), fut)
	}

	pub fn update_sync<F, R>(scope: Scope, fun: F) -> R
	where
		F: FnOnce() -> R,
	{
		TASK_SCOPE.sync_scope(Arc::new(scope), fun)
	}
}

impl ScopeProvider for TaskScopeProvider {
	fn provide_scope(&self) -> Result<Arc<Scope>, ServiceNotFoundError> { Ok(TASK_SCOPE.get()) }
}