use core::fmt;
use core::marker::PhantomData;
use std::sync::Arc;
use super::{Inner, Runtime, RuntimeHandle};
use crate::rt::context;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RuntimeId(u64);
impl fmt::Display for RuntimeId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[must_use = "the runtime is set only while the guard lives"]
pub struct EnterGuard<'a> {
_set: context::RuntimeSet,
_runtime: PhantomData<&'a ()>,
_not_send: PhantomData<*const ()>,
}
impl fmt::Debug for EnterGuard<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EnterGuard").finish_non_exhaustive()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct TryCurrentError {
_private: (),
}
impl TryCurrentError {
pub fn is_missing_context(&self) -> bool {
true
}
}
impl fmt::Display for TryCurrentError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(
"no runtime is set on this thread: call it inside `block_on`, a task, or `enter`",
)
}
}
impl std::error::Error for TryCurrentError {}
fn enter(inner: &Arc<Inner>) -> EnterGuard<'_> {
EnterGuard {
_set: context::set_runtime(inner),
_runtime: PhantomData,
_not_send: PhantomData,
}
}
impl Runtime {
pub fn enter(&self) -> EnterGuard<'_> {
enter(&self.inner)
}
pub fn id(&self) -> RuntimeId {
RuntimeId(self.inner.id)
}
pub fn shutdown_background(self) {
self.inner.workers.stop_all();
drop(self.inner.workers.take_threads());
}
}
impl RuntimeHandle {
pub fn enter(&self) -> EnterGuard<'_> {
enter(&self.inner)
}
pub fn id(&self) -> RuntimeId {
RuntimeId(self.inner.id)
}
pub fn try_current() -> Result<Self, TryCurrentError> {
context::runtime()
.map(|inner| Self { inner })
.ok_or(TryCurrentError { _private: () })
}
}
pub fn worker_index() -> Option<usize> {
let runtime = context::runtime()?;
context::current(|shard| shard.and_then(|shard| shard.worker_index(runtime.id)))
}