use core::future::Future;
use std::io;
use std::sync::Arc;
use super::super::context;
use super::{DEFAULT, Inner, Runtime, Task, spawn_here, spawn_on};
pub(super) fn try_default() -> io::Result<&'static Runtime> {
if let Some(runtime) = DEFAULT.get() {
return Ok(runtime);
}
static STARTING: std::sync::Mutex<()> = std::sync::Mutex::new(());
let _one = STARTING
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
if let Some(runtime) = DEFAULT.get() {
return Ok(runtime);
}
let runtime = super::Builder::new().build()?;
Ok(DEFAULT.get_or_init(|| runtime))
}
pub(crate) fn try_current() -> io::Result<Arc<Inner>> {
match context::runtime() {
Some(inner) => Ok(inner),
None => try_default().map(|runtime| Arc::clone(&runtime.inner)),
}
}
fn ensure_shard() -> io::Result<()> {
if context::current(|current| current.is_some()) {
return Ok(());
}
context::own_shard().map(drop)
}
pub(crate) fn try_spawn<F>(
inner: &Arc<Inner>,
worker: Option<usize>,
future: F,
) -> io::Result<Task<F::Output>>
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
if let Some(worker) = worker {
return super::placement::spawn_on_worker(inner, worker, future);
}
match inner.workers.place(inner.id, inner.local_margin) {
Some(shard) => Ok(spawn_on(inner, shard, future)),
None => {
ensure_shard()?;
Ok(spawn_here(future, false))
}
}
}
pub(crate) fn try_spawn_local<F>(worker: Option<usize>, future: F) -> io::Result<Task<F::Output>>
where
F: Future + 'static,
F::Output: 'static,
{
if let Some(worker) = worker
&& super::worker_index() != Some(worker)
{
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!(
"a future that is not Send spawns only on the worker that runs it, not on worker \
{worker}: use RuntimeHandle::spawn_local_on_worker to make it there"
),
));
}
ensure_shard()?;
Ok(spawn_here(future, true))
}
pub(crate) fn try_spawn_blocking<F, T>(worker: Option<usize>, f: F) -> io::Result<Task<T>>
where
F: FnOnce() -> T + Send + 'static,
T: Send + 'static,
{
if let Some(worker) = worker {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!(
"the blocking pool runs no worker, so a blocking call cannot go to worker \
{worker}: spawn it without one"
),
));
}
Ok(try_current()?.pool.spawn(f))
}