Skip to content

Commit 4cc2c4a

Browse files
committed
Add DataView to standard library
1 parent 6f3209e commit 4cc2c4a

File tree

5 files changed

+5042
-0
lines changed

5 files changed

+5042
-0
lines changed

std/assembly/dataview.ts

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import { HEADER_SIZE } from "./internal/arraybuffer";
2+
3+
export class DataView {
4+
constructor(
5+
readonly buffer: ArrayBuffer,
6+
readonly byteOffset: i32 = 0,
7+
readonly byteLength: i32 = i32.MIN_VALUE,
8+
) {
9+
if (byteLength === i32.MIN_VALUE) byteLength = buffer.byteLength - byteOffset;
10+
11+
if (byteOffset < 0) throw new RangeError("byteOffset cannot be negative");
12+
if (byteLength < 0) throw new RangeError("byteLength cannot be negative");
13+
if (byteOffset + byteLength > buffer.byteLength) throw new RangeError("Length out of range of buffer");
14+
}
15+
16+
@inline
17+
getFloat32(byteOffset: i32, littleEndian: boolean = false): f32 {
18+
var result: u32 = load<u32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
19+
return reinterpret<f32>(littleEndian ? result : bswap<u32>(result));
20+
}
21+
22+
@inline
23+
getFloat64(byteOffset: i32, littleEndian: boolean = false): f64 {
24+
var result: u64 = load<u64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
25+
return reinterpret<f64>(littleEndian ? result : bswap<u64>(result));
26+
}
27+
28+
@inline
29+
getInt8(byteOffset: i32): i8 {
30+
return load<i8>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
31+
}
32+
33+
@inline
34+
getInt16(byteOffset: i32, littleEndian: boolean = false): i16 {
35+
var result: i16 = load<i16>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
36+
return littleEndian ? result : bswap<i16>(result);
37+
}
38+
39+
@inline
40+
getInt32(byteOffset: i32, littleEndian: boolean = false): i32 {
41+
var result: i32 = load<i32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
42+
return littleEndian ? result : bswap<i32>(result);
43+
}
44+
45+
@inline
46+
getUint8(byteOffset: i32): u8 {
47+
return load<u8>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
48+
}
49+
50+
@inline
51+
getUint16(byteOffset: i32, littleEndian: boolean = false): u16 {
52+
var result: u16 = load<u16>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
53+
return littleEndian ? result : bswap<u16>(result);
54+
}
55+
56+
@inline
57+
getUint32(byteOffset: i32, littleEndian: boolean = false): u32 {
58+
var result: u32 = load<u32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
59+
return littleEndian ? result : bswap<u32>(result);
60+
}
61+
62+
@inline
63+
setFloat32(byteOffset: i32, value: f32, littleEndian: boolean = false): void {
64+
var input: f32 = littleEndian ? value : reinterpret<f32>(bswap<u32>(reinterpret<u32>(value)));
65+
store<f32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, input, HEADER_SIZE);
66+
}
67+
68+
@inline
69+
setFloat64(byteOffset: i32, value: f64, littleEndian: boolean = false): void {
70+
var input: f64 = littleEndian ? value : reinterpret<f64>(bswap<u64>(reinterpret<u64>(value)));
71+
store<f64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, input, HEADER_SIZE);
72+
}
73+
74+
@inline
75+
setInt8(byteOffset: i32, value: i8): void {
76+
store<i8>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, value, HEADER_SIZE);
77+
}
78+
79+
@inline
80+
setInt16(byteOffset: i32, value: i16, littleEndian: boolean = false): void {
81+
store<i16>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<i16>(value), HEADER_SIZE);
82+
}
83+
84+
@inline
85+
setInt32(byteOffset: i32, value: i32, littleEndian: boolean = false): void {
86+
store<i32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<i32>(value), HEADER_SIZE);
87+
}
88+
89+
@inline
90+
setUint8(byteOffset: i32, value: u8): void {
91+
store<u8>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, value, HEADER_SIZE);
92+
}
93+
94+
@inline
95+
setUint16(byteOffset: i32, value: u16, littleEndian: boolean = false): void {
96+
store<u16>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<u16>(value), HEADER_SIZE);
97+
}
98+
99+
@inline
100+
setUint32(byteOffset: i32, value: u32, littleEndian: boolean = false): void {
101+
store<u32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<u32>(value), HEADER_SIZE);
102+
}
103+
104+
/**
105+
* Non-standard additions that makes sense in WebAssembly, but won't work in JS
106+
*/
107+
108+
@inline
109+
getInt64(byteOffset: i32, littleEndian: boolean = false): i64 {
110+
var result: i64 = load<i64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
111+
return littleEndian ? result : bswap<i64>(result);
112+
}
113+
114+
@inline
115+
getUint64(byteOffset: i32, littleEndian: boolean = false): u64 {
116+
var result: u64 = load<u64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
117+
return littleEndian ? result : bswap<u64>(result);
118+
}
119+
120+
@inline
121+
setInt64(byteOffset: i32, value: i64, littleEndian: boolean = false): void {
122+
store<i64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<i64>(value), HEADER_SIZE);
123+
}
124+
125+
@inline
126+
setUint64(byteOffset: i32, value: u64, littleEndian: boolean = false): void {
127+
store<u64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<u64>(value), HEADER_SIZE);
128+
}
129+
}

std/assembly/index.d.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,58 @@ declare class ArrayBuffer {
380380
slice(begin?: i32, end?: i32): ArrayBuffer;
381381
}
382382

383+
/** The `DataView` view provides a low-level interface for reading and writing multiple number types in a binary `ArrayBuffer`, without having to care about the platform's endianness. */
384+
declare class DataView {
385+
/** The `buffer` accessor property represents the `ArrayBuffer` or `SharedArrayBuffer` referenced by the `DataView` at construction time. */
386+
readonly buffer: ArrayBuffer;
387+
/** The `byteLength` accessor property represents the length (in bytes) of this view from the start of its `ArrayBuffer` or `SharedArrayBuffer`. */
388+
readonly byteLength: i32;
389+
/** The `byteOffset` accessor property represents the offset (in bytes) of this view from the start of its `ArrayBuffer` or `SharedArrayBuffer`. */
390+
readonly byteOffset: i32;
391+
/** Constructs a new `DataView` with the given properties */
392+
constructor(buffer: ArrayBuffer, byteOffset?: i32, byteLength?: i32);
393+
/** The `getFloat32()` method gets a signed 32-bit float (float) at the specified byte offset from the start of the `DataView`. */
394+
getFloat32(byteOffset: i32, littleEndian?: boolean): f32
395+
/** The `getFloat64()` method gets a signed 64-bit float (double) at the specified byte offset from the start of the `DataView`. */
396+
getFloat64(byteOffset: i32, littleEndian?: boolean): f64
397+
/** The `getInt8()` method gets a signed 8-bit integer (byte) at the specified byte offset from the start of the `DataView`. */
398+
getInt8(byteOffset: i32): i8
399+
/** The `getInt16()` method gets a signed 16-bit integer (short) at the specified byte offset from the start of the `DataView`. */
400+
getInt16(byteOffset: i32, littleEndian?: boolean): i16
401+
/** The `getInt32()` method gets a signed 32-bit integer (long) at the specified byte offset from the start of the `DataView`. */
402+
getInt32(byteOffset: i32, littleEndian?: boolean): i32
403+
/** The `getInt64()` method gets a signed 64-bit integer (long long) at the specified byte offset from the start of the `DataView`. */
404+
getInt64(byteOffset: i32, littleEndian?: boolean): i64
405+
/** The `getUint8()` method gets an unsigned 8-bit integer (unsigned byte) at the specified byte offset from the start of the `DataView`. */
406+
getUint8(byteOffset: i32): u8
407+
/** The `getUint16()` method gets an unsigned 16-bit integer (unsigned short) at the specified byte offset from the start of the `DataView`. */
408+
getUint16(byteOffset: i32, littleEndian?: boolean): u16
409+
/** The `getUint32()` method gets an unsigned 32-bit integer (unsigned long) at the specified byte offset from the start of the `DataView`. */
410+
getUint32(byteOffset: i32, littleEndian?: boolean): u32
411+
/** The `getUint64()` method gets an unsigned 64-bit integer (unsigned long long) at the specified byte offset from the start of the `DataView`. */
412+
getUint64(byteOffset: i32, littleEndian?: boolean): u64
413+
/** The `setFloat32()` method stores a signed 32-bit float (float) value at the specified byte offset from the start of the `DataView`. */
414+
setFloat32(byteOffset: i32, value: f32, littleEndian?: boolean): void
415+
/** The `setFloat64()` method stores a signed 64-bit float (double) value at the specified byte offset from the start of the `DataView`. */
416+
setFloat64(byteOffset: i32, value: f64, littleEndian?: boolean): void
417+
/** The `setInt8()` method stores a signed 8-bit integer (byte) value at the specified byte offset from the start of the `DataView`. */
418+
setInt8(byteOffset: i32, value: i8): void
419+
/** The `setInt16()` method stores a signed 16-bit integer (short) value at the specified byte offset from the start of the `DataView`. */
420+
setInt16(byteOffset: i32, value: i16, littleEndian?: boolean): void
421+
/** The `setInt32()` method stores a signed 32-bit integer (long) value at the specified byte offset from the start of the `DataView`. */
422+
setInt32(byteOffset: i32, value: i32, littleEndian?: boolean): void
423+
/** The `setInt64()` method stores a signed 64-bit integer (long long) value at the specified byte offset from the start of the `DataView`. */
424+
setInt64(byteOffset: i32, value: i64, littleEndian?: boolean): void
425+
/** The `setUint8()` method stores an unsigned 8-bit integer (byte) value at the specified byte offset from the start of the `DataView`. */
426+
setUint8(byteOffset: i32, value: u8): void
427+
/** The `setUint16()` method stores an unsigned 16-bit integer (unsigned short) value at the specified byte offset from the start of the `DataView`. */
428+
setUint16(byteOffset: i32, value: u16, littleEndian?: boolean): void
429+
/** The `setUint32()` method stores an unsigned 32-bit integer (unsigned long) value at the specified byte offset from the start of the `DataView`. */
430+
setUint32(byteOffset: i32, value: u32, littleEndian?: boolean): void
431+
/** The `setUint64()` method stores an unsigned 64-bit integer (unsigned long long) value at the specified byte offset from the start of the `DataView`. */
432+
setUint64(byteOffset: i32, value: u64, littleEndian?: boolean): void
433+
}
434+
383435
/** Interface for a typed view on an array buffer. */
384436
interface ArrayBufferView<T> {
385437
[key: number]: T;

std/portable/index.d.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,50 @@ declare class ArrayBuffer {
243243
slice(begin?: i32, end?: i32): ArrayBuffer;
244244
}
245245

246+
/** The `DataView` view provides a low-level interface for reading and writing multiple number types in a binary `ArrayBuffer`, without having to care about the platform's endianness. */
247+
declare class DataView {
248+
/** The `buffer` accessor property represents the `ArrayBuffer` or `SharedArrayBuffer` referenced by the `DataView` at construction time. */
249+
readonly buffer: ArrayBuffer;
250+
/** The `byteLength` accessor property represents the length (in bytes) of this view from the start of its `ArrayBuffer` or `SharedArrayBuffer`. */
251+
readonly byteLength: i32;
252+
/** The `byteOffset` accessor property represents the offset (in bytes) of this view from the start of its `ArrayBuffer` or `SharedArrayBuffer`. */
253+
readonly byteOffset: i32;
254+
/** Constructs a new `DataView` with the given properties */
255+
constructor(buffer: ArrayBuffer, byteOffset?: i32, byteLength?: i32);
256+
/** The `getFloat32()` method gets a signed 32-bit float (float) at the specified byte offset from the start of the `DataView`. */
257+
getFloat32(byteOffset: i32, littleEndian?: boolean): f32
258+
/** The `getFloat64()` method gets a signed 64-bit float (double) at the specified byte offset from the start of the `DataView`. */
259+
getFloat64(byteOffset: i32, littleEndian?: boolean): f64
260+
/** The `getInt8()` method gets a signed 8-bit integer (byte) at the specified byte offset from the start of the `DataView`. */
261+
getInt8(byteOffset: i32): i8
262+
/** The `getInt16()` method gets a signed 16-bit integer (short) at the specified byte offset from the start of the `DataView`. */
263+
getInt16(byteOffset: i32, littleEndian?: boolean): i16
264+
/** The `getInt32()` method gets a signed 32-bit integer (long) at the specified byte offset from the start of the `DataView`. */
265+
getInt32(byteOffset: i32, littleEndian?: boolean): i32
266+
/** The `getUint8()` method gets an unsigned 8-bit integer (unsigned byte) at the specified byte offset from the start of the `DataView`. */
267+
getUint8(byteOffset: i32): u8
268+
/** The `getUint16()` method gets an unsigned 16-bit integer (unsigned short) at the specified byte offset from the start of the `DataView`. */
269+
getUint16(byteOffset: i32, littleEndian?: boolean): u16
270+
/** The `getUint32()` method gets an unsigned 32-bit integer (unsigned long) at the specified byte offset from the start of the `DataView`. */
271+
getUint32(byteOffset: i32, littleEndian?: boolean): u32
272+
/** The `setFloat32()` method stores a signed 32-bit float (float) value at the specified byte offset from the start of the `DataView`. */
273+
setFloat32(byteOffset: i32, value: f32, littleEndian?: boolean): void
274+
/** The `setFloat64()` method stores a signed 64-bit float (double) value at the specified byte offset from the start of the `DataView`. */
275+
setFloat64(byteOffset: i32, value: f64, littleEndian?: boolean): void
276+
/** The `setInt8()` method stores a signed 8-bit integer (byte) value at the specified byte offset from the start of the `DataView`. */
277+
setInt8(byteOffset: i32, value: i8): void
278+
/** The `setInt16()` method stores a signed 16-bit integer (short) value at the specified byte offset from the start of the `DataView`. */
279+
setInt16(byteOffset: i32, value: i16, littleEndian?: boolean): void
280+
/** The `setInt32()` method stores a signed 32-bit integer (long) value at the specified byte offset from the start of the `DataView`. */
281+
setInt32(byteOffset: i32, value: i32, littleEndian?: boolean): void
282+
/** The `setUint8()` method stores an unsigned 8-bit integer (byte) value at the specified byte offset from the start of the `DataView`. */
283+
setUint8(byteOffset: i32, value: u8): void
284+
/** The `setUint16()` method stores an unsigned 16-bit integer (unsigned short) value at the specified byte offset from the start of the `DataView`. */
285+
setUint16(byteOffset: i32, value: u16, littleEndian?: boolean): void
286+
/** The `setUint32()` method stores an unsigned 32-bit integer (unsigned long) value at the specified byte offset from the start of the `DataView`. */
287+
setUint32(byteOffset: i32, value: u32, littleEndian?: boolean): void
288+
}
289+
246290
declare class Array<T> {
247291
[key: number]: T;
248292
length: i32;

0 commit comments

Comments
 (0)