From 4fa489838e203b52432a075905d59fda7f643dc0 Mon Sep 17 00:00:00 2001
From: David Sehnal <david.sehnal@gmail.com>
Date: Fri, 15 Jun 2018 21:02:32 +0200
Subject: [PATCH] "nomial types" for Element and Element.Index

---
 src/mol-data/int/impl/segmentation.ts         |  6 +--
 src/mol-data/int/interval.ts                  | 52 +++++++++----------
 src/mol-data/int/ordered-set.ts               | 10 +++-
 src/mol-data/int/segmentation.ts              | 18 +++----
 .../structure/model/formats/mmcif.ts          |  7 +--
 .../structure/model/formats/mmcif/ihm.ts      |  5 +-
 .../model/properties/atomic/hierarchy.ts      |  7 +--
 .../model/properties/coarse/hierarchy.ts      |  3 +-
 src/mol-model/structure/query/modifiers.ts    |  4 +-
 src/mol-model/structure/structure/element.ts  | 12 -----
 .../structure/structure/util/lookup3d.ts      |  1 +
 11 files changed, 63 insertions(+), 62 deletions(-)

diff --git a/src/mol-data/int/impl/segmentation.ts b/src/mol-data/int/impl/segmentation.ts
index fed6a7fb7..63313431f 100644
--- a/src/mol-data/int/impl/segmentation.ts
+++ b/src/mol-data/int/impl/segmentation.ts
@@ -50,11 +50,11 @@ export function projectValue({ segments }: Segmentation, set: OrderedSet, value:
     return OrderedSet.findRange(set, OrderedSet.getAt(segments, idx), OrderedSet.getAt(segments, idx + 1) - 1);
 }
 
-export class SegmentIterator implements Iterator<Segs.Segment> {
+export class SegmentIterator<T extends number = number> implements Iterator<Segs.Segment<T>> {
     private segmentMin = 0;
     private segmentMax = 0;
     private setRange = Interval.Empty;
-    private value: Segs.Segment = { index: 0, start: 0, end: 0 };
+    private value: Segs.Segment<T> = { index: 0, start: 0, end: 0 };
 
     hasNext: boolean = false;
 
@@ -94,7 +94,7 @@ export class SegmentIterator implements Iterator<Segs.Segment> {
         this.hasNext = this.segmentMax >= this.segmentMin;
     }
 
-    setSegment(segment: Segs.Segment) {
+    setSegment(segment: Segs.Segment<T>) {
         this.setRange = Interval.ofBounds(segment.start, segment.end);
         this.updateSegmentRange();
     }
diff --git a/src/mol-data/int/interval.ts b/src/mol-data/int/interval.ts
index 2b4c6cd17..d5edcfc9e 100644
--- a/src/mol-data/int/interval.ts
+++ b/src/mol-data/int/interval.ts
@@ -9,48 +9,48 @@ import * as Impl from './impl/interval'
 namespace Interval {
     export const Empty: Interval = Impl.Empty as any;
 
-    export const ofSingleton: (value: number) => Interval = (v) => Impl.ofRange(v, v) as any;
+    export const ofSingleton: <T extends number = number>(value: T) => Interval<T> = (v) => Impl.ofRange(v, v) as any;
     /** Create interval from range [min, max] */
-    export const ofRange: (min: number, max: number) => Interval = Impl.ofRange as any;
+    export const ofRange: <T extends number = number>(min: T, max: T) => Interval<T> = Impl.ofRange as any;
     /** Create interval from bounds [start, end), i.e. [start, end - 1] */
-    export const ofBounds: (start: number, end: number) => Interval = Impl.ofBounds as any;
-    export const is: (v: any) => v is Interval = Impl.is as any;
+    export const ofBounds: <T extends number = number>(start: T, end: T) => Interval<T> = Impl.ofBounds as any;
+    export const is: <T extends number = number>(v: any) => v is Interval<T> = Impl.is as any;
 
     /** Test if a value is within the bounds of the interval */
-    export const has: (interval: Interval, x: number) => boolean = Impl.has as any;
-    export const indexOf: (interval: Interval, x: number) => number = Impl.indexOf as any;
-    export const getAt: (interval: Interval, i: number) => number = Impl.getAt as any;
-
-    /** Start value of the interval, same as min value */
-    export const start: (interval: Interval) => number = Impl.start as any;
-    /** End value of the interval, same as max + 1 */
-    export const end: (interval: Interval) => number = Impl.end as any;
-    /** Min value of the interval, same as start value */
-    export const min: (interval: Interval) => number = Impl.min as any;
-    /** Max value of the interval, same as end - 1 */
-    export const max: (interval: Interval) => number = Impl.max as any;
+    export const has: <T extends number = number>(interval: Interval<T>, x: T) => boolean = Impl.has as any;
+    export const indexOf: <T extends number = number>(interval: Interval<T>, x: T) => number = Impl.indexOf as any;
+    export const getAt: <T extends number = number>(interval: Interval<T>, i: number) => T = Impl.getAt as any;
+
+    /** Start value of the Interval<T>, same as min value */
+    export const start: <T extends number = number>(interval: Interval<T>) => T = Impl.start as any;
+    /** End value of the Interval<T>, same as max + 1 */
+    export const end: <T extends number = number>(interval: Interval<T>) => T = Impl.end as any;
+    /** Min value of the Interval<T>, same as start value */
+    export const min: <T extends number = number>(interval: Interval<T>) => T = Impl.min as any;
+    /** Max value of the Interval<T>, same as end - 1 */
+    export const max: <T extends number = number>(interval: Interval<T>) => T = Impl.max as any;
     /** Number of values in the interval */
-    export const size: (interval: Interval) => number = Impl.size as any;
+    export const size: <T extends number = number>(interval: Interval<T>) => number = Impl.size as any;
     /** Hash code describing the interval */
-    export const hashCode: (interval: Interval) => number = Impl.hashCode as any;
+    export const hashCode: <T extends number = number>(interval: Interval<T>) => number = Impl.hashCode as any;
 
     /** Test if two intervals are identical */
-    export const areEqual: (a: Interval, b: Interval) => boolean = Impl.areEqual as any;
+    export const areEqual: <T extends number = number>(a: Interval<T>, b: Interval<T>) => boolean = Impl.areEqual as any;
     /** Test if two intervals are intersecting, i.e. their bounds overlap */
-    export const areIntersecting: (a: Interval, b: Interval) => boolean = Impl.areIntersecting as any;
+    export const areIntersecting: <T extends number = number>(a: Interval<T>, b: Interval<T>) => boolean = Impl.areIntersecting as any;
 
     /** Test if interval b is fully included in interval a */
-    export const isSubInterval: (a: Interval, b: Interval) => boolean = Impl.isSubInterval as any;
+    export const isSubInterval: <T extends number = number>(a: Interval<T>, b: Interval<T>) => boolean = Impl.isSubInterval as any;
 
-    export const findPredecessorIndex: (interval: Interval, x: number) => number = Impl.findPredecessorIndex as any;
-    export const findPredecessorIndexInInterval: (interval: Interval, x: number, bounds: Interval) => number = Impl.findPredecessorIndexInInterval as any;
-    export const findRange: (interval: Interval, min: number, max: number) => Interval = Impl.findRange as any;
+    export const findPredecessorIndex: <T extends number = number>(interval: Interval<T>, x: T) => number = Impl.findPredecessorIndex as any;
+    export const findPredecessorIndexInInterval: <T extends number = number>(interval: Interval<T>, x: T, bounds: Interval) => number = Impl.findPredecessorIndexInInterval as any;
+    export const findRange: <T extends number = number>(interval: Interval<T>, min: T, max: T) => Interval = Impl.findRange as any;
 
     /** Get a new interval that is the intersection of the two intervals */
-    export const intersect: (a: Interval, b: Interval) => Interval = Impl.intersect as any;
+    export const intersect: <T extends number = number>(a: Interval<T>, b: Interval<T>) => Interval<T> = Impl.intersect as any;
 }
 
 /** Interval describing a range [min, max] of values */
-interface Interval { '@type': 'int-interval' }
+interface Interval<T extends number = number> { '@type': 'int-interval' }
 
 export default Interval
\ No newline at end of file
diff --git a/src/mol-data/int/ordered-set.ts b/src/mol-data/int/ordered-set.ts
index ba2f61dcf..e9abea226 100644
--- a/src/mol-data/int/ordered-set.ts
+++ b/src/mol-data/int/ordered-set.ts
@@ -40,9 +40,17 @@ namespace OrderedSet {
     export function forEach<T extends number, Ctx>(set: OrderedSet<T>, f: (v: T, i: number, ctx: Ctx) => void, ctx?: Ctx): Ctx {
         return Base.forEach(set as any, f as any, ctx);
     }
+
+    export function isInterval<T extends number = number>(set: OrderedSet<T>): set is Interval<T> {
+        return Interval.is(set);
+    }
+
+    export function isSortedArray<T extends number = number>(set: OrderedSet<T>): set is SortedArray<T> {
+        return !Interval.is(set);
+    }
 }
 
-type OrderedSet<T extends number = number> = Interval | SortedArray<T>
+type OrderedSet<T extends number = number> = Interval<T> | SortedArray<T>
 //{ '@type': 'int-interval' | 'int-sorted-array' }
 
 export default OrderedSet
\ No newline at end of file
diff --git a/src/mol-data/int/segmentation.ts b/src/mol-data/int/segmentation.ts
index 51f5c5ecd..8f7c58db6 100644
--- a/src/mol-data/int/segmentation.ts
+++ b/src/mol-data/int/segmentation.ts
@@ -9,22 +9,22 @@ import OrderedSet from './ordered-set'
 import * as Impl from './impl/segmentation'
 
 namespace Segmentation {
-    export interface Segment { index: number, start: number, end: number }
+    export interface Segment<T extends number = number> { index: number, start: number, end: number }
 
-    export const create: (segs: ArrayLike<number>) => Segmentation = Impl.create as any;
-    export const ofOffsets: (offsets: ArrayLike<number>, bounds: Interval) => Segmentation = Impl.ofOffsets as any;
+    export const create: <T extends number = number>(segs: ArrayLike<T>) => Segmentation<T> = Impl.create as any;
+    export const ofOffsets: <T extends number = number>(offsets: ArrayLike<T>, bounds: Interval) => Segmentation<T> = Impl.ofOffsets as any;
 
-    export const count: (segs: Segmentation) => number = Impl.count as any;
-    export const getSegment: (segs: Segmentation, value: number) => number = Impl.getSegment as any;
-    export const projectValue: (segs: Segmentation, set: OrderedSet, value: number) => Interval = Impl.projectValue as any;
+    export const count: <T extends number = number>(segs: Segmentation<T>) => number = Impl.count as any;
+    export const getSegment: <T extends number = number>(segs: Segmentation<T>, value: T) => number = Impl.getSegment as any;
+    export const projectValue: <T extends number = number>(segs: Segmentation<T>, set: OrderedSet<T>, value: T) => Interval = Impl.projectValue as any;
 
     // Segment iterator that mutates a single segment object to mark all the segments.
-    export const transientSegments: (segs: Segmentation, set: OrderedSet, segment?: Segment) => Impl.SegmentIterator = Impl.segments as any;
+    export const transientSegments: <T extends number = number>(segs: Segmentation<T>, set: OrderedSet<T>, segment?: Segment<T>) => Impl.SegmentIterator = Impl.segments as any;
 }
 
-interface Segmentation {
+interface Segmentation<T extends number = number> {
     '@type': 'segmentation',
-    readonly segments: ArrayLike<number>,
+    readonly segments: ArrayLike<T>,
     readonly segmentMap: ArrayLike<number>,
     readonly count: number
 }
diff --git a/src/mol-model/structure/model/formats/mmcif.ts b/src/mol-model/structure/model/formats/mmcif.ts
index 31f3abb45..abd3a7a59 100644
--- a/src/mol-model/structure/model/formats/mmcif.ts
+++ b/src/mol-model/structure/model/formats/mmcif.ts
@@ -23,6 +23,7 @@ import { getSecondaryStructureMmCif } from './mmcif/secondary-structure';
 import { getSequence } from './mmcif/sequence';
 import { sortAtomSite } from './mmcif/sort';
 import { mmCIF_Database, mmCIF_Schema } from 'mol-io/reader/cif/schema/mmcif';
+import { Element } from '../../../structure'
 
 import mmCIF_Format = Format.mmCIF
 type AtomSite = mmCIF_Database['atom_site']
@@ -40,7 +41,7 @@ function findHierarchyOffsets(atom_site: AtomSite) {
     if (atom_site._rowCount === 0) return { residues: [], chains: [] };
 
     const start = 0, end = atom_site._rowCount;
-    const residues = [start], chains = [start];
+    const residues = [start as Element], chains = [start as Element];
 
     const { label_entity_id, label_asym_id, label_seq_id, auth_seq_id, pdbx_PDB_ins_code, label_comp_id } = atom_site;
 
@@ -52,8 +53,8 @@ function findHierarchyOffsets(atom_site: AtomSite) {
             || !pdbx_PDB_ins_code.areValuesEqual(i - 1, i)
             || !label_comp_id.areValuesEqual(i - 1, i);
 
-        if (newResidue) residues[residues.length] = i;
-        if (newChain) chains[chains.length] = i;
+        if (newResidue) residues[residues.length] = i as Element;
+        if (newChain) chains[chains.length] = i as Element;
     }
     return { residues, chains };
 }
diff --git a/src/mol-model/structure/model/formats/mmcif/ihm.ts b/src/mol-model/structure/model/formats/mmcif/ihm.ts
index 1dfdc1c1d..8fe3b4f4a 100644
--- a/src/mol-model/structure/model/formats/mmcif/ihm.ts
+++ b/src/mol-model/structure/model/formats/mmcif/ihm.ts
@@ -12,6 +12,7 @@ import { getCoarseKeys } from '../../properties/utils/coarse-keys';
 import { UUID } from 'mol-util';
 import { Segmentation, Interval } from 'mol-data/int';
 import { Mat3, Tensor } from 'mol-math/linear-algebra';
+import { Element } from '../../../structure'
 
 export function getIHMCoarse(data: mmCIF, entities: Entities): { hierarchy: CoarseHierarchy, conformation: CoarseConformation } {
     if (data.ihm_model_list._rowCount === 0) return { hierarchy: CoarseHierarchy.Empty, conformation: void 0 as any };
@@ -71,9 +72,9 @@ function getGaussianConformation(data: mmCIF['ihm_gaussian_obj_site']): CoarseGa
 }
 
 function getChainSegments(asym_id: Column<string>) {
-    const offsets = [0];
+    const offsets = [0 as Element];
     for (let i = 1, _i = asym_id.rowCount; i < _i; i++) {
-        if (!asym_id.areValuesEqual(i - 1, i)) offsets[offsets.length] = i;
+        if (!asym_id.areValuesEqual(i - 1, i)) offsets[offsets.length] = i as Element;
     }
 
     return Segmentation.ofOffsets(offsets, Interval.ofBounds(0, asym_id.rowCount));
diff --git a/src/mol-model/structure/model/properties/atomic/hierarchy.ts b/src/mol-model/structure/model/properties/atomic/hierarchy.ts
index 9b04d0f36..513f36110 100644
--- a/src/mol-model/structure/model/properties/atomic/hierarchy.ts
+++ b/src/mol-model/structure/model/properties/atomic/hierarchy.ts
@@ -7,7 +7,8 @@
 import { Column, Table } from 'mol-data/db'
 import { Segmentation } from 'mol-data/int'
 import { mmCIF_Schema as mmCIF } from 'mol-io/reader/cif/schema/mmcif'
-import { ElementSymbol} from '../../types'
+import { ElementSymbol } from '../../types'
+import { Element } from '../../../structure'
 
 export const AtomsSchema = {
     type_symbol: Column.Schema.Aliased<ElementSymbol>(mmCIF.atom_site.type_symbol),
@@ -47,8 +48,8 @@ export interface AtomicData {
 }
 
 export interface AtomicSegments {
-    residueSegments: Segmentation,
-    chainSegments: Segmentation
+    residueSegments: Segmentation<Element>,
+    chainSegments: Segmentation<Element>
     // TODO: include entity segments?
 }
 
diff --git a/src/mol-model/structure/model/properties/coarse/hierarchy.ts b/src/mol-model/structure/model/properties/coarse/hierarchy.ts
index 52748b367..81a7be2dd 100644
--- a/src/mol-model/structure/model/properties/coarse/hierarchy.ts
+++ b/src/mol-model/structure/model/properties/coarse/hierarchy.ts
@@ -7,6 +7,7 @@
 import { mmCIF_Database as mmCIF } from 'mol-io/reader/cif/schema/mmcif'
 import { Column } from 'mol-data/db'
 import { Segmentation } from 'mol-data/int';
+import { Element } from '../../../structure'
 
 export interface CoarsedElementKeys {
     // assign a key to each element
@@ -27,7 +28,7 @@ export interface CoarseElementData {
     seq_id_begin: Column<number>,
     seq_id_end: Column<number>,
 
-    chainSegments: Segmentation
+    chainSegments: Segmentation<Element>
 }
 
 export type CoarseElements = CoarsedElementKeys & CoarseElementData
diff --git a/src/mol-model/structure/query/modifiers.ts b/src/mol-model/structure/query/modifiers.ts
index a8497a16e..3b332ff7f 100644
--- a/src/mol-model/structure/query/modifiers.ts
+++ b/src/mol-model/structure/query/modifiers.ts
@@ -6,7 +6,7 @@
 
 import { Segmentation } from 'mol-data/int';
 import { RuntimeContext } from 'mol-task';
-import { Structure, Unit, Element } from '../structure';
+import { Structure, Unit } from '../structure';
 import Query from './query';
 import Selection from './selection';
 import { UniqueStructuresBuilder } from './utils/builders';
@@ -29,7 +29,7 @@ function getWholeResidues(ctx: RuntimeContext, source: Structure, structure: Str
         while (residuesIt.hasNext) {
             const rI = residuesIt.move().index;
             for (let j = residueSegments.segments[rI], _j = residueSegments.segments[rI + 1]; j < _j; j++) {
-                builder.addElement(j as Element);
+                builder.addElement(j);
             }
         }
         builder.commitUnit();
diff --git a/src/mol-model/structure/structure/element.ts b/src/mol-model/structure/structure/element.ts
index b39c810dc..c9add11f9 100644
--- a/src/mol-model/structure/structure/element.ts
+++ b/src/mol-model/structure/structure/element.ts
@@ -17,18 +17,6 @@ namespace Element {
     export type Index = { readonly '@type': 'element-index' } & number
     export type Indices = OrderedSet<Index>
 
-    // export interface Packed { '@type': Tuple['@type'] }
-    // export namespace Packed {
-    //     export const Zero: Packed = Tuple.Zero;
-    //     export const create: (unit: number, index: number) => Packed = Tuple.create;
-    //     export const is: (x: any) => x is Packed = Tuple.is;
-    //     export const unitId: (e: Packed) => number = Tuple.fst;
-    //     export const elementIndex: (e: Packed) => number = Tuple.snd;
-    //     export const areEqual: (e: Packed, b: Packed) => boolean = Tuple.areEqual;
-    //     export const hashCode: (e: Packed) => number = Tuple.hashCode;
-    //     export function createEmptyArray(n: number): Packed[] { return new Float64Array(n) as any; }
-    // }
-
     /** All the information required to access element properties */
     export interface Location<U = Unit> {
         unit: U,
diff --git a/src/mol-model/structure/structure/util/lookup3d.ts b/src/mol-model/structure/structure/util/lookup3d.ts
index c6cc3ce85..19187af2f 100644
--- a/src/mol-model/structure/structure/util/lookup3d.ts
+++ b/src/mol-model/structure/structure/util/lookup3d.ts
@@ -19,6 +19,7 @@ export class StructureLookup3D {
         return this.unitLookup.find(x, y, z, radius);
     }
 
+    // TODO: find another efficient way how to implement this instead of using "tuple".
     // find(x: number, y: number, z: number, radius: number): Result<Element.Packed> {
     //     Result.reset(this.result);
     //     const { units } = this.structure;
-- 
GitLab