export const FLAG_DICT = { /** * @description 当前节点没有任何特性。 */ None: 0, /** * @description 当前节点的值是可变的。值的变化可以通过此节点继续传递。 */ Mutable: 1, /** * @description 当前节点的值可能发生了变化,待确定。 */ Pending: 2, /** * @description 当前节点的值发生了变化。 */ Dirty: 4, /** * @description 当前节点正在进行观察。当上游节点的值发生变化时应该通知当前节点。 */ Watching: 8, /** * @description 当前节点正在进行依赖收集。 * * 目前只考虑到以下用途: * * 1. 用于防止在某节点依赖收集过程中依赖发生变化导致该节点重复运行。 * * ``` * const count = signal(0) * effect(() => { * count(count() + 1) * }) * ``` */ Tracking: 16, /** * @description 当前节点正在进行依赖收集,且正在尝试复用现存连接。 */ TrackingReusing: 32, } as const export const hasMutable = (flags: number): boolean => { return (flags & FLAG_DICT.Mutable) !== 0 } export const setMutable = (flags?: number | undefined): number => { return flags === undefined ? FLAG_DICT.Mutable : flags | FLAG_DICT.Mutable } export const unsetMutable = (flags: number): number => { return flags & ~FLAG_DICT.Mutable } export const toggleMutable = (flags: number): number => { return flags ^ FLAG_DICT.Mutable } export const hasDirty = (flags: number): boolean => { return (flags & FLAG_DICT.Dirty) !== 0 } export const setDirty = (flags?: number | undefined): number => { return flags === undefined ? FLAG_DICT.Dirty : flags | FLAG_DICT.Dirty } export const unsetDirty = (flags: number): number => { return flags & ~FLAG_DICT.Dirty } export const toggleDirty = (flags: number): number => { return flags ^ FLAG_DICT.Dirty } export const hasPending = (flags: number): boolean => { return (flags & FLAG_DICT.Pending) !== 0 } export const setPending = (flags?: number | undefined): number => { return flags === undefined ? FLAG_DICT.Pending : flags | FLAG_DICT.Pending } export const unsetPending = (flags: number): number => { return flags & ~FLAG_DICT.Pending } export const togglePending = (flags: number): number => { return flags ^ FLAG_DICT.Pending } export const hasWatching = (flags: number): boolean => { return (flags & FLAG_DICT.Watching) !== 0 } export const setWatching = (flags?: number | undefined): number => { return flags === undefined ? FLAG_DICT.Watching : flags | FLAG_DICT.Watching } export const unsetWatching = (flags: number): number => { return flags & ~FLAG_DICT.Watching } export const toggleWatching = (flags: number): number => { return flags ^ FLAG_DICT.Watching } export const hasTracking = (flags: number): boolean => { return (flags & FLAG_DICT.Tracking) !== 0 } export const setTracking = (flags?: number | undefined): number => { return flags === undefined ? FLAG_DICT.Tracking : flags | FLAG_DICT.Tracking } export const unsetTracking = (flags: number): number => { return flags & ~FLAG_DICT.Tracking } export const toggleTracking = (flags: number): number => { return flags ^ FLAG_DICT.Tracking } export const hasTrackingReusing = (flags: number): boolean => { return (flags & FLAG_DICT.TrackingReusing) !== 0 } export const setTrackingReusing = (flags?: number): number => { return flags === undefined ? FLAG_DICT.TrackingReusing : flags | FLAG_DICT.TrackingReusing } export const unsetTrackingReusing = (flags: number): number => { return flags & ~FLAG_DICT.TrackingReusing } export const toggleTrackingReusing = (flags: number): number => { return flags ^ FLAG_DICT.TrackingReusing } export class Flags { private flags: number constructor() { this.flags = FLAG_DICT.None } static clone(flags: Flags): Flags { const newFlags = new Flags() newFlags.set(flags.get()) return newFlags } get(): number { return this.flags } set(flags: number): this { this.flags = flags return this } clear(): this { this.flags = FLAG_DICT.None return this } hasMutable(): boolean { return hasMutable(this.flags) } setMutable(): this { this.flags = setMutable(this.flags) return this } unsetMutable(): this { this.flags = unsetMutable(this.flags) return this } toggleMutable(): this { this.flags = toggleMutable(this.flags) return this } hasDirty(): boolean { return hasDirty(this.flags) } setDirty(): this { this.flags = setDirty(this.flags) return this } unsetDirty(): this { this.flags = unsetDirty(this.flags) return this } toggleDirty(): this { this.flags = toggleDirty(this.flags) return this } hasPending(): boolean { return hasPending(this.flags) } setPending(): this { this.flags = setPending(this.flags) return this } unsetPending(): this { this.flags = unsetPending(this.flags) return this } togglePending(): this { this.flags = togglePending(this.flags) return this } hasWatching(): boolean { return hasWatching(this.flags) } setWatching(): this { this.flags = setWatching(this.flags) return this } unsetWatching(): this { this.flags = unsetWatching(this.flags) return this } toggleWatching(): this { this.flags = toggleWatching(this.flags) return this } hasTracking(): boolean { return hasTracking(this.flags) } setTracking(): this { this.flags = setTracking(this.flags) return this } unsetTracking(): this { this.flags = unsetTracking(this.flags) return this } toggleTracking(): this { this.flags = toggleTracking(this.flags) return this } hasTrackingReusing(): boolean { return hasTrackingReusing(this.flags) } setTrackingReusing(): this { this.flags = setTrackingReusing(this.flags) return this } unsetTrackingReusing(): this { this.flags = unsetTrackingReusing(this.flags) return this } toggleTrackingReusing(): this { this.flags = toggleTrackingReusing(this.flags) return this } toString(): string { if (this.flags === FLAG_DICT.None) { return "Flags(None)" } const activeFlags: string[] = [] if (this.hasMutable()) { activeFlags.push("Mutable") } if (this.hasPending()) { activeFlags.push("Pending") } if (this.hasDirty()) { activeFlags.push("Dirty") } if (this.hasWatching()) { activeFlags.push("Watching") } if (this.hasTracking()) { activeFlags.push("Tracking") } if (this.hasTrackingReusing()) { activeFlags.push("TrackingReusing") } return `Flags(${activeFlags.join(" | ")})` } } export const flags = (flags?: number | undefined): Flags => { const f = new Flags() if (flags !== undefined) { f.set(flags) } return f }