@gmod/hic 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ export { readerFromFilehandle } from './reader.ts'
4
4
  export type { HicConfig } from './hicFile.ts'
5
5
  export type { ContactRecords } from './contactRecords.ts'
6
6
  export type {
7
+ BaseOpts,
7
8
  Chromosome,
8
9
  HicMetadata,
9
10
  HicRegion,
package/src/lru.ts CHANGED
@@ -65,8 +65,6 @@ export default class LRU<K, V> {
65
65
  }
66
66
  }
67
67
 
68
- // Used to evict a rejected in-flight promise so the next caller retries
69
- // rather than resolving against a cached failure forever.
70
68
  delete(key: K) {
71
69
  const existing = this.map.get(key)
72
70
  if (existing !== undefined) {
@@ -1,6 +1,6 @@
1
1
  import BinaryParser from './binary.ts'
2
2
 
3
- import type { Reader } from './types.ts'
3
+ import type { BaseOpts, Reader } from './types.ts'
4
4
 
5
5
  const DOUBLE = 8
6
6
 
@@ -25,7 +25,7 @@ export default class NormalizationVector {
25
25
  this.dataType = dataType
26
26
  }
27
27
 
28
- async getValues(start: number, end: number) {
28
+ async getValues(start: number, end: number, opts?: BaseOpts) {
29
29
  // The read below clamps to `nValues`, so the cache can never cover past it.
30
30
  // Compare against the clamped bound or a request that runs off the end of
31
31
  // the vector — reachable when the assembly's refseq is longer than the size
@@ -33,11 +33,27 @@ export default class NormalizationVector {
33
33
  // forever, and every call re-reads the same range from the file.
34
34
  const wanted = Math.min(end, this.nValues)
35
35
  if (!this.cache || start < this.cache.start || wanted > this.cache.end) {
36
- const adjustedStart = Math.max(0, start - 1000)
37
36
  const adjustedEnd = Math.min(this.nValues, end + 1000)
37
+ // Clamped against `adjustedEnd`, and not merely against zero, or a window
38
+ // starting past the vector produces a NEGATIVE `n` — and a negative read
39
+ // length reaches the reader as `new Uint8Array(-8)`, a RangeError that
40
+ // fails the whole fetch instead of the empty answer the caller below
41
+ // already handles. The padding is what sets how far past is far enough:
42
+ // more than 1000 bins, which at a fine binsize is not far at all.
43
+ //
44
+ // Reachable exactly where the comment above says: the assembly's refseq
45
+ // is longer than the size the `.hic` recorded for that chromosome, so a
46
+ // view of the tail of it asks for bins the vector never had.
47
+ const adjustedStart = Math.min(Math.max(0, start - 1000), adjustedEnd)
38
48
  const startPosition = this.filePosition + adjustedStart * this.dataType
39
49
  const n = adjustedEnd - adjustedStart
40
- const data = await this.file.read(startPosition, n * this.dataType)
50
+ // Nothing to read when the window is entirely past the vector, and on a
51
+ // remote file a zero-length range request is still a round trip — one per
52
+ // region pair, on every fetch, for as long as the view stays there.
53
+ const data =
54
+ n > 0
55
+ ? await this.file.read(startPosition, n * this.dataType, opts)
56
+ : new ArrayBuffer(0)
41
57
  const parser = new BinaryParser(new DataView(data))
42
58
  const values = new Float64Array(n)
43
59
  for (let i = 0; i < n; i++) {
package/src/reader.ts CHANGED
@@ -1,10 +1,12 @@
1
- import type { Reader } from './types.ts'
1
+ import type { BaseOpts, Reader } from './types.ts'
2
2
  import type { GenericFilehandle } from 'generic-filehandle2'
3
3
 
4
4
  export function readerFromFilehandle(filehandle: GenericFilehandle): Reader {
5
5
  return {
6
- async read(position: number, length: number) {
7
- const buf = await filehandle.read(length, position)
6
+ async read(position: number, length: number, opts?: BaseOpts) {
7
+ const buf = await filehandle.read(length, position, {
8
+ signal: opts?.signal,
9
+ })
8
10
  return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength)
9
11
  },
10
12
  }
package/src/types.ts CHANGED
@@ -4,9 +4,20 @@
4
4
  * reads past the end to discover whether a file carries normalization data at
5
5
  * all. `generic-filehandle2` handles behave this way (a remote 416 included),
6
6
  * and `readerFromFilehandle` adapts one to this shape.
7
+ *
8
+ * A reader that ignores `opts.signal` still cancels, only later: the parser
9
+ * checks the signal when a fetch of blocks lands.
7
10
  */
8
11
  export interface Reader {
9
- read: (position: number, length: number) => Promise<ArrayBuffer>
12
+ read: (
13
+ position: number,
14
+ length: number,
15
+ opts?: BaseOpts,
16
+ ) => Promise<ArrayBuffer>
17
+ }
18
+
19
+ export interface BaseOpts {
20
+ signal?: AbortSignal
10
21
  }
11
22
 
12
23
  /**
@@ -30,7 +41,7 @@ export type ProgressCallback = (current: number, total: number) => void
30
41
  * belongs to the operation a caller is waiting on, and a file-wide callback
31
42
  * could not say which of several concurrent fetches it was describing.
32
43
  */
33
- export interface ProgressOpts {
44
+ export interface ProgressOpts extends BaseOpts {
34
45
  onProgress?: ProgressCallback
35
46
  }
36
47