File size: 4,313 Bytes
5641073
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/**
 * @author jdiaz5513
 */

import initTrace from "debug";

import { ListElementSize } from "../list-element-size";
import { List } from "./list";
import { Pointer, validate, getContent } from "./pointer";
import { PointerType } from "./pointer-type";

const trace = initTrace("capnp:data");
trace("load");

/**
 * A generic blob of bytes. Can be converted to a DataView or Uint8Array to access its contents using `toDataView()` and
 * `toUint8Array()`. Use `copyBuffer()` to copy an entire buffer at once.
 *
 * @export
 * @class Data
 * @extends {List<number>}
 */

export class Data extends List<number> {
  static fromPointer(pointer: Pointer): Data {
    validate(PointerType.LIST, pointer, ListElementSize.BYTE);

    return this._fromPointerUnchecked(pointer);
  }

  protected static _fromPointerUnchecked(pointer: Pointer): Data {
    return new this(
      pointer.segment,
      pointer.byteOffset,
      pointer._capnp.depthLimit
    );
  }

  /**
   * Copy the contents of `src` into this Data pointer. If `src` is smaller than the length of this pointer then the
   * remaining bytes will be zeroed out. Extra bytes in `src` are ignored.
   *
   * @param {(ArrayBuffer | ArrayBufferView)} src The source buffer.
   * @returns {void}
   */

  // TODO: Would be nice to have a way to zero-copy a buffer by allocating a new segment into the message with that
  // buffer data.

  copyBuffer(src: ArrayBuffer | ArrayBufferView): void {
    const c = getContent(this);

    const dstLength = this.getLength();
    const srcLength = src.byteLength;

    const i =
      src instanceof ArrayBuffer
        ? new Uint8Array(src)
        : new Uint8Array(
            src.buffer,
            src.byteOffset,
            Math.min(dstLength, srcLength)
          );

    const o = new Uint8Array(c.segment.buffer, c.byteOffset, this.getLength());

    o.set(i);

    if (dstLength > srcLength) {
      trace(
        "Zeroing out remaining %d bytes after copy into %s.",
        dstLength - srcLength,
        this
      );

      o.fill(0, srcLength, dstLength);
    } else if (dstLength < srcLength) {
      trace(
        "Truncated %d bytes from source buffer while copying to %s.",
        srcLength - dstLength,
        this
      );
    }
  }

  /**
   * Read a byte from the specified offset.
   *
   * @param {number} byteOffset The byte offset to read.
   * @returns {number} The byte value.
   */

  get(byteOffset: number): number {
    const c = getContent(this);
    return c.segment.getUint8(c.byteOffset + byteOffset);
  }

  /**
   * Write a byte at the specified offset.
   *
   * @param {number} byteOffset The byte offset to set.
   * @param {number} value The byte value to set.
   * @returns {void}
   */

  set(byteOffset: number, value: number): void {
    const c = getContent(this);
    c.segment.setUint8(c.byteOffset + byteOffset, value);
  }

  /**
   * Creates a **copy** of the underlying buffer data and returns it as an ArrayBuffer.
   *
   * To obtain a reference to the underlying buffer instead, use `toUint8Array()` or `toDataView()`.
   *
   * @returns {ArrayBuffer} A copy of this data buffer.
   */

  toArrayBuffer(): ArrayBuffer {
    const c = getContent(this);
    return c.segment.buffer.slice(
      c.byteOffset,
      c.byteOffset + this.getLength()
    );
  }

  /**
   * Convert this Data pointer to a DataView representing the pointer's contents.
   *
   * WARNING: The DataView references memory from a message segment, so do not venture outside the bounds of the
   * DataView or else BAD THINGS.
   *
   * @returns {DataView} A live reference to the underlying buffer.
   */

  toDataView(): DataView {
    const c = getContent(this);
    return new DataView(c.segment.buffer, c.byteOffset, this.getLength());
  }

  toString(): string {
    return `Data_${super.toString()}`;
  }

  /**
   * Convert this Data pointer to a Uint8Array representing the pointer's contents.
   *
   * WARNING: The Uint8Array references memory from a message segment, so do not venture outside the bounds of the
   * Uint8Array or else BAD THINGS.
   *
   * @returns {DataView} A live reference to the underlying buffer.
   */

  toUint8Array(): Uint8Array {
    const c = getContent(this);
    return new Uint8Array(c.segment.buffer, c.byteOffset, this.getLength());
  }
}