import type {ReactContext} from 'shared/ReactTypes';
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
import {enableCache} from 'shared/ReactFeatureFlags';
import {REACT_CONTEXT_TYPE} from 'shared/ReactSymbols';
import {pushProvider, popProvider} from './ReactFiberNewContext';
import * as Scheduler from 'scheduler';
const AbortControllerLocal: typeof AbortController = enableCache
? typeof AbortController !== 'undefined'
? AbortController
:
function AbortControllerShim() {
const listeners = [];
const signal = (this.signal = {
aborted: false,
addEventListener: (type, listener) => {
listeners.push(listener);
},
});
this.abort = () => {
signal.aborted = true;
listeners.forEach(listener => listener());
};
}
:
null;
export type Cache = {
controller: AbortController,
data: Map<() => mixed, mixed>,
refCount: number,
};
export type CacheComponentState = {
+parent: Cache,
+cache: Cache,
};
export type SpawnedCachePool = {
+parent: Cache,
+pool: Cache,
};
const {
unstable_scheduleCallback: scheduleCallback,
unstable_NormalPriority: NormalPriority,
} = Scheduler;
export const CacheContext: ReactContext<Cache> = enableCache
? {
$$typeof: REACT_CONTEXT_TYPE,
Consumer: (null: any),
Provider: (null: any),
_currentValue: (null: any),
_currentValue2: (null: any),
_threadCount: 0,
}
: (null: any);
if (__DEV__ && enableCache) {
CacheContext._currentRenderer = null;
CacheContext._currentRenderer2 = null;
}
export function createCache(): Cache {
if (!enableCache) {
return (null: any);
}
const cache: Cache = {
controller: new AbortControllerLocal(),
data: new Map(),
refCount: 0,
};
return cache;
}
export function retainCache(cache: Cache) {
if (!enableCache) {
return;
}
if (__DEV__) {
if (cache.controller.signal.aborted) {
console.warn(
'A cache instance was retained after it was already freed. ' +
'This likely indicates a bug in React.',
);
}
}
cache.refCount++;
}
export function releaseCache(cache: Cache) {
if (!enableCache) {
return;
}
cache.refCount--;
if (__DEV__) {
if (cache.refCount < 0) {
console.warn(
'A cache instance was released after it was already freed. ' +
'This likely indicates a bug in React.',
);
}
}
if (cache.refCount === 0) {
scheduleCallback(NormalPriority, () => {
cache.controller.abort();
});
}
}
export function pushCacheProvider(workInProgress: Fiber, cache: Cache) {
if (!enableCache) {
return;
}
pushProvider(workInProgress, CacheContext, cache);
}
export function popCacheProvider(workInProgress: Fiber, cache: Cache) {
if (!enableCache) {
return;
}
popProvider(CacheContext, workInProgress);
}