Browse Source

mol-state: call StateTransformer.dispose when recreating object

David Sehnal 5 years ago
parent
commit
70de73a95b

+ 3 - 2
src/mol-plugin-state/transforms/representation.ts

@@ -141,12 +141,13 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({
     },
     update({ a, b, oldParams, newParams, cache }, plugin: PluginContext) {
         return Task.create('Structure Representation', async ctx => {
+            if (newParams.type.name !== oldParams.type.name) return StateTransformer.UpdateResult.Recreate;
+
+            // dispose isn't called on update so we need to handle it manually
             const oldProvider = plugin.representation.structure.registry.get(oldParams.type.name);
             if (oldProvider.ensureCustomProperties) oldProvider.ensureCustomProperties.detach(a.data);
             Theme.releaseDependencies(plugin.representation.structure.themes, { structure: a.data }, oldParams);
 
-            if (newParams.type.name !== oldParams.type.name) return StateTransformer.UpdateResult.Recreate;
-
             const provider = plugin.representation.structure.registry.get(newParams.type.name);
             const propertyCtx = { runtime: ctx, fetch: plugin.fetch };
             if (provider.ensureCustomProperties) await provider.ensureCustomProperties.attach(propertyCtx, a.data);

+ 18 - 1
src/mol-state/state.ts

@@ -477,7 +477,9 @@ async function update(ctx: UpdateContext) {
 
         for (let i = deletes.length - 1; i >= 0; i--) {
             const cell = ctx.cells.get(deletes[i]);
-            cell?.transform.transformer.definition.dispose?.({ b: cell.obj, params: cell.transform.params, cache: cell.cache }, ctx.parent.globalContext);
+            if (cell) {
+                dispose(cell.transform, cell.obj, cell?.transform.params, cell.cache, ctx.parent.globalContext);
+            }
         }
 
         for (const d of deletes) {
@@ -866,9 +868,11 @@ async function updateNode(ctx: UpdateContext, currentRef: Ref): Promise<UpdateNo
         return { ref: currentRef, action: 'created', obj };
     } else {
         const oldParams = current.params.values;
+        const oldCache = current.cache;
         const newParams = params.values;
         current.params = params;
 
+
         const updateKind = !!current.obj && current.obj !== StateObject.Null
             ? await updateObject(ctx, current, transform.transformer, parent, current.obj!, oldParams, newParams)
             : StateTransformer.UpdateResult.Recreate;
@@ -876,7 +880,10 @@ async function updateNode(ctx: UpdateContext, currentRef: Ref): Promise<UpdateNo
         switch (updateKind) {
             case StateTransformer.UpdateResult.Recreate: {
                 const oldObj = current.obj;
+                dispose(transform, oldObj, oldParams, oldCache, ctx.parent.globalContext);
+
                 const newObj = await createObject(ctx, current, transform.transformer, parent, newParams);
+
                 updateTag(newObj, transform);
                 current.obj = newObj;
                 return { ref: currentRef, action: 'replaced', oldObj, obj: newObj };
@@ -885,6 +892,8 @@ async function updateNode(ctx: UpdateContext, currentRef: Ref): Promise<UpdateNo
                 updateTag(current.obj, transform);
                 return { ref: currentRef, action: 'updated', obj: current.obj! };
             case StateTransformer.UpdateResult.Null: {
+                dispose(transform, current.obj, oldParams, oldCache, ctx.parent.globalContext);
+
                 current.obj = StateObject.Null;
                 return { ref: currentRef, action: 'updated', obj: current.obj! };
             }
@@ -894,6 +903,14 @@ async function updateNode(ctx: UpdateContext, currentRef: Ref): Promise<UpdateNo
     }
 }
 
+function dispose(transform: StateTransform, b: StateObject | undefined, params: any, cache: any, globalContext: any) {
+    transform.transformer.definition.dispose?.({
+        b: b !== StateObject.Null ? b : void 0,
+        params,
+        cache
+    }, globalContext);
+}
+
 function updateTag(obj: StateObject | undefined, transform: StateTransform) {
     if (!obj || obj === StateObject.Null) return;
     (obj.tags as string[] | undefined) = transform.tags;

+ 10 - 1
src/mol-state/transformer.ts

@@ -103,7 +103,16 @@ namespace Transformer {
         /** Parameter interpolation */
         interpolate?(src: P, target: P, t: number, globalCtx: unknown): P
 
-        /** Cleanup resources */
+        /**
+         * Cleanup resources
+         *
+         * Automatically called on deleting an object and on recreating it
+         * (i.e. when update returns UpdateResult.Recreate or UpdateResult.Null)
+         *
+         * Not called on UpdateResult.Updated because the resources might not
+         * have been invalidated. In this case, the possible cleanup has to be handled
+         * manually.
+         */
         dispose?(params: DisposeParams<B, P>, globalCtx: unknown): void
 
         /** Custom conversion to and from JSON */