summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/src/utils/resource/query-cache.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/debugger/src/utils/resource/query-cache.js')
-rw-r--r--devtools/client/debugger/src/utils/resource/query-cache.js148
1 files changed, 148 insertions, 0 deletions
diff --git a/devtools/client/debugger/src/utils/resource/query-cache.js b/devtools/client/debugger/src/utils/resource/query-cache.js
new file mode 100644
index 0000000000..6fa8c922ad
--- /dev/null
+++ b/devtools/client/debugger/src/utils/resource/query-cache.js
@@ -0,0 +1,148 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
+
+// @flow
+
+import type { ResourceBound, ResourceState } from "./core";
+import type {
+ ResourceQuery,
+ QueryCacheHandler,
+ QueryContext,
+ QueryResult,
+} from "./base-query";
+import { strictEqual, shallowEqual } from "./compare";
+
+export type WeakArgsBound =
+ | $ReadOnly<{ [string]: mixed }>
+ | $ReadOnlyArray<mixed>;
+
+export type ShallowArgsBound =
+ | $ReadOnly<{ [string]: mixed }>
+ | $ReadOnlyArray<mixed>;
+
+/**
+ * A query 'cache' function that uses the identity of the arguments object to
+ * cache data for the query itself.
+ */
+export function queryCacheWeak<
+ R: ResourceBound,
+ Args: WeakArgsBound,
+ Mapped,
+ Reduced
+>(
+ handler: QueryCacheHandler<R, Args, Mapped, Reduced>
+): ResourceQuery<R, Args, Reduced> {
+ const cache = new WeakMap();
+ return makeCacheFunction({
+ handler,
+ // The WeakMap will only return entries for the exact object,
+ // so there is no need to compare at all.
+ compareArgs: () => true,
+ getEntry: args => cache.get(args) || null,
+ setEntry: (args, entry) => {
+ cache.set(args, entry);
+ },
+ });
+}
+
+/**
+ * A query 'cache' function that uses shallow comparison to cache the most
+ * recent calculated result based on the value of the argument.
+ */
+export function queryCacheShallow<
+ R: ResourceBound,
+ // We require args to be an object here because if you're using a primitive
+ // then you should be using queryCacheStrict instead.
+ Args: ShallowArgsBound,
+ Mapped,
+ Reduced
+>(
+ handler: QueryCacheHandler<R, Args, Mapped, Reduced>
+): ResourceQuery<R, Args, Reduced> {
+ let latestEntry = null;
+ return makeCacheFunction({
+ handler,
+ compareArgs: shallowEqual,
+ getEntry: () => latestEntry,
+ setEntry: (args, entry) => {
+ latestEntry = entry;
+ },
+ });
+}
+
+/**
+ * A query 'cache' function that uses strict comparison to cache the most
+ * recent calculated result based on the value of the argument.
+ */
+export function queryCacheStrict<R: ResourceBound, Args, Mapped, Reduced>(
+ handler: QueryCacheHandler<R, Args, Mapped, Reduced>
+): ResourceQuery<R, Args, Reduced> {
+ let latestEntry = null;
+ return makeCacheFunction({
+ handler,
+ compareArgs: strictEqual,
+ getEntry: () => latestEntry,
+ setEntry: (args, entry) => {
+ latestEntry = entry;
+ },
+ });
+}
+
+type CacheEntry<R: ResourceBound, Args, Mapped, Reduced> = {
+ context: QueryContext<Args>,
+ state: ResourceState<R>,
+ result: QueryResult<Mapped, Reduced>,
+};
+
+type CacheFunctionInfo<R: ResourceBound, Args, Mapped, Reduced> = {|
+ // The handler to call when the args or the state are different from
+ // those in the entry for the arguments.
+ handler: QueryCacheHandler<R, Args, Mapped, Reduced>,
+
+ // Compare two sets of arguments to decide whether or not they should be
+ // treated as the same set of arguments from the standpoint of caching.
+ compareArgs: (a: Args, b: Args) => boolean,
+
+ getEntry: (args: Args) => CacheEntry<R, Args, Mapped, Reduced> | null,
+ setEntry: (args: Args, entry: CacheEntry<R, Args, Mapped, Reduced>) => void,
+|};
+function makeCacheFunction<R: ResourceBound, Args, Mapped, Reduced>(
+ info: CacheFunctionInfo<R, Args, Mapped, Reduced>
+): ResourceQuery<R, Args, Reduced> {
+ const { handler, compareArgs, getEntry, setEntry } = info;
+
+ return (state, args: Args) => {
+ let entry = getEntry(args);
+
+ const sameArgs = !!entry && compareArgs(entry.context.args, args);
+ const sameState = !!entry && entry.state === state;
+
+ if (!entry || !sameArgs || !sameState) {
+ const context =
+ !entry || !sameArgs
+ ? {
+ args,
+ identMap: new WeakMap(),
+ }
+ : entry.context;
+
+ const result = handler(state, context, entry ? entry.result : null);
+
+ if (entry) {
+ entry.context = context;
+ entry.state = state;
+ entry.result = result;
+ } else {
+ entry = {
+ context,
+ state,
+ result,
+ };
+ setEntry(args, entry);
+ }
+ }
+
+ return entry.result.reduced;
+ };
+}