use crate::ManagedTask;
use bun_threading::UnboundedQueue;
use bun_threading::unbounded_queue::{Link, Linked};
#[inline]
pub fn create(task: Task) -> core::ptr::NonNull<ConcurrentTask> {
ConcurrentTask::create(task)
}
#[inline]
pub fn create_from<T: Taskable>(task: *mut T) -> core::ptr::NonNull<ConcurrentTask> {
ConcurrentTask::create_from(task)
}
#[inline]
pub fn from_callback<T>(
ptr: *mut T,
callback: fn(*mut T) -> crate::JsResult<()>,
) -> core::ptr::NonNull<ConcurrentTask> {
ConcurrentTask::from_callback(ptr, callback)
}
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct TaskTag(pub u8);
#[allow(non_upper_case_globals)]
pub mod task_tag {
use super::TaskTag;
macro_rules! tags {
($($name:ident),* $(,)?) => {
tags!(@ 0u8, $($name,)*);
pub const COUNT: u8 = tags!(@count 0u8, $($name,)*);
};
(@ $n:expr, $head:ident, $($rest:ident,)*) => {
pub const $head: TaskTag = TaskTag($n);
tags!(@ $n + 1u8, $($rest,)*);
};
(@ $n:expr,) => {};
(@count $n:expr, $head:ident, $($rest:ident,)*) => { tags!(@count $n + 1u8, $($rest,)*) };
(@count $n:expr,) => { $n };
}
tags! {
Access,
AnyTask,
AppendFile,
ArchiveExtractTask,
ArchiveBlobTask,
ArchiveWriteTask,
ArchiveFilesTask,
AsyncGlobWalkTask,
AsyncImageTask,
AsyncTransformTask,
BakeHotReloadEvent, BundleV2DeferredBatchTask, ShellYesTask, Chmod,
Chown,
Close,
CopyFile,
CopyFilePromiseTask,
CppTask,
Exists,
Fchmod,
FChown,
Fdatasync,
FetchTasklet,
Fstat,
FSWatchTask,
Fsync,
FTruncate,
Futimes,
GetAddrInfoRequestTask,
HotReloadTask,
ImmediateObject,
JSCDeferredWorkTask,
Lchmod,
Lchown,
Link,
Lstat,
Lutimes,
ManagedTask,
Mkdir,
Mkdtemp,
NapiAsyncWork, NapiFinalizerTask,
NativePromiseContextDeferredDerefTask,
NativeBrotli,
NativeZlib,
NativeZstd,
Open,
PollPendingModulesTask,
PosixSignalTask,
ProcessWaiterThreadTask,
Read,
Readdir,
ReaddirRecursive,
ReadFile,
ReadFileTask,
Readlink,
Readv,
FlushPendingFileSinkTask,
Realpath,
RealpathNonNative,
Rename,
Rm,
Rmdir,
RuntimeTranspilerStore,
S3HttpDownloadStreamingTask,
S3HttpSimpleTask,
ServerAllConnectionsClosedTask,
ShellAsync,
ShellAsyncSubprocessDone,
ShellCondExprStatTask,
ShellCpTask,
ShellGlobTask,
ShellIOReaderAsyncDeinit,
ShellIOWriterAsyncDeinit,
ShellIOWriter,
ShellLsTask,
ShellMkdirTask,
ShellMvBatchedTask,
ShellMvCheckTargetTask,
ShellRmDirTask,
ShellRmTask,
ShellTouchTask,
Stat,
StatFS,
StreamPending,
Symlink,
ThreadSafeFunction,
TimeoutObject,
Truncate,
Unlink,
Utimes,
Write,
WriteFile,
WriteFileTask,
Writev,
}
}
#[derive(Copy, Clone)]
pub struct Task {
pub tag: TaskTag,
pub ptr: *mut (),
}
pub trait Taskable {
const TAG: TaskTag;
#[inline]
fn into_task(ptr: *mut Self) -> Task {
Task::new(Self::TAG, ptr.cast::<()>())
}
}
impl Task {
#[inline]
pub const fn new(tag: TaskTag, ptr: *mut ()) -> Task {
Task { tag, ptr }
}
#[inline]
pub fn init<T: Taskable>(ptr: *mut T) -> Task {
Task::new(T::TAG, ptr.cast::<()>())
}
#[inline]
pub fn from_boxed<T: Taskable>(task: Box<T>) -> Task {
Task::new(T::TAG, bun_core::heap::into_raw(task).cast::<()>())
}
#[inline]
pub fn init_with_type<T: Taskable>(ptr: *mut ()) -> Task {
Task::new(T::TAG, ptr)
}
}
impl Taskable for crate::AnyTask::AnyTask {
const TAG: TaskTag = task_tag::AnyTask;
}
impl Taskable for crate::ManagedTask::ManagedTask {
const TAG: TaskTag = task_tag::ManagedTask;
}
#[repr(C)]
pub struct ConcurrentTask {
pub task: Task,
pub next: Link<ConcurrentTask>,
pub auto_delete: bool,
}
impl Default for ConcurrentTask {
fn default() -> Self {
Self {
task: unsafe { bun_core::ffi::zeroed_unchecked() },
next: Link::new(),
auto_delete: false,
}
}
}
const _: () = assert!(
core::mem::size_of::<ConcurrentTask>()
== core::mem::size_of::<Task>() + 2 * core::mem::size_of::<usize>(),
"ConcurrentTask = Task + next ptr + auto_delete (padded)"
);
unsafe impl Linked for ConcurrentTask {
#[inline]
unsafe fn link(item: *mut Self) -> *const Link<Self> {
unsafe { core::ptr::addr_of!((*item).next) }
}
}
pub type Queue = UnboundedQueue<ConcurrentTask>;
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum AutoDeinit {
ManualDeinit,
AutoDeinit,
}
impl ConcurrentTask {
#[inline]
pub fn new(init: ConcurrentTask) -> *mut ConcurrentTask {
bun_core::heap::into_raw(Box::new(init))
}
#[inline]
pub unsafe fn destroy(this: *mut ConcurrentTask) {
drop(unsafe { bun_core::heap::take(this) });
}
pub fn create(task: Task) -> core::ptr::NonNull<ConcurrentTask> {
let raw = ConcurrentTask::new(ConcurrentTask {
task,
next: Link::new(),
auto_delete: true,
});
unsafe { core::ptr::NonNull::new_unchecked(raw) }
}
pub fn create_from<T: Taskable>(task: *mut T) -> core::ptr::NonNull<ConcurrentTask> {
Self::create(Task::init(task))
}
#[inline]
pub fn create_boxed<T: Taskable>(task: Box<T>) -> core::ptr::NonNull<ConcurrentTask> {
Self::create(Task::from_boxed(task))
}
pub fn from_callback<T>(
ptr: *mut T,
callback: fn(*mut T) -> crate::JsResult<()>,
) -> core::ptr::NonNull<ConcurrentTask> {
Self::create(ManagedTask::ManagedTask::new(ptr, callback))
}
pub fn from<T: Taskable>(
&mut self,
of: *mut T,
auto_deinit: AutoDeinit,
) -> &mut ConcurrentTask {
*self = ConcurrentTask {
task: Task::init(of),
next: Link::new(),
auto_delete: auto_deinit == AutoDeinit::AutoDeinit,
};
self
}
#[inline]
pub fn auto_delete(&self) -> bool {
self.auto_delete
}
}