Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REFACTOR] Split managers into multiple maps #19159

Merged
merged 1 commit into from
Sep 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions packages/@ember/-internals/glimmer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,8 +404,12 @@ export { INVOKE } from './lib/helpers/action';
export { default as OutletView } from './lib/views/outlet';
export { OutletState } from './lib/utils/outlet';
export { capabilities } from './lib/component-managers/custom';
export { setComponentManager, getComponentManager } from './lib/utils/custom-component-manager';
export { setModifierManager, getModifierManager } from './lib/utils/custom-modifier-manager';
export {
setComponentManager,
getComponentManager,
setModifierManager,
getModifierManager,
} from './lib/utils/managers';
export { capabilities as modifierCapabilities } from './lib/modifiers/custom';
export { isSerializationFirstNode } from './lib/utils/serialization-first-node-helpers';
export { setComponentTemplate, getComponentTemplate } from './lib/utils/component-template';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from '@glimmer/interfaces';
import { createConstRef, isConstRef, Reference, valueForRef } from '@glimmer/reference';
import { registerDestructor } from '@glimmer/runtime';
import { unwrapTemplate } from '@glimmer/util';
import { _WeakSet, unwrapTemplate } from '@glimmer/util';
import InternalComponent from '../components/internal';
import { EmberVMEnvironment } from '../environment';
import RuntimeResolver from '../resolver';
Expand Down Expand Up @@ -57,6 +57,12 @@ export class InternalComponentDefinition
}
}

const INTERNAL_MANAGERS = new _WeakSet();

export function isInternalManager(manager: object): manager is InternalManager {
return INTERNAL_MANAGERS.has(manager);
}

export default class InternalManager
extends AbstractComponentManager<InternalComponentState, InternalDefinitionState>
implements WithStaticLayout<InternalComponentState, InternalDefinitionState, RuntimeResolver> {
Expand All @@ -66,6 +72,7 @@ export default class InternalManager

constructor(private owner: Owner, private name: string) {
super();
INTERNAL_MANAGERS.add(this);
}

getCapabilities(): ComponentCapabilities {
Expand Down
11 changes: 2 additions & 9 deletions packages/@ember/-internals/glimmer/lib/components/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
@module @ember/component
*/
import InternalManager from '../component-managers/internal';
import { setManager } from '../utils/managers';
import { setComponentManager } from '../utils/managers';
import InternalComponent from './internal';

/**
Expand Down Expand Up @@ -117,13 +117,6 @@ export default class Input extends InternalComponent {
}
}

setManager(
{
factory: InternalManager.for('input'),
internal: true,
type: 'component',
},
Input
);
setComponentManager(InternalManager.for('input'), Input);

Input.toString = () => '@ember/component/input';
28 changes: 11 additions & 17 deletions packages/@ember/-internals/glimmer/lib/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,8 @@ import {
import { PartialDefinitionImpl } from '@glimmer/opcode-compiler';
import { getDynamicVar, ModifierDefinition, registerDestructor } from '@glimmer/runtime';
import { CurlyComponentDefinition } from './component-managers/curly';
import { CustomManagerDefinition, ManagerDelegate } from './component-managers/custom';
import InternalComponentManager, {
InternalComponentDefinition,
} from './component-managers/internal';
import { CustomManagerDefinition } from './component-managers/custom';
import { InternalComponentDefinition, isInternalManager } from './component-managers/internal';
import { TemplateOnlyComponentDefinition } from './component-managers/template-only';
import InternalComponent from './components/internal';
import { isClassHelper, isHelperFactory } from './helper';
Expand All @@ -44,14 +42,13 @@ import { default as queryParams } from './helpers/query-param';
import { default as readonly } from './helpers/readonly';
import { default as unbound } from './helpers/unbound';
import ActionModifierManager from './modifiers/action';
import { CustomModifierDefinition, ModifierManagerDelegate } from './modifiers/custom';
import { CustomModifierDefinition } from './modifiers/custom';
import OnModifierManager from './modifiers/on';
import { mountHelper } from './syntax/mount';
import { outletHelper } from './syntax/outlet';
import { Factory as TemplateFactory, OwnedTemplate } from './template';
import { getComponentTemplate } from './utils/component-template';
import { getModifierManager } from './utils/custom-modifier-manager';
import { getManager } from './utils/managers';
import { getComponentManager, getModifierManager } from './utils/managers';
import { createHelperRef } from './utils/references';

function instrumentationPayload(name: string) {
Expand Down Expand Up @@ -404,10 +401,9 @@ export default class RuntimeResolverImpl implements RuntimeResolver<OwnedTemplat
let owner = meta.owner;
let modifier = owner.factoryFor<unknown, FactoryClass>(`modifier:${name}`);
if (modifier !== undefined) {
let managerFactory = getModifierManager<ModifierManagerDelegate<unknown>>(modifier.class);
let manager = managerFactory!(owner);
let manager = getModifierManager(owner, modifier.class!);

return new CustomModifierDefinition(name, modifier, manager, this.isInteractive);
return new CustomModifierDefinition(name, modifier, manager!, this.isInteractive);
}
}

Expand Down Expand Up @@ -465,24 +461,22 @@ export default class RuntimeResolverImpl implements RuntimeResolver<OwnedTemplat
assert(`missing component class ${name}`, pair.component.class !== undefined);

let ComponentClass = pair.component.class!;
let wrapper = getManager(ComponentClass);
let manager = getComponentManager(owner, ComponentClass);

if (wrapper !== null && wrapper.type === 'component') {
let { factory } = wrapper;

if (wrapper.internal) {
if (manager !== undefined) {
if (isInternalManager(manager)) {
assert(`missing layout for internal component ${name}`, pair.layout !== null);

definition = new InternalComponentDefinition(
factory(owner) as InternalComponentManager,
manager,
ComponentClass as typeof InternalComponent,
layout!
);
} else {
definition = new CustomManagerDefinition(
name,
pair.component,
factory(owner) as ManagerDelegate<unknown>,
manager,
layout !== undefined
? layout
: owner.lookup<TemplateFactory>(P`template:components/-default`)!(owner)
Expand Down

This file was deleted.

This file was deleted.

140 changes: 125 additions & 15 deletions packages/@ember/-internals/glimmer/lib/utils/managers.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,144 @@
import { Owner } from '@ember/-internals/owner';
import { Option } from '@glimmer/interfaces';
import { deprecate } from '@ember/debug';
import { COMPONENT_MANAGER_STRING_LOOKUP } from '@ember/deprecated-features';
import { ManagerDelegate as ComponentManagerDelegate } from '../component-managers/custom';
import InternalComponentManager from '../component-managers/internal';
import { ModifierManagerDelegate } from '../modifiers/custom';

const MANAGERS: WeakMap<object, ManagerWrapper<unknown>> = new WeakMap();
type ManagerDelegate =
| ComponentManagerDelegate<unknown>
| InternalComponentManager
| ModifierManagerDelegate<unknown>;

const getPrototypeOf = Object.getPrototypeOf;
const COMPONENT_MANAGERS = new WeakMap<
object,
ManagerFactory<ComponentManagerDelegate<unknown> | InternalComponentManager>
>();

export type ManagerFactory<ManagerDelegate> = (owner: Owner) => ManagerDelegate;
const MODIFIER_MANAGERS = new WeakMap<object, ManagerFactory<ModifierManagerDelegate<unknown>>>();

export interface ManagerWrapper<ManagerDelegate> {
factory: ManagerFactory<ManagerDelegate>;
internal: boolean;
type: 'component' | 'modifier';
}
const MANAGER_INSTANCES: WeakMap<Owner, WeakMap<ManagerFactory, unknown>> = new WeakMap();

export type ManagerFactory<D extends ManagerDelegate = ManagerDelegate> = (owner: Owner) => D;

///////////

export function setManager<ManagerDelegate>(wrapper: ManagerWrapper<ManagerDelegate>, obj: object) {
MANAGERS.set(obj, wrapper);
const getPrototypeOf = Object.getPrototypeOf;

function setManager<Def extends object>(
map: WeakMap<object, ManagerFactory>,
factory: ManagerFactory,
obj: Def
): Def {
map.set(obj, factory);
return obj;
}

export function getManager<ManagerDelegate>(obj: object): Option<ManagerWrapper<ManagerDelegate>> {
function getManager<D extends ManagerDelegate>(
map: WeakMap<object, ManagerFactory<D>>,
obj: object
): ManagerFactory<D> | undefined {
let pointer = obj;
while (pointer !== undefined && pointer !== null) {
let manager = MANAGERS.get(pointer);
const manager = map.get(pointer);

if (manager !== undefined) {
return manager as ManagerWrapper<ManagerDelegate>;
return manager;
}

pointer = getPrototypeOf(pointer);
}

return null;
return undefined;
}

function getManagerInstanceForOwner<D extends ManagerDelegate>(
owner: Owner,
factory: ManagerFactory<D>
): D {
let managers = MANAGER_INSTANCES.get(owner);

if (managers === undefined) {
managers = new WeakMap();
MANAGER_INSTANCES.set(owner, managers);
}

let instance = managers.get(factory);

if (instance === undefined) {
instance = factory(owner);
managers.set(factory, instance!);
}

// We know for sure that it's the correct type at this point, but TS can't know
return instance as D;
}

///////////

export function setModifierManager(
factory: ManagerFactory<ModifierManagerDelegate<unknown>>,
definition: object
) {
return setManager(MODIFIER_MANAGERS, factory, definition);
}

export function getModifierManager(
owner: Owner,
definition: object
): ModifierManagerDelegate<unknown> | undefined {
const factory = getManager(MODIFIER_MANAGERS, definition);

if (factory !== undefined) {
return getManagerInstanceForOwner(owner, factory);
}

return undefined;
}

export function setComponentManager(
stringOrFunction:
| string
| ManagerFactory<ComponentManagerDelegate<unknown> | InternalComponentManager>,
obj: object
) {
let factory: ManagerFactory<ComponentManagerDelegate<unknown> | InternalComponentManager>;
if (COMPONENT_MANAGER_STRING_LOOKUP && typeof stringOrFunction === 'string') {
deprecate(
'Passing the name of the component manager to "setupComponentManager" is deprecated. Please pass a function that produces an instance of the manager.',
false,
{
id: 'deprecate-string-based-component-manager',
until: '4.0.0',
url: 'https://emberjs.com/deprecations/v3.x/#toc_component-manager-string-lookup',
}
);
factory = function(owner: Owner) {
return owner.lookup<ComponentManagerDelegate<unknown> | InternalComponentManager>(
`component-manager:${stringOrFunction}`
)!;
};
} else {
factory = stringOrFunction as ManagerFactory<
ComponentManagerDelegate<unknown> | InternalComponentManager
>;
}

return setManager(COMPONENT_MANAGERS, factory, obj);
}

export function getComponentManager(
owner: Owner,
definition: object
): ComponentManagerDelegate<unknown> | InternalComponentManager | undefined {
const factory = getManager<ComponentManagerDelegate<unknown> | InternalComponentManager>(
COMPONENT_MANAGERS,
definition
);

if (factory !== undefined) {
return getManagerInstanceForOwner(owner, factory);
}

return undefined;
}