Skip to content

Commit

Permalink
Began implementing Buffer static side
Browse files Browse the repository at this point in the history
  • Loading branch information
james-pre committed Nov 25, 2024
1 parent fcd5a0d commit 3eede92
Showing 1 changed file with 189 additions and 3 deletions.
192 changes: 189 additions & 3 deletions src/buffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@ import type { Buffer as NodeBuffer } from 'buffer';
export class Buffer extends Uint8Array implements NodeBuffer {
protected view = new DataView(this.buffer, this.byteOffset, this.byteLength);

/* constructor(str: string, encoding?: BufferEncoding);
constructor(size: number);
constructor(array: Uint8Array | ArrayBufferLike | readonly any[]);
constructor(dataOrLength: readonly any[] | string | number | Uint8Array | ArrayBufferLike, encoding?: BufferEncoding) */

constructor(input: string | ArrayBufferLike | Uint8Array | number, encoding?: BufferEncoding) {
if (typeof input === 'number') {
super(input);
} else if (typeof input === 'string') {
super(encode(input, encoding || 'utf8'));
} else {
super(input);
}
this.view = new DataView(this.buffer, this.byteOffset, this.byteLength);
}

write(string: string, offset?: number | BufferEncoding, length?: number | BufferEncoding, encoding?: BufferEncoding): number {
let actualOffset = 0;
let actualLength = this.length;
Expand Down Expand Up @@ -383,10 +399,180 @@ export class Buffer extends Uint8Array implements NodeBuffer {
this.view.setFloat64(offset, value, false);
return offset + 8;
}

/* from(arrayBuffer: WithImplicitCoercion<ArrayBufferLike>, byteOffset?: number, length?: number): Buffer;
from(data: WithImplicitCoercion<Uint8Array | readonly number[] | string>): Buffer;
from(str: WithImplicitCoercion<string> | { [Symbol.toPrimitive](hint: 'string'): string }, encoding?: BufferEncoding): Buffer; */
from(
value: WithImplicitCoercion<ArrayBufferLike | Uint8Array | string | readonly number[]> | { [Symbol.toPrimitive](hint: 'string'): string },
encoding?: number | BufferEncoding,
length?: number
): Buffer {
if (typeof value === 'string') return new Buffer(encode(value, encoding || 'utf8'));

Check failure on line 411 in src/buffer.ts

View workflow job for this annotation

GitHub Actions / Continuous Integration

Argument of type 'number | BufferEncoding' is not assignable to parameter of type 'BufferEncoding'.
if (value instanceof ArrayBuffer || value instanceof SharedArrayBuffer) return new Buffer(new Uint8Array(value));
if (Array.isArray(value)) return new Buffer(new Uint8Array(value));
return new Buffer(value);

Check failure on line 414 in src/buffer.ts

View workflow job for this annotation

GitHub Actions / Continuous Integration

Argument of type 'Uint8Array | readonly number[] | { valueOf(): string | ArrayBufferLike | Uint8Array | readonly number[]; } | { [Symbol.toPrimitive](hint: "string"): string; }' is not assignable to parameter of type 'string | number | ArrayBufferLike | Uint8Array'.
}

// alloc(size: number, fill?: string | Uint8Array | number, encoding?: BufferEncoding): Buffer
static alloc(size: number, fill?: string | number | Uint8Array, encoding: BufferEncoding = 'utf8'): Buffer {
const buffer = new Buffer(size);
if (fill === undefined) return buffer;

if (typeof fill === 'string') {
buffer.fill(encode(fill, encoding));

Check failure on line 423 in src/buffer.ts

View workflow job for this annotation

GitHub Actions / Continuous Integration

Argument of type 'Uint8Array' is not assignable to parameter of type 'number'.
} else if (typeof fill === 'number') {
buffer.fill(fill);
} else {
buffer.set(fill);
}

return buffer;
}

// allocUnsafe(size: number): Buffer
static allocUnsafe(size: number): Buffer {
return new Buffer(size);
}

// concat(list: readonly Uint8Array[], totalLength?: number): Buffer
static concat(list: Buffer[], totalLength?: number): Buffer {
if (list.length === 0) return Buffer.alloc(0);

totalLength ??= list.reduce((acc, buf) => acc + buf.length, 0);

const buffer = Buffer.allocUnsafe(totalLength);
let offset = 0;
for (const buf of list) {
buffer.set(buf, offset);
offset += buf.length;
}
return buffer;
}

static isBuffer(obj: any): obj is Buffer {
return obj instanceof Buffer;
}

// byteLength(string: string | Buffer | NodeJS.ArrayBufferView | ArrayBufferLike, encoding?: BufferEncoding): number {}
static byteLength(string: string | ArrayBufferLike | NodeJS.ArrayBufferView, encoding: BufferEncoding = 'utf8'): number {
if (typeof string === 'string') {
return encode(string, encoding).length;
} else if (string instanceof ArrayBuffer || string instanceof SharedArrayBuffer || string instanceof Uint8Array) {
return string.byteLength;
} else {
throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer.');
}
}

static isEncoding(encoding: string): encoding is BufferEncoding {
return ['utf8', 'utf-8', 'ascii', 'latin1', 'binary', 'base64', 'base64url', 'hex', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le'].includes(encoding.toLowerCase());
}

static compare(buf1: Uint8Array, buf2: Uint8Array): -1 | 0 | 1 {
if (!(buf1 instanceof Uint8Array) || !(buf2 instanceof Uint8Array)) {
throw new TypeError('Arguments must be Buffers');
}
if (buf1 === buf2) return 0;

for (let i = 0; i < Math.min(buf1.length, buf2.length); i++) {
if (buf1[i] !== buf2[i]) {
return buf1[i] < buf2[i] ? -1 : 1;
}
}
if (buf1.length < buf2.length) return -1;
if (buf1.length > buf2.length) return 1;
return 0;
}

static of(...items: number[]): Buffer {}

Check failure on line 488 in src/buffer.ts

View workflow job for this annotation

GitHub Actions / Continuous Integration

A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.

static copyBytesFrom(view: NodeJS.TypedArray, offset?: number, length?: number): Buffer {}

Check failure on line 490 in src/buffer.ts

View workflow job for this annotation

GitHub Actions / Continuous Integration

A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.

static allocUnsafeSlow(size: number): Buffer {}

Check failure on line 492 in src/buffer.ts

View workflow job for this annotation

GitHub Actions / Continuous Integration

A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.

static poolSize: number;
}

Buffer satisfies typeof NodeBuffer;

Check failure on line 497 in src/buffer.ts

View workflow job for this annotation

GitHub Actions / Continuous Integration

Type 'typeof Buffer' does not satisfy the expected type 'BufferConstructor'.

function decode(data: Uint8Array, encoding: BufferEncoding) {
if (encoding == 'utf16le') encoding = 'utf-16le';
const decoder = new TextDecoder(encoding);
return decoder.decode(data);
switch (encoding) {
case 'base64':
return btoa(String.fromCharCode(...data));
case 'base64url':
return btoa(String.fromCharCode(...data))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
case 'binary':
return String.fromCharCode(...data);
case 'hex':
return Array.from(data)
.map(byte => byte.toString(16).padStart(2, '0'))
.join('');
case 'utf16le':
case 'ucs2':
case 'ucs-2':
encoding = 'utf-16le';
// Fall through to use TextDecoder
default:
return new TextDecoder(encoding).decode(data);
}
}

function encode(input: string, encoding: BufferEncoding): Uint8Array {
switch (encoding) {
case 'utf-16le':
case 'utf16le':
case 'ucs2':
case 'ucs-2': {
const buffer = new Uint8Array(input.length * 2);
for (let i = 0; i < input.length; i++) {
const code = input.charCodeAt(i);
buffer[i * 2] = code & 0xff;
buffer[i * 2 + 1] = code >> 8;
}
return buffer;
}
case 'base64': {
const binaryString = atob(input);
const buffer = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
buffer[i] = binaryString.charCodeAt(i);
}
return buffer;
}
case 'base64url': {
input = input.replace(/-/g, '+').replace(/_/g, '/');
while (input.length % 4 !== 0) {
input += '=';
}
const binaryString = atob(input);
const buffer = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
buffer[i] = binaryString.charCodeAt(i);
}
return buffer;
}
case 'binary': {
const buffer = new Uint8Array(input.length);
for (let i = 0; i < input.length; i++) {
buffer[i] = input.charCodeAt(i);
}
return buffer;
}
case 'hex': {
const buffer = new Uint8Array(input.length / 2);
for (let i = 0; i < buffer.length; i++) {
buffer[i] = parseInt(input.substr(i * 2, 2), 16);
}
return buffer;
}
case 'ascii':
case 'utf8':
case 'utf-8':
case 'latin1':
return new TextEncoder().encode(input);
}
}

0 comments on commit 3eede92

Please sign in to comment.