diff --git a/src/mol-state/context.ts b/src/mol-state/context.ts new file mode 100644 index 0000000000000000000000000000000000000000..16e06198eeabaf284b8d0cb524a5592f781c72dc --- /dev/null +++ b/src/mol-state/context.ts @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { Subject } from 'rxjs' +import { StateObject } from './object'; +import { Task } from 'mol-task'; +import { Transform } from './tree/transform'; + +interface StateContext { + events: { + object: { + stateChanged: Subject<{ ref: Transform.Ref }>, + updated: Subject<{ ref: Transform.Ref }>, + replaced: Subject<{ ref: Transform.Ref, old?: StateObject }>, + created: Subject<{ ref: Transform.Ref }>, + removed: Subject<{ ref: Transform.Ref }>, + }, + warn: Subject<string> + }, + globalContext: unknown, + runTask<T>(task: T | Task<T>): T | Promise<T> +} + +namespace StateContext { + export function create(globalContext?: unknown/* task?: { observer?: Progress.Observer, updateRateMs?: number } */): StateContext { + return { + events: { + object: { + stateChanged: new Subject(), + updated: new Subject(), + replaced: new Subject(), + created: new Subject(), + removed: new Subject() + }, + warn: new Subject() + }, + globalContext, + runTask<T>(t: T | Task<T>) { + if (typeof (t as any).run === 'function') return (t as Task<T>).run(); + return t as T; + } + } + } +} + +export { StateContext } \ No newline at end of file diff --git a/src/mol-state/context/context.ts b/src/mol-state/context/context.ts deleted file mode 100644 index b7fd34c4cb9e8389d55489c8b0b5c8b8330307ab..0000000000000000000000000000000000000000 --- a/src/mol-state/context/context.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author David Sehnal <david.sehnal@gmail.com> - */ - -export interface StateContext { - -} \ No newline at end of file diff --git a/src/mol-state/event/dispatcher.ts b/src/mol-state/event/dispatcher.ts deleted file mode 100644 index 32dcb9a0516c288ed83911bba462598e0372cb0d..0000000000000000000000000000000000000000 --- a/src/mol-state/event/dispatcher.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author David Sehnal <david.sehnal@gmail.com> - */ - -export interface EventDispatcher { - // TODO -} \ No newline at end of file diff --git a/src/mol-state/event/event.ts b/src/mol-state/event/event.ts deleted file mode 100644 index 32dcb9a0516c288ed83911bba462598e0372cb0d..0000000000000000000000000000000000000000 --- a/src/mol-state/event/event.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author David Sehnal <david.sehnal@gmail.com> - */ - -export interface EventDispatcher { - // TODO -} \ No newline at end of file diff --git a/src/mol-state/index.ts b/src/mol-state/index.ts index 9dd0621de618c2a038d9e82f08cf9e6be0f0f843..0ebc69a6980415c57a8dcfe28fab11e0ab8d66ff 100644 --- a/src/mol-state/index.ts +++ b/src/mol-state/index.ts @@ -2,4 +2,12 @@ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> - */ \ No newline at end of file + */ + +export * from './object' +export * from './state' +export * from './transformer' +export * from './tree' +export * from './context' +export * from './tree/transform' +export * from './tree/selection' \ No newline at end of file diff --git a/src/mol-state/object.ts b/src/mol-state/object.ts index 38389e2a36c68f7c0404ae3609d85d1248b46122..7f9019fc9bc5e03c776c5cc242e6aeb7d254787d 100644 --- a/src/mol-state/object.ts +++ b/src/mol-state/object.ts @@ -16,12 +16,6 @@ export interface StateObject<P = unknown, D = unknown> { } export namespace StateObject { - // export type TypeOf<T> - // = T extends StateObject<infer X> ? [X] - // : T extends [StateObject<infer X>] ? [X] - // : T extends [StateObject<infer X>, StateObject<infer Y>] ? [X, Y] - // : unknown[]; - export enum StateType { // The object has been successfully created Ok, @@ -53,8 +47,9 @@ export namespace StateObject { } export interface Wrapped { - obj: StateObject, state: StateType, + errorText?: string, + obj?: StateObject, version: string } } \ No newline at end of file diff --git a/src/mol-state/state.ts b/src/mol-state/state.ts index f2db317f28a476c8e7dbaa27f573fdb4b479a6be..dfba3eba5b84f9ff8ca355a901e04ea2aff19356 100644 --- a/src/mol-state/state.ts +++ b/src/mol-state/state.ts @@ -5,31 +5,34 @@ */ import { StateObject } from './object'; -import { TransformTree } from './tree/tree'; +import { StateTree } from './tree'; import { Transform } from './tree/transform'; import { Map as ImmutableMap } from 'immutable'; // import { StateContext } from './context/context'; import { ImmutableTree } from './util/immutable-tree'; import { Transformer } from './transformer'; -import { Task } from 'mol-task'; +import { StateContext } from './context'; +import { UUID } from 'mol-util'; export interface State<ObjectProps = unknown> { definition: State.Definition<ObjectProps>, - objects: State.Objects + objects: State.Objects, + context: StateContext } export namespace State { - export type ObjectProps<P> = ImmutableMap<Transform.Ref, P> - export type Objects = Map<Transform.Ref, StateObject.Wrapped> + export type Ref = Transform.Ref + export type ObjectProps<P = unknown> = ImmutableMap<Ref, P> + export type Objects = Map<Ref, StateObject.Wrapped> export interface Definition<P = unknown> { - tree: TransformTree, + tree: StateTree, // things like object visibility props: ObjectProps<P> } - export function create(): State { - const tree = TransformTree.create(); + export function create(params?: { globalContext?: unknown }): State { + const tree = StateTree.create(); const objects: Objects = new Map(); const root = tree.getValue(tree.rootRef)!; @@ -40,44 +43,60 @@ export namespace State { tree, props: ImmutableMap() }, - objects + objects, + context: StateContext.create(params && params.globalContext) }; } - export async function update<P>(state: State<P>, tree: TransformTree, props?: ObjectProps<P>): Promise<State<P>> { + export async function update<P>(state: State<P>, tree: StateTree): Promise<State<P>> { + const ctx: UpdateContext = { + stateCtx: state.context, + old: state.definition, + tree: tree, + props: state.definition.props.asMutable(), + objects: state.objects + }; + const roots = findUpdateRoots(state.objects, tree); - const deletes = findDeletes(state.objects, tree); + const deletes = findDeletes(ctx); for (const d of deletes) { state.objects.delete(d); } - console.log('roots', roots); + initObjectState(ctx, roots); + for (const root of roots) { - await updateSubtree(state.definition.tree, tree, state.objects, root); + await updateSubtree(ctx, root); } return { - definition: { tree, props: props || state.definition.props }, - objects: state.objects + definition: { tree, props: ctx.props.asImmutable() as ObjectProps<P> }, + objects: state.objects, + context: state.context }; } - function findUpdateRoots(objects: Objects, tree: TransformTree) { - console.log(tree); + interface UpdateContext { + stateCtx: StateContext, + old: Definition, + tree: StateTree, + props: ObjectProps, + objects: Objects + } + + function findUpdateRoots(objects: Objects, tree: StateTree) { const findState = { - roots: [] as Transform.Ref[], + roots: [] as Ref[], objects }; ImmutableTree.doPreOrder(tree, tree.nodes.get(tree.rootRef)!, findState, (n, _, s) => { if (!s.objects.has(n.ref)) { - console.log('missing', n.ref); s.roots.push(n.ref); return false; } const o = s.objects.get(n.ref)!; if (o.version !== n.value.version) { - console.log('diff version', n.ref, n.value.version, o.version); s.roots.push(n.ref); return false; } @@ -88,75 +107,130 @@ export namespace State { return findState.roots; } - function findDeletes(objects: Objects, tree: TransformTree): Transform.Ref[] { - // TODO - return []; + function findDeletes(ctx: UpdateContext): Ref[] { + // TODO: do this in some sort of "tree order"? + const deletes: Ref[] = []; + const keys = ctx.objects.keys(); + while (true) { + const key = keys.next(); + if (key.done) break; + if (!ctx.tree.nodes.has(key.value)) deletes.push(key.value); + } + return deletes; + } + + function setObjectState(ctx: UpdateContext, ref: Ref, state: StateObject.StateType, errorText?: string) { + if (ctx.objects.has(ref)) { + const obj = ctx.objects.get(ref)!; + obj.state = state; + obj.errorText = errorText; + } else { + const obj = { state, version: UUID.create(), errorText }; + ctx.objects.set(ref, obj); + } + ctx.stateCtx.events.object.stateChanged.next({ ref }); } - function findParent(tree: TransformTree, objects: Objects, root: Transform.Ref, types: { type: StateObject.Type }[]): StateObject { + function _initVisitor(t: ImmutableTree.Node<Transform>, _: any, ctx: UpdateContext) { + setObjectState(ctx, t.ref, StateObject.StateType.Pending); + } + /** Return "resolve set" */ + function initObjectState(ctx: UpdateContext, roots: Ref[]) { + for (const root of roots) { + ImmutableTree.doPreOrder(ctx.tree, ctx.tree.nodes.get(root), ctx, _initVisitor); + } + } + + function doError(ctx: UpdateContext, ref: Ref, errorText: string) { + setObjectState(ctx, ref, StateObject.StateType.Error, errorText); + const wrap = ctx.objects.get(ref)!; + if (wrap.obj) { + ctx.stateCtx.events.object.removed.next({ ref }); + wrap.obj = void 0; + } + + const children = ctx.tree.nodes.get(ref)!.children.values(); + while (true) { + const next = children.next(); + if (next.done) return; + doError(ctx, next.value, 'Parent node contains error.'); + } + } + + function findParent(tree: StateTree, objects: Objects, root: Ref, types: { type: StateObject.Type }[]): StateObject { let current = tree.nodes.get(root)!; - console.log('finding', types.map(t => t.type.kind)); while (true) { current = tree.nodes.get(current.parent)!; - if (current.ref === tree.rootRef) return objects.get(tree.rootRef)!.obj; - const obj = objects.get(current.ref)!.obj; - console.log('current', obj.type.kind); - for (const t of types) if (obj.type === t.type) return objects.get(current.ref)!.obj; + if (current.ref === tree.rootRef) { + return objects.get(tree.rootRef)!.obj!; + } + const obj = objects.get(current.ref)!.obj!; + for (const t of types) if (obj.type === t.type) return objects.get(current.ref)!.obj!; } } - async function updateSubtree(oldTree: TransformTree, tree: TransformTree, objects: Objects, root: Transform.Ref) { - await updateNode(oldTree, tree, objects, root); - const children = tree.nodes.get(root)!.children.values(); + async function updateSubtree(ctx: UpdateContext, root: Ref) { + setObjectState(ctx, root, StateObject.StateType.Pending); + + try { + const update = await updateNode(ctx, root); + setObjectState(ctx, root, StateObject.StateType.Ok); + if (update === 'created') { + ctx.stateCtx.events.object.created.next({ ref: root }); + } else if (update === 'updated') { + ctx.stateCtx.events.object.updated.next({ ref: root }); + } + } catch (e) { + doError(ctx, root, '' + e); + return; + } + + const children = ctx.tree.nodes.get(root)!.children.values(); while (true) { const next = children.next(); if (next.done) return; - await updateSubtree(oldTree, tree, objects, next.value); + await updateSubtree(ctx, next.value); } } - async function updateNode(oldTree: TransformTree, tree: TransformTree, objects: Objects, currentRef: Transform.Ref) { + async function updateNode(ctx: UpdateContext, currentRef: Ref) { + const { old: { tree: oldTree }, tree, objects } = ctx; const transform = tree.getValue(currentRef)!; const parent = findParent(tree, objects, currentRef, transform.transformer.definition.from); - console.log('parent', parent ? parent.ref : 'undefined') - if (!oldTree.nodes.has(transform.ref) || !objects.has(transform.ref)) { - console.log('creating...', transform.transformer.id, oldTree.nodes.has(transform.ref), objects.has(transform.ref)); - const obj = await createObject(transform.transformer, parent, transform.params); - obj.ref = transform.ref; + //console.log('parent', transform.transformer.id, transform.transformer.definition.from[0].type, parent ? parent.ref : 'undefined') + if (!oldTree.nodes.has(currentRef) || !objects.has(currentRef)) { + console.log('creating...', transform.transformer.id, oldTree.nodes.has(currentRef), objects.has(currentRef)); + const obj = await createObject(ctx, transform.transformer, parent, transform.params); + obj.ref = currentRef; objects.set(currentRef, { obj, state: StateObject.StateType.Ok, version: transform.version }); + return 'created'; } else { console.log('updating...', transform.transformer.id); - const current = objects.get(transform.ref)!.obj; - const oldParams = oldTree.getValue(transform.ref)!.params; - switch (await updateObject(transform.transformer, parent, current, oldParams, transform.params)) { + const current = objects.get(currentRef)!; + const oldParams = oldTree.getValue(currentRef)!.params; + switch (await updateObject(ctx, transform.transformer, parent, current.obj!, oldParams, transform.params)) { case Transformer.UpdateResult.Recreate: { - const obj = await createObject(transform.transformer, parent, transform.params); - obj.ref = transform.ref; + const obj = await createObject(ctx, transform.transformer, parent, transform.params); + obj.ref = currentRef; objects.set(currentRef, { obj, state: StateObject.StateType.Ok, version: transform.version }); - break; - } - case Transformer.UpdateResult.Updated: { - const obj = objects.get(currentRef)!; - obj.version = transform.version; - break; + ctx.stateCtx.events.object.created.next({ ref: currentRef }); + return 'created'; } + case Transformer.UpdateResult.Updated: + current.version = transform.version; + return 'updated'; } } } - async function runTask<A>(t: A | Task<A>): Promise<A> { - if ((t as any).run) return await (t as Task<A>).run(); - return t as A; - } - - function createObject(transformer: Transformer, a: StateObject, params: any) { - return runTask(transformer.definition.apply({ a, params })); + function createObject(ctx: UpdateContext, transformer: Transformer, a: StateObject, params: any) { + return ctx.stateCtx.runTask(transformer.definition.apply({ a, params, globalCtx: ctx.stateCtx.globalContext })); } - async function updateObject(transformer: Transformer, a: StateObject, b: StateObject, oldParams: any, newParams: any) { + async function updateObject(ctx: UpdateContext, transformer: Transformer, a: StateObject, b: StateObject, oldParams: any, newParams: any) { if (!transformer.definition.update) { return Transformer.UpdateResult.Recreate; } - return runTask(transformer.definition.update({ a, oldParams, b, newParams })); + return ctx.stateCtx.runTask(transformer.definition.update({ a, oldParams, b, newParams, globalCtx: ctx.stateCtx.globalContext })); } } diff --git a/src/mol-state/transformer.ts b/src/mol-state/transformer.ts index 7b6cfaa4e56d1647f5c76eb98f3841b0c7836f2c..139a1d6107bc58589f5e528018860e653bcb1c7c 100644 --- a/src/mol-state/transformer.ts +++ b/src/mol-state/transformer.ts @@ -6,7 +6,6 @@ import { Task } from 'mol-task'; import { StateObject } from './object'; -import { TransformContext } from './tree/context'; import { Transform } from './tree/transform'; export interface Transformer<A extends StateObject = StateObject, B extends StateObject = StateObject, P = unknown> { @@ -24,14 +23,16 @@ export namespace Transformer { export interface ApplyParams<A extends StateObject = StateObject, P = unknown> { a: A, - params: P + params: P, + globalCtx: unknown } export interface UpdateParams<A extends StateObject = StateObject, B extends StateObject = StateObject, P = unknown> { a: A, b: B, oldParams: P, - newParams: P + newParams: P, + globalCtx: unknown } export enum UpdateResult { Unchanged, Updated, Recreate } @@ -55,19 +56,19 @@ export namespace Transformer { update?(params: UpdateParams<A, B, P>): Task<UpdateResult> | UpdateResult, /** Check the parameters and return a list of errors if the are not valid. */ - defaultParams?(a: A, context: TransformContext): P, + defaultParams?(a: A, globalCtx: unknown): P, /** Specify default control descriptors for the parameters */ - defaultControls?(a: A, context: TransformContext): Transformer.ControlsFor<P>, + defaultControls?(a: A, globalCtx: unknown): Transformer.ControlsFor<P>, /** Check the parameters and return a list of errors if the are not valid. */ - validateParams?(a: A, params: P, context: TransformContext): string[] | undefined, + validateParams?(a: A, params: P, globalCtx: unknown): string[] | undefined, /** Optional custom parameter equality. Use deep structural equal by default. */ areParamsEqual?(oldParams: P, newParams: P): boolean, /** Test if the transform can be applied to a given node */ - isApplicable?(a: A, context: TransformContext): boolean, + isApplicable?(a: A, globalCtx: unknown): boolean, /** By default, returns true */ isSerializable?(params: P): { isSerializable: true } | { isSerializable: false; reason: string }, diff --git a/src/mol-state/transformer/controller.ts b/src/mol-state/transformer/controller.ts deleted file mode 100644 index 4d970bf1e035ee3c5a6d75f8a86a7c1f495e2691..0000000000000000000000000000000000000000 --- a/src/mol-state/transformer/controller.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author David Sehnal <david.sehnal@gmail.com> - */ - -// TODO: relactive transformer params controller \ No newline at end of file diff --git a/src/mol-state/transformer/manager.ts b/src/mol-state/transformer/manager.ts deleted file mode 100644 index fc04509557cbe18ba20c67ac0c364ed4807c38dd..0000000000000000000000000000000000000000 --- a/src/mol-state/transformer/manager.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author David Sehnal <david.sehnal@gmail.com> - */ - -// TODO: index for registered transformers \ No newline at end of file diff --git a/src/mol-state/tree.ts b/src/mol-state/tree.ts new file mode 100644 index 0000000000000000000000000000000000000000..06e83f0ae4236d22443b8774b249e0498088a528 --- /dev/null +++ b/src/mol-state/tree.ts @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { Transform } from './tree/transform'; +import { ImmutableTree } from './util/immutable-tree'; +import { Transformer } from './transformer'; +import { StateObject } from './object'; + +interface StateTree extends ImmutableTree<Transform> { } + +namespace StateTree { + export interface Transient extends ImmutableTree.Transient<Transform> { } + + function _getRef(t: Transform) { return t.ref; } + + export function create() { + return ImmutableTree.create<Transform>(Transform.createRoot('<:root:>'), _getRef); + } + + export function updateParams<T extends Transformer = Transformer>(tree: StateTree, ref: Transform.Ref, params: Transformer.Params<T>): StateTree { + const t = tree.nodes.get(ref)!.value; + const newTransform = Transform.updateParams(t, params); + const newTree = ImmutableTree.asTransient(tree); + newTree.setValue(ref, newTransform); + return newTree.asImmutable(); + } + + export function toJSON(tree: StateTree) { + return ImmutableTree.toJSON(tree, Transform.toJSON); + } + + export function fromJSON(data: any): StateTree { + return ImmutableTree.fromJSON(data, _getRef, Transform.fromJSON); + } + + export interface Builder { + getTree(): StateTree + } + + export function build(tree: StateTree) { + return new Builder.Root(tree); + } + + export namespace Builder { + interface State { + tree: StateTree.Transient + } + + export class Root implements Builder { + private state: State; + to<A extends StateObject>(ref: Transform.Ref) { return new To<A>(this.state, ref); } + toRoot<A extends StateObject>() { return new To<A>(this.state, this.state.tree.rootRef as any); } + delete(ref: Transform.Ref) { this.state.tree.remove(ref); return this; } + getTree(): StateTree { return this.state.tree.asImmutable(); } + constructor(tree: StateTree) { this.state = { tree: ImmutableTree.asTransient(tree) } } + } + + export class To<A extends StateObject> implements Builder { + apply<T extends Transformer<A, any, any>>(tr: T, params?: Transformer.Params<T>, props?: Partial<Transform.Props>): To<Transformer.To<T>> { + const t = tr.apply(params, props); + this.state.tree.add(this.ref, t); + return new To(this.state, t.ref); + } + + getTree(): StateTree { return this.state.tree.asImmutable(); } + + constructor(private state: State, private ref: Transform.Ref) { + if (!this.state.tree.nodes.has(ref)) { + throw new Error(`Could not find node '${ref}'.`); + } + } + } + } +} + +export { StateTree } \ No newline at end of file diff --git a/src/mol-state/tree/action.ts b/src/mol-state/tree/action.ts deleted file mode 100644 index f5216c5abbeb50e7497369b1675c2109cbf4db49..0000000000000000000000000000000000000000 --- a/src/mol-state/tree/action.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author David Sehnal <david.sehnal@gmail.com> - */ - -// TODO: tree actions: Add, Update, Delete; action queue \ No newline at end of file diff --git a/src/mol-state/tree/builder.ts b/src/mol-state/tree/builder.ts deleted file mode 100644 index 4ed5632bc555c864c0ca194622bd85e4de4f6228..0000000000000000000000000000000000000000 --- a/src/mol-state/tree/builder.ts +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author David Sehnal <david.sehnal@gmail.com> - */ - -import { ImmutableTree } from '../util/immutable-tree'; -import { TransformTree } from './tree'; -import { StateObject } from '../object'; -import { Transform } from './transform'; -import { Transformer } from '../transformer'; - -export interface StateTreeBuilder { - getTree(): TransformTree -} - -export namespace StateTreeBuilder { - interface State { - tree: TransformTree.Transient - } - - export function create(tree: TransformTree) { - return new Root(tree); - } - - export class Root implements StateTreeBuilder { - private state: State; - //to<A extends StateObject>(ref: Transform.Ref) { return new To<A>(this.state, ref); } - to<A extends StateObject>(ref: Transform.Ref) { return new To<A>(this.state, ref); } - toRoot<A extends StateObject>() { return new To<A>(this.state, this.state.tree.rootRef as any); } - getTree(): TransformTree { return this.state.tree.asImmutable(); } - constructor(tree: TransformTree) { this.state = { tree: ImmutableTree.asTransient(tree) } } - } - - export class To<A extends StateObject> implements StateTreeBuilder { - apply<T extends Transformer<A, any, any>>(tr: T, params?: Transformer.Params<T>, props?: Partial<Transform.Props>): To<Transformer.To<T>> { - const t = tr.apply(params, props); - this.state.tree.add(this.ref, t); - return new To(this.state, t.ref); - } - - getTree(): TransformTree { return this.state.tree.asImmutable(); } - - constructor(private state: State, private ref: Transform.Ref) { - - } - } -} \ No newline at end of file diff --git a/src/mol-state/tree/context.ts b/src/mol-state/tree/context.ts deleted file mode 100644 index 1c274d8cc9b04844ecf2c6dbeae524a15a7bcc82..0000000000000000000000000000000000000000 --- a/src/mol-state/tree/context.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author David Sehnal <david.sehnal@gmail.com> - */ - -import { EventDispatcher } from '../event/event'; - -export interface TransformContext { - /** An event dispatcher for executing child tasks. */ - dispatcher: EventDispatcher, - - globalContext: any - // tree: ModelTree -} \ No newline at end of file diff --git a/src/mol-state/tree/selection.ts b/src/mol-state/tree/selection.ts index 7c7fe83382a744be37fe5118239b71702aebc60d..84130cdc3dfe2d525171ec6063abbfe696bc67cc 100644 --- a/src/mol-state/tree/selection.ts +++ b/src/mol-state/tree/selection.ts @@ -4,4 +4,8 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -// TODO \ No newline at end of file +namespace StateTreeSelection { + +} + +export { StateTreeSelection } \ No newline at end of file diff --git a/src/mol-state/tree/transform.ts b/src/mol-state/tree/transform.ts index 7c7af9e93cf2bbc3bc546648a08a5125a0ef6e6e..6e494e9d2309cc4928d258c8b48e3994c2604a08 100644 --- a/src/mol-state/tree/transform.ts +++ b/src/mol-state/tree/transform.ts @@ -12,7 +12,8 @@ export interface Transform<A extends StateObject = StateObject, B extends StateO readonly transformer: Transformer<A, B, P>, readonly params: P, readonly ref: Transform.Ref, - readonly version: string + readonly version: string, + readonly defaultProps?: unknown } export namespace Transform { @@ -49,7 +50,8 @@ export namespace Transform { transformer: string, params: any, ref: string, - version: string + version: string, + defaultProps?: unknown } function _id(x: any) { return x; } @@ -61,7 +63,8 @@ export namespace Transform { transformer: t.transformer.id, params: pToJson(t.params), ref: t.ref, - version: t.version + version: t.version, + defaultProps: t.defaultProps }; } @@ -74,7 +77,8 @@ export namespace Transform { transformer, params: pFromJson(t.params), ref: t.ref, - version: t.version + version: t.version, + defaultProps: t.defaultProps }; } } \ No newline at end of file diff --git a/src/mol-state/tree/tree.ts b/src/mol-state/tree/tree.ts deleted file mode 100644 index 686a0941d23da77f3b6dc9f9225bb534a9dce152..0000000000000000000000000000000000000000 --- a/src/mol-state/tree/tree.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author David Sehnal <david.sehnal@gmail.com> - */ - -import { Transform } from './transform'; -import { ImmutableTree } from '../util/immutable-tree'; -import { Transformer } from '../transformer'; - -export interface TransformTree extends ImmutableTree<Transform> { } - -export namespace TransformTree { - export interface Transient extends ImmutableTree.Transient<Transform> { } - - function _getRef(t: Transform) { return t.ref; } - - export function create() { - return ImmutableTree.create<Transform>(Transform.createRoot('<:root:>'), _getRef); - } - - export function updateParams<T extends Transformer = Transformer>(tree: TransformTree, ref: Transform.Ref, params: Transformer.Params<T>): TransformTree { - const t = tree.nodes.get(ref)!.value; - const newTransform = Transform.updateParams(t, params); - const newTree = ImmutableTree.asTransient(tree); - newTree.setValue(ref, newTransform); - return newTree.asImmutable(); - } - - export function toJSON(tree: TransformTree) { - return ImmutableTree.toJSON(tree, Transform.toJSON); - } - - export function fromJSON(data: any): TransformTree { - return ImmutableTree.fromJSON(data, _getRef, Transform.fromJSON); - } -} \ No newline at end of file diff --git a/src/mol-state/util/immutable-tree.ts b/src/mol-state/util/immutable-tree.ts index e4ab973da5e7fcc606aeef1fcec84d66fc975d3b..421f8c3bb9c0f2b53ef239dc2427fae1d3d0f974 100644 --- a/src/mol-state/util/immutable-tree.ts +++ b/src/mol-state/util/immutable-tree.ts @@ -62,7 +62,7 @@ export namespace ImmutableTree { type VisitorCtx = { nodes: Ns, state: any, f: (node: N, nodes: Ns, state: any) => boolean | undefined | void }; function _postOrderFunc(this: VisitorCtx, c: ImmutableTree.Ref | undefined) { _doPostOrder(this, this.nodes.get(c!)!); } - function _doPostOrder<T, S>(ctx: VisitorCtx, root: N) { + function _doPostOrder(ctx: VisitorCtx, root: N) { if (root.children.size) { root.children.forEach(_postOrderFunc, ctx); } @@ -79,7 +79,7 @@ export namespace ImmutableTree { } function _preOrderFunc(this: VisitorCtx, c: ImmutableTree.Ref | undefined) { _doPreOrder(this, this.nodes.get(c!)!); } - function _doPreOrder<T, S>(ctx: VisitorCtx, root: N) { + function _doPreOrder(ctx: VisitorCtx, root: N) { const ret = ctx.f(root, ctx.nodes, ctx.state); if (typeof ret === 'boolean' && !ret) return; if (root.children.size) { @@ -225,12 +225,7 @@ export namespace ImmutableTree { const parent = nodes.get(node.parent)!; const children = mutate(parent.ref).children; const st = subtreePostOrder(this, node); - if (parent.ref === node.ref) { - nodes.clear(); - mutations.clear(); - return st; - } - children.delete(ref); + if (ref !== this.rootRef) children.delete(ref); for (const n of st) { nodes.delete(n.value.ref); mutations.delete(n.value.ref); diff --git a/src/perf-tests/state.ts b/src/perf-tests/state.ts index e46ffcd5beab495833ffa9c59d97843634a0d138..976c329f6db349f9f3cc99e11345f964e7562776 100644 --- a/src/perf-tests/state.ts +++ b/src/perf-tests/state.ts @@ -1,10 +1,6 @@ -import { Transformer } from 'mol-state/transformer'; -import { StateObject } from 'mol-state/object'; +import { State, StateObject, StateTree, Transformer } from 'mol-state'; import { Task } from 'mol-task'; -import { TransformTree } from 'mol-state/tree/tree'; -import { StateTreeBuilder } from 'mol-state/tree/builder'; -import { State } from 'mol-state/state'; -import * as util from 'util' +import * as util from 'util'; export type TypeClass = 'root' | 'shape' | 'prop' export interface ObjProps { label: string } @@ -72,7 +68,7 @@ export async function testState() { const state = State.create(); const tree = state.definition.tree; - const builder = StateTreeBuilder.create(tree) + const builder = StateTree.build(tree); builder.toRoot<Root>() .apply(CreateSquare, { a: 10 }, { ref: 'square' }) .apply(CaclArea); @@ -80,7 +76,7 @@ export async function testState() { printTTree(tree1); - const tree2 = TransformTree.updateParams<typeof CreateSquare>(tree1, 'square', { a: 15 }); + const tree2 = StateTree.updateParams<typeof CreateSquare>(tree1, 'square', { a: 15 }); printTTree(tree1); printTTree(tree2); @@ -89,11 +85,11 @@ export async function testState() { console.log(util.inspect(state1.objects, true, 3, true)); console.log('----------------'); - const jsonString = JSON.stringify(TransformTree.toJSON(tree2), null, 2); + const jsonString = JSON.stringify(StateTree.toJSON(tree2), null, 2); const jsonData = JSON.parse(jsonString); printTTree(tree2); console.log(jsonString); - const treeFromJson = TransformTree.fromJSON(jsonData); + const treeFromJson = StateTree.fromJSON(jsonData); printTTree(treeFromJson); console.log('----------------'); @@ -106,7 +102,7 @@ testState(); //test(); -export function printTTree(tree: TransformTree) { +export function printTTree(tree: StateTree) { let lines: string[] = []; function print(offset: string, ref: any) { const t = tree.nodes.get(ref)!;