mirror of https://github.com/ghostfolio/ghostfolio
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
267 lines
6.7 KiB
267 lines
6.7 KiB
import * as Equal from "../Equal.js"
|
|
import type * as FiberId from "../FiberId.js"
|
|
import { dual, pipe } from "../Function.js"
|
|
import { globalValue } from "../GlobalValue.js"
|
|
import * as Hash from "../Hash.js"
|
|
import * as HashSet from "../HashSet.js"
|
|
import { format, NodeInspectSymbol, toJSON } from "../Inspectable.js"
|
|
import * as MutableRef from "../MutableRef.js"
|
|
import * as Option from "../Option.js"
|
|
import { hasProperty } from "../Predicate.js"
|
|
|
|
/** @internal */
|
|
const FiberIdSymbolKey = "effect/FiberId"
|
|
|
|
/** @internal */
|
|
export const FiberIdTypeId: FiberId.FiberIdTypeId = Symbol.for(
|
|
FiberIdSymbolKey
|
|
) as FiberId.FiberIdTypeId
|
|
|
|
/** @internal */
|
|
const OP_NONE = "None" as const
|
|
|
|
/** @internal */
|
|
export type OP_NONE = typeof OP_NONE
|
|
|
|
/** @internal */
|
|
const OP_RUNTIME = "Runtime" as const
|
|
|
|
/** @internal */
|
|
export type OP_RUNTIME = typeof OP_RUNTIME
|
|
|
|
/** @internal */
|
|
const OP_COMPOSITE = "Composite" as const
|
|
|
|
/** @internal */
|
|
export type OP_COMPOSITE = typeof OP_COMPOSITE
|
|
|
|
const emptyHash = Hash.string(`${FiberIdSymbolKey}-${OP_NONE}`)
|
|
|
|
/** @internal */
|
|
class None implements FiberId.None {
|
|
readonly [FiberIdTypeId]: FiberId.FiberIdTypeId = FiberIdTypeId
|
|
readonly _tag = OP_NONE
|
|
readonly id = -1
|
|
readonly startTimeMillis = -1;
|
|
[Hash.symbol](): number {
|
|
return emptyHash
|
|
}
|
|
[Equal.symbol](that: unknown): boolean {
|
|
return isFiberId(that) && that._tag === OP_NONE
|
|
}
|
|
toString() {
|
|
return format(this.toJSON())
|
|
}
|
|
toJSON() {
|
|
return {
|
|
_id: "FiberId",
|
|
_tag: this._tag
|
|
}
|
|
}
|
|
[NodeInspectSymbol]() {
|
|
return this.toJSON()
|
|
}
|
|
}
|
|
|
|
/** @internal */
|
|
class Runtime implements FiberId.Runtime {
|
|
readonly [FiberIdTypeId]: FiberId.FiberIdTypeId = FiberIdTypeId
|
|
readonly _tag = OP_RUNTIME
|
|
constructor(
|
|
readonly id: number,
|
|
readonly startTimeMillis: number
|
|
) {}
|
|
[Hash.symbol](): number {
|
|
return Hash.cached(this, Hash.string(`${FiberIdSymbolKey}-${this._tag}-${this.id}-${this.startTimeMillis}`))
|
|
}
|
|
[Equal.symbol](that: unknown): boolean {
|
|
return isFiberId(that) &&
|
|
that._tag === OP_RUNTIME &&
|
|
this.id === that.id &&
|
|
this.startTimeMillis === that.startTimeMillis
|
|
}
|
|
toString() {
|
|
return format(this.toJSON())
|
|
}
|
|
toJSON() {
|
|
return {
|
|
_id: "FiberId",
|
|
_tag: this._tag,
|
|
id: this.id,
|
|
startTimeMillis: this.startTimeMillis
|
|
}
|
|
}
|
|
[NodeInspectSymbol]() {
|
|
return this.toJSON()
|
|
}
|
|
}
|
|
|
|
/** @internal */
|
|
class Composite implements FiberId.Composite {
|
|
readonly [FiberIdTypeId]: FiberId.FiberIdTypeId = FiberIdTypeId
|
|
readonly _tag = OP_COMPOSITE
|
|
constructor(
|
|
readonly left: FiberId.FiberId,
|
|
readonly right: FiberId.FiberId
|
|
) {
|
|
}
|
|
_hash: number | undefined;
|
|
[Hash.symbol](): number {
|
|
return pipe(
|
|
Hash.string(`${FiberIdSymbolKey}-${this._tag}`),
|
|
Hash.combine(Hash.hash(this.left)),
|
|
Hash.combine(Hash.hash(this.right)),
|
|
Hash.cached(this)
|
|
)
|
|
}
|
|
[Equal.symbol](that: unknown): boolean {
|
|
return isFiberId(that) &&
|
|
that._tag === OP_COMPOSITE &&
|
|
Equal.equals(this.left, that.left) &&
|
|
Equal.equals(this.right, that.right)
|
|
}
|
|
toString() {
|
|
return format(this.toJSON())
|
|
}
|
|
toJSON() {
|
|
return {
|
|
_id: "FiberId",
|
|
_tag: this._tag,
|
|
left: toJSON(this.left),
|
|
right: toJSON(this.right)
|
|
}
|
|
}
|
|
[NodeInspectSymbol]() {
|
|
return this.toJSON()
|
|
}
|
|
}
|
|
|
|
/** @internal */
|
|
export const none: FiberId.None = new None()
|
|
|
|
/** @internal */
|
|
export const runtime = (id: number, startTimeMillis: number): FiberId.Runtime => {
|
|
return new Runtime(id, startTimeMillis)
|
|
}
|
|
|
|
/** @internal */
|
|
export const composite = (left: FiberId.FiberId, right: FiberId.FiberId): FiberId.Composite => {
|
|
return new Composite(left, right)
|
|
}
|
|
|
|
/** @internal */
|
|
export const isFiberId = (self: unknown): self is FiberId.FiberId => hasProperty(self, FiberIdTypeId)
|
|
|
|
/** @internal */
|
|
export const isNone = (self: FiberId.FiberId): self is FiberId.None => {
|
|
return self._tag === OP_NONE || pipe(toSet(self), HashSet.every((id) => isNone(id)))
|
|
}
|
|
|
|
/** @internal */
|
|
export const isRuntime = (self: FiberId.FiberId): self is FiberId.Runtime => {
|
|
return self._tag === OP_RUNTIME
|
|
}
|
|
|
|
/** @internal */
|
|
export const isComposite = (self: FiberId.FiberId): self is FiberId.Composite => {
|
|
return self._tag === OP_COMPOSITE
|
|
}
|
|
|
|
/** @internal */
|
|
export const combine = dual<
|
|
(that: FiberId.FiberId) => (self: FiberId.FiberId) => FiberId.FiberId,
|
|
(self: FiberId.FiberId, that: FiberId.FiberId) => FiberId.FiberId
|
|
>(2, (self, that) => {
|
|
if (self._tag === OP_NONE) {
|
|
return that
|
|
}
|
|
if (that._tag === OP_NONE) {
|
|
return self
|
|
}
|
|
return new Composite(self, that)
|
|
})
|
|
|
|
/** @internal */
|
|
export const combineAll = (fiberIds: HashSet.HashSet<FiberId.FiberId>): FiberId.FiberId => {
|
|
return pipe(fiberIds, HashSet.reduce(none as FiberId.FiberId, (a, b) => combine(b)(a)))
|
|
}
|
|
|
|
/** @internal */
|
|
export const getOrElse = dual<
|
|
(that: FiberId.FiberId) => (self: FiberId.FiberId) => FiberId.FiberId,
|
|
(self: FiberId.FiberId, that: FiberId.FiberId) => FiberId.FiberId
|
|
>(2, (self, that) => isNone(self) ? that : self)
|
|
|
|
/** @internal */
|
|
export const ids = (self: FiberId.FiberId): HashSet.HashSet<number> => {
|
|
switch (self._tag) {
|
|
case OP_NONE: {
|
|
return HashSet.empty()
|
|
}
|
|
case OP_RUNTIME: {
|
|
return HashSet.make(self.id)
|
|
}
|
|
case OP_COMPOSITE: {
|
|
return pipe(ids(self.left), HashSet.union(ids(self.right)))
|
|
}
|
|
}
|
|
}
|
|
|
|
const _fiberCounter = globalValue(
|
|
Symbol.for("effect/Fiber/Id/_fiberCounter"),
|
|
() => MutableRef.make(0)
|
|
)
|
|
|
|
/** @internal */
|
|
export const make = (id: number, startTimeSeconds: number): FiberId.FiberId => {
|
|
return new Runtime(id, startTimeSeconds)
|
|
}
|
|
|
|
/** @internal */
|
|
export const threadName = (self: FiberId.FiberId): string => {
|
|
const identifiers = Array.from(ids(self)).map((n) => `#${n}`).join(",")
|
|
return identifiers
|
|
}
|
|
|
|
/** @internal */
|
|
export const toOption = (self: FiberId.FiberId): Option.Option<FiberId.FiberId> => {
|
|
const fiberIds = toSet(self)
|
|
if (HashSet.size(fiberIds) === 0) {
|
|
return Option.none()
|
|
}
|
|
let first = true
|
|
let acc: FiberId.FiberId
|
|
for (const fiberId of fiberIds) {
|
|
if (first) {
|
|
acc = fiberId
|
|
first = false
|
|
} else {
|
|
// @ts-expect-error
|
|
acc = pipe(acc, combine(fiberId))
|
|
}
|
|
}
|
|
// @ts-expect-error
|
|
return Option.some(acc)
|
|
}
|
|
|
|
/** @internal */
|
|
export const toSet = (self: FiberId.FiberId): HashSet.HashSet<FiberId.Runtime> => {
|
|
switch (self._tag) {
|
|
case OP_NONE: {
|
|
return HashSet.empty()
|
|
}
|
|
case OP_RUNTIME: {
|
|
return HashSet.make(self)
|
|
}
|
|
case OP_COMPOSITE: {
|
|
return pipe(toSet(self.left), HashSet.union(toSet(self.right)))
|
|
}
|
|
}
|
|
}
|
|
|
|
/** @internal */
|
|
export const unsafeMake = (): FiberId.Runtime => {
|
|
const id = MutableRef.get(_fiberCounter)
|
|
pipe(_fiberCounter, MutableRef.set(id + 1))
|
|
return new Runtime(id, Date.now())
|
|
}
|
|
|