function toSelector(arg) {
    if (typeof arg === "function") {
        return arg;
    }
    if (arg instanceof ORM) {
        return arg.stateSelector;
    }
    if (arg instanceof MapSelectorSpec) {
        // the argument to map() needs to be callable
        arg.selector = toSelector(arg.selector);
    }
    if (arg instanceof SelectorSpec) {
        const { orm, cachePath } = arg;
        let level;

        // the selector cache for the spec's ORM
        if (!selectorCache.has(orm)) {
            selectorCache.set(orm, new Map());
        }
        const ormSelectors = selectorCache.get(orm);

        /**
         * Drill down into selector map by cachePath.
         *
         * The selector itself is stored under a special SELECTOR_KEY
         * so that we can store selectors below it as well.
         */
        level = ormSelectors;
        for (let i = 0; i < cachePath.length; ++i) {
            const storageKey = cachePath[i];
            if (!level.has(storageKey)) {
                level.set(storageKey, new Map());
            }
            level = level.get(storageKey);
        }
        if (level && level.has(SELECTOR_KEY)) {
            // Cache hit: the selector has been created before
            return level.get(SELECTOR_KEY);
        }
        // Cache miss: the selector needs to be created
        const selector = createSelectorFromSpec(arg);
        // Save the selector at the cachePath position
        level.set(SELECTOR_KEY, selector);

        return selector;
    }
    throw new Error(
        `Failed to interpret selector argument: ${JSON.stringify(
            arg
        )} of type ${typeof arg}`
    );
}
@private
@param {function|ORM|SelectorSpec} arg