![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/lavocat.quebec/private_html/node_modules/effect/src/ |
/**
* @since 2.0.0
*/
import type { Effect } from "./Effect.js"
import type { RuntimeFiber } from "./Fiber.js"
import type { FiberRef } from "./FiberRef.js"
import { dual } from "./Function.js"
import { globalValue } from "./GlobalValue.js"
import * as core from "./internal/core.js"
/**
* @since 2.0.0
* @category models
*/
export type Task = () => void
/**
* @since 2.0.0
* @category models
*/
export interface Scheduler {
shouldYield(fiber: RuntimeFiber<unknown, unknown>): number | false
scheduleTask(task: Task, priority: number): void
}
/**
* @since 2.0.0
* @category utils
*/
export class PriorityBuckets<in out T = Task> {
/**
* @since 2.0.0
*/
public buckets: Array<[number, Array<T>]> = []
/**
* @since 2.0.0
*/
scheduleTask(task: T, priority: number) {
const length = this.buckets.length
let bucket: [number, Array<T>] | undefined = undefined
let index = 0
for (; index < length; index++) {
if (this.buckets[index][0] <= priority) {
bucket = this.buckets[index]
} else {
break
}
}
if (bucket && bucket[0] === priority) {
bucket[1].push(task)
} else if (index === length) {
this.buckets.push([priority, [task]])
} else {
this.buckets.splice(index, 0, [priority, [task]])
}
}
}
/**
* @since 2.0.0
* @category constructors
*/
export class MixedScheduler implements Scheduler {
/**
* @since 2.0.0
*/
running = false
/**
* @since 2.0.0
*/
tasks = new PriorityBuckets()
constructor(
/**
* @since 2.0.0
*/
readonly maxNextTickBeforeTimer: number
) {}
/**
* @since 2.0.0
*/
private starveInternal(depth: number) {
const tasks = this.tasks.buckets
this.tasks.buckets = []
for (const [_, toRun] of tasks) {
for (let i = 0; i < toRun.length; i++) {
toRun[i]()
}
}
if (this.tasks.buckets.length === 0) {
this.running = false
} else {
this.starve(depth)
}
}
/**
* @since 2.0.0
*/
private starve(depth = 0) {
if (depth >= this.maxNextTickBeforeTimer) {
setTimeout(() => this.starveInternal(0), 0)
} else {
Promise.resolve(void 0).then(() => this.starveInternal(depth + 1))
}
}
/**
* @since 2.0.0
*/
shouldYield(fiber: RuntimeFiber<unknown, unknown>): number | false {
return fiber.currentOpCount > fiber.getFiberRef(core.currentMaxOpsBeforeYield)
? fiber.getFiberRef(core.currentSchedulingPriority)
: false
}
/**
* @since 2.0.0
*/
scheduleTask(task: Task, priority: number) {
this.tasks.scheduleTask(task, priority)
if (!this.running) {
this.running = true
this.starve()
}
}
}
/**
* @since 2.0.0
* @category schedulers
*/
export const defaultScheduler: Scheduler = globalValue(
Symbol.for("effect/Scheduler/defaultScheduler"),
() => new MixedScheduler(2048)
)
/**
* @since 2.0.0
* @category constructors
*/
export class SyncScheduler implements Scheduler {
/**
* @since 2.0.0
*/
tasks = new PriorityBuckets()
/**
* @since 2.0.0
*/
deferred = false
/**
* @since 2.0.0
*/
scheduleTask(task: Task, priority: number) {
if (this.deferred) {
defaultScheduler.scheduleTask(task, priority)
} else {
this.tasks.scheduleTask(task, priority)
}
}
/**
* @since 2.0.0
*/
shouldYield(fiber: RuntimeFiber<unknown, unknown>): number | false {
return fiber.currentOpCount > fiber.getFiberRef(core.currentMaxOpsBeforeYield)
? fiber.getFiberRef(core.currentSchedulingPriority)
: false
}
/**
* @since 2.0.0
*/
flush() {
while (this.tasks.buckets.length > 0) {
const tasks = this.tasks.buckets
this.tasks.buckets = []
for (const [_, toRun] of tasks) {
for (let i = 0; i < toRun.length; i++) {
toRun[i]()
}
}
}
this.deferred = true
}
}
/**
* @since 2.0.0
* @category constructors
*/
export class ControlledScheduler implements Scheduler {
/**
* @since 2.0.0
*/
tasks = new PriorityBuckets()
/**
* @since 2.0.0
*/
deferred = false
/**
* @since 2.0.0
*/
scheduleTask(task: Task, priority: number) {
if (this.deferred) {
defaultScheduler.scheduleTask(task, priority)
} else {
this.tasks.scheduleTask(task, priority)
}
}
/**
* @since 2.0.0
*/
shouldYield(fiber: RuntimeFiber<unknown, unknown>): number | false {
return fiber.currentOpCount > fiber.getFiberRef(core.currentMaxOpsBeforeYield)
? fiber.getFiberRef(core.currentSchedulingPriority)
: false
}
/**
* @since 2.0.0
*/
step() {
const tasks = this.tasks.buckets
this.tasks.buckets = []
for (const [_, toRun] of tasks) {
for (let i = 0; i < toRun.length; i++) {
toRun[i]()
}
}
}
}
/**
* @since 2.0.0
* @category constructors
*/
export const makeMatrix = (...record: Array<[number, Scheduler]>): Scheduler => {
const index = record.sort(([p0], [p1]) => p0 < p1 ? -1 : p0 > p1 ? 1 : 0)
return {
shouldYield(fiber) {
for (const scheduler of record) {
const priority = scheduler[1].shouldYield(fiber)
if (priority !== false) {
return priority
}
}
return false
},
scheduleTask(task, priority) {
let scheduler: Scheduler | undefined = undefined
for (const i of index) {
if (priority >= i[0]) {
scheduler = i[1]
} else {
return (scheduler ?? defaultScheduler).scheduleTask(task, priority)
}
}
return (scheduler ?? defaultScheduler).scheduleTask(task, priority)
}
}
}
/**
* @since 2.0.0
* @category utilities
*/
export const defaultShouldYield: Scheduler["shouldYield"] = (fiber) => {
return fiber.currentOpCount > fiber.getFiberRef(core.currentMaxOpsBeforeYield)
? fiber.getFiberRef(core.currentSchedulingPriority)
: false
}
/**
* @since 2.0.0
* @category constructors
*/
export const make = (
scheduleTask: Scheduler["scheduleTask"],
shouldYield: Scheduler["shouldYield"] = defaultShouldYield
): Scheduler => ({
scheduleTask,
shouldYield
})
/**
* @since 2.0.0
* @category constructors
*/
export const makeBatched = (
callback: (runBatch: () => void) => void,
shouldYield: Scheduler["shouldYield"] = defaultShouldYield
) => {
let running = false
const tasks = new PriorityBuckets()
const starveInternal = () => {
const tasksToRun = tasks.buckets
tasks.buckets = []
for (const [_, toRun] of tasksToRun) {
for (let i = 0; i < toRun.length; i++) {
toRun[i]()
}
}
if (tasks.buckets.length === 0) {
running = false
} else {
starve()
}
}
const starve = () => callback(starveInternal)
return make((task, priority) => {
tasks.scheduleTask(task, priority)
if (!running) {
running = true
starve()
}
}, shouldYield)
}
/**
* @since 2.0.0
* @category constructors
*/
export const timer = (ms: number, shouldYield: Scheduler["shouldYield"] = defaultShouldYield) =>
make((task) => setTimeout(task, ms), shouldYield)
/**
* @since 2.0.0
* @category constructors
*/
export const timerBatched = (ms: number, shouldYield: Scheduler["shouldYield"] = defaultShouldYield) =>
makeBatched((task) => setTimeout(task, ms), shouldYield)
/** @internal */
export const currentScheduler: FiberRef<Scheduler> = globalValue(
Symbol.for("effect/FiberRef/currentScheduler"),
() => core.fiberRefUnsafeMake(defaultScheduler)
)
/** @internal */
export const withScheduler = dual<
/** @internal */
(scheduler: Scheduler) => <A, E, R>(self: Effect<A, E, R>) => Effect<A, E, R>,
/** @internal */
<A, E, R>(self: Effect<A, E, R>, scheduler: Scheduler) => Effect<A, E, R>
>(2, (self, scheduler) => core.fiberRefLocally(self, currentScheduler, scheduler))