use std::num::NonZeroUsize;
use crate::{BatchDecision, BatchPolicy, BatchQuery, ExecError, Pool, WorkspaceProvider};
pub struct Exec<'a> {
token: threadteam::Exec<'a>,
workspace: Option<&'a dyn WorkspaceProvider>,
policy: BatchPolicy,
}
impl std::fmt::Debug for Exec<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Exec")
.field("token", &self.token)
.field("workspace", &self.workspace.is_some())
.field("policy", &self.policy)
.finish()
}
}
impl<'a> Exec<'a> {
pub fn serial() -> Exec<'static> {
Exec {
token: threadteam::Exec::serial(),
workspace: None,
policy: BatchPolicy::default(),
}
}
pub fn serial_with_workspace(workspace: &'a dyn WorkspaceProvider) -> Self {
Exec {
token: threadteam::Exec::serial(),
workspace: Some(workspace),
policy: BatchPolicy::default(),
}
}
pub fn new(pool: &'a Pool<'_>, budget: usize) -> Result<Self, ExecError> {
Ok(Exec {
token: threadteam::Exec::new(pool.inner(), budget)?,
workspace: Some(pool.workspace()),
policy: BatchPolicy::default(),
})
}
pub fn from_token(
token: threadteam::Exec<'a>,
workspace: Option<&'a dyn WorkspaceProvider>,
policy: BatchPolicy,
) -> Self {
Exec {
token,
workspace,
policy,
}
}
pub fn token(&mut self) -> threadteam::Exec<'_> {
self.token.reborrow()
}
pub fn into_token(self) -> threadteam::Exec<'a> {
self.token
}
pub fn reborrow(&mut self) -> Exec<'_> {
Exec {
token: self.token.reborrow(),
workspace: self.workspace,
policy: self.policy,
}
}
#[must_use]
pub fn limit(self, max: NonZeroUsize) -> Self {
Exec {
token: self.token.limit(max),
workspace: self.workspace,
policy: self.policy,
}
}
pub fn batch_policy(&self) -> &BatchPolicy {
&self.policy
}
#[must_use]
pub fn with_batch_policy(mut self, policy: BatchPolicy) -> Self {
self.policy = policy;
self
}
pub fn batch_decision(&self, query: &BatchQuery) -> BatchDecision {
crate::batch::batch_decision(&self.policy, self, query)
}
pub fn budget(&self) -> usize {
self.token.budget().get()
}
pub fn workspace(&self) -> Option<&'a dyn WorkspaceProvider> {
self.workspace
}
pub fn token_ref(&self) -> &threadteam::Exec<'a> {
&self.token
}
pub fn width_for(&self, serial_ns: f64, sections: u32) -> usize {
self.token.width_for(ns_duration(serial_ns), sections).get()
}
pub fn width_for_within(&self, budget: usize, serial_ns: f64, sections: u32) -> usize {
let budget = NonZeroUsize::new(budget.max(1))
.unwrap_or(NonZeroUsize::MIN)
.min(self.token.budget());
threadteam::width_for_by(ns_duration(serial_ns), sections, budget, |k| {
self.token.dispatch_cost(k)
})
.get()
}
pub fn pays(&self, serial_ns: f64, sections: u32, width: usize) -> bool {
let width = NonZeroUsize::new(width).unwrap_or(NonZeroUsize::MIN);
self.token.pays(ns_duration(serial_ns), sections, width)
}
}
fn ns_duration(ns: f64) -> std::time::Duration {
if ns.is_nan() || ns <= 0.0 {
std::time::Duration::ZERO
} else if ns >= 1e18 {
std::time::Duration::from_secs(u64::MAX / 4)
} else {
std::time::Duration::from_secs_f64(ns * 1e-9)
}
}