use observed::Sink;
#[cfg(debug_assertions)]
use observed::emit;
use thread_aware::{Thread, ThreadAware};
use tick::Clock;
use crate::runtime::dispatch::DispatcherClient;
#[cfg(debug_assertions)]
use crate::runtime::telemetry::events::{BacktraceText, BuiltinsThreadMismatch, ThreadName};
use crate::task::scheduler::Scheduler;
#[derive(Debug, Clone)]
pub struct Builtins {
pub(crate) scheduler: Scheduler,
thread: Thread,
clock: Clock,
sink: Sink,
}
impl Builtins {
#[must_use]
#[inline]
pub fn scheduler(&self) -> &Scheduler {
self.validate();
&self.scheduler
}
#[must_use]
#[inline]
pub fn thread(&self) -> &Thread {
self.validate();
&self.thread
}
#[must_use]
#[inline]
pub fn clock(&self) -> &Clock {
self.validate();
&self.clock
}
#[must_use]
#[inline]
pub fn sink(&self) -> &Sink {
self.validate();
&self.sink
}
#[cfg_attr(test, mutants::skip)]
#[cfg(debug_assertions)]
fn validate(&self) {
let thread = std::thread::current();
if thread.id() != self.thread.id() {
let backtrace = std::backtrace::Backtrace::capture();
emit!(
&self.sink,
BuiltinsThreadMismatch {
name: ThreadName::new(thread.name().unwrap_or_default()),
id: thread.id().into(),
backtrace: BacktraceText(backtrace.to_string()),
}
);
}
}
#[cfg(not(debug_assertions))]
#[cfg_attr(test, mutants::skip)]
#[expect(clippy::unused_self, reason = "Optimized away on release builds")]
#[inline(always)]
fn validate(&self) {
}
}
impl ThreadAware for Builtins {
fn relocate(&mut self, _source: Option<&Thread>, destination: &Thread) {
if self.thread == *destination {
return;
}
let Some(worker_index) = self.scheduler.resolve_worker_index(destination) else {
return;
};
let source = self.thread.clone();
self.scheduler.relocate_to_worker(destination, worker_index);
self.thread = destination.clone();
self.clock.relocate(Some(&source), destination);
self.sink.relocate(Some(&source), destination);
}
}
impl Builtins {
pub(crate) fn new(dispatcher: DispatcherClient, clock: Clock, thread: Thread, sink: Sink) -> Self {
Self {
scheduler: Scheduler::new(dispatcher, thread.clone()),
thread,
clock,
sink,
}
}
}
impl AsRef<Scheduler> for Builtins {
#[inline]
fn as_ref(&self) -> &Scheduler {
self.scheduler()
}
}
impl AsRef<Clock> for Builtins {
#[inline]
fn as_ref(&self) -> &Clock {
self.clock()
}
}
impl AsRef<Sink> for Builtins {
#[inline]
fn as_ref(&self) -> &Sink {
self.sink()
}
}