Skip to content

[Implement] Buffer#inspect #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions assembly/buffer/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { BLOCK_MAXSIZE, BLOCK, BLOCK_OVERHEAD } from "rt/common";
import { E_INVALIDLENGTH, E_INDEXOUTOFRANGE } from "util/error";
import { Uint8Array } from "typedarray";
const BUFFER_INSPECT_HEADER_START = "<Buffer ";
const BUFFER_INSPECT_HEADER_BYTE_LEN = 16;

export let INSPECT_MAX_BYTES: i32 = 50;

export class Buffer extends Uint8Array {
constructor(size: i32) {
Expand Down Expand Up @@ -237,6 +241,72 @@ export class Buffer extends Uint8Array {
store<i64>(this.dataStart + offset, bswap<i64>(reinterpret<i64>(value)));
return offset + 8;
}

/**
* Calculate an inspectable string to print to the console.
*
* @example
* let result = Buffer.from([1, 2, 3, 4, 5]).inspect();
* // '<Buffer 01 02 03 04 05>'
*/
inspect(): string {
let byteLength = this.byteLength;
if (INSPECT_MAX_BYTES == 0 || byteLength == 0) return "<Buffer >";

// Calculate if an elipsis will be in the string
let elipsisEnd = byteLength > INSPECT_MAX_BYTES;
let maxBytes = elipsisEnd ? INSPECT_MAX_BYTES : byteLength;

// find the start of the buffer
let dataStart = this.dataStart;

/**
* Formula for stringLength is calculated by adding the constant character count
* to the number of visible bytes multiplied by 3, and adding 3 more for an ellipsis
* if the total number of visible bytes is less than the actual byteLength.
*
* @example
* let stringLength = (3 * maxBytes) + len("<Buffer ") + len(">") + (elipsisEnd ? 3 : 0);
*
* // This can be reduced to...
* let stringLength = (3 * maxBytes) + 8 + (elipsisEnd ? 3 : 0);
*
* // finally, `a * 3 + 3` is the same thing as `(a + 1) * 3`
* // we can cast `elipsisEnd` to an integer `1 | 0`
* let stringLength = 3 * (maxBytes + i32(elipsisEnd)) + 8;
*/
let stringLength = 3 * (maxBytes + i32(elipsisEnd)) + 8;

// create the result
let result = __alloc(stringLength << 1, idof<String>());

// copy the 16 "<Buffer " bytes
memory.copy(
result,
changetype<usize>(BUFFER_INSPECT_HEADER_START),
BUFFER_INSPECT_HEADER_BYTE_LEN,
);

// Start writing at index 8
let writeOffset = result + BUFFER_INSPECT_HEADER_BYTE_LEN;
for (let i = 0; i < maxBytes; i++, writeOffset += 6) {
let byte = <u32>load<u8>(dataStart + <usize>i);

store<u32>(writeOffset, Buffer.HEX.charsFromByte(byte));
if (i == maxBytes - 1) {
if (elipsisEnd) {
// make this a single 64 bit store
store<u64>(writeOffset, <u64>0x003e_002e_002e_002e, 4); // "...>"
} else {
store<u16>(writeOffset, <u16>62, 4); // ">"
}
} else {
store<u16>(writeOffset, <u16>32, 4); // " "
}
}

return changetype<string>(result);
}
}

export namespace Buffer {
Expand Down
20 changes: 20 additions & 0 deletions assembly/node.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ declare class Buffer extends Uint8Array {
readUInt8(offset?: i32): u8;
/** Writes an inputted value to the buffer, at the desired offset. */
writeInt8(value:i8, offset?:i32): i32;
/** Reads a signed integer at the designated offset. */
readInt8(offset?: i32): i8;
/** Writes an inputted u8 value to the buffer, at the desired offset. */
writeUInt8(value:u8, offset?:i32): i32;
/** Reads a signed 16-bit integer, stored in Little Endian format at the designated offset. */
Expand Down Expand Up @@ -77,6 +79,24 @@ declare class Buffer extends Uint8Array {
writeDoubleLE(value: f64, offset?: i32): i32;
/** Writes an inputted 64-bit double at the designated offset, stored in Big Endian format */
writeDoubleBE(value: f64, offset?: i32): i32;
/** Inspect a buffer. */
inspect(): string;
}

declare module "buffer" {
/**
* The maximum number of bytes to inspect on a buffer.
*
* @example
* import { INSPECT_MAX_BYTES } from "buffer";
* // @ts-ignore: This is treated like a global
* INSPECT_MAX_BYTES = <i32>10;
*/
export var INSPECT_MAX_BYTES: i32;

// To export the buffer, we must obtain the `typeof Buffer`
const BuffType: typeof Buffer;
export { BuffType as Buffer };
}

declare namespace Buffer {
Expand Down
17 changes: 16 additions & 1 deletion tests/buffer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* });
*/
import { BLOCK_MAXSIZE } from "rt/common";
import { INSPECT_MAX_BYTES } from "buffer";

// Helper function to quickly create a Buffer from an array.
//@ts-ignore
Expand Down Expand Up @@ -140,6 +141,20 @@ describe("buffer", () => {
// }).toThrow();
});


test("#inspect", () => {
let buff = create<Buffer>([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]);
let result = buff.inspect();
expect<string>(result).toBe("<Buffer 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f>");
INSPECT_MAX_BYTES = 5;
result = buff.inspect();
expect<string>(result).toBe("<Buffer 00 01 02 03 04...>");

buff = new Buffer(0);
result = buff.inspect()
expect<string>(result).toBe("<Buffer >");
});

test("#readUInt16LE", () => {
let buff = create<Buffer>([0x0,0x05,0x0]);
expect<u16>(buff.readUInt16LE()).toBe(1280);
Expand Down Expand Up @@ -531,7 +546,7 @@ describe("buffer", () => {
expected = create<Buffer>([5, 6, 7]);
expect<Buffer>(actual).toStrictEqual(expected);
});

test("#Hex.encode", () => {
let actual = "000102030405060708090a0b0c0d0e0f102030405060708090a0b0c0d0e0f0";
let exampleBuffer = create<Buffer>([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0]);
Expand Down