lots of small cleanup
This commit is contained in:
parent
ec035e9a5d
commit
362fda5b4b
|
@ -1,3 +1,7 @@
|
|||
/**
|
||||
* TODO: bigint, large decimals. For right now, only use numbers that fit in
|
||||
* JavaScript number.
|
||||
*/
|
||||
/// <reference types="node" />
|
||||
export declare const Types: {
|
||||
readonly BERT_START: 131;
|
||||
|
@ -22,6 +26,23 @@ export declare const Lang: {
|
|||
readonly ELIXIR: 0;
|
||||
readonly ERLANG: 1;
|
||||
};
|
||||
interface Partial<Type> {
|
||||
value: Type;
|
||||
rest: Buffer;
|
||||
}
|
||||
export declare class Atom {
|
||||
readonly value: string;
|
||||
private constructor();
|
||||
private static atoms;
|
||||
static toAtom: (value: string) => Atom;
|
||||
}
|
||||
/**
|
||||
* WIP WIP WIP
|
||||
*/
|
||||
export declare class Tuple {
|
||||
readonly values: any[];
|
||||
constructor(values: any[]);
|
||||
}
|
||||
export declare class Bert {
|
||||
#private;
|
||||
private allBinariesAsString;
|
||||
|
@ -147,150 +168,21 @@ export declare class Bert {
|
|||
encode_tuple: (obj: Buffer, buffer: Buffer) => Buffer;
|
||||
encode_array: (obj: any[], buffer: Buffer) => Buffer;
|
||||
encode_map: (obj: Record<string, any>, buffer: Buffer) => Buffer;
|
||||
decode_atom: (buffer: Buffer, count: 1 | 2 | 4) => {
|
||||
value: any;
|
||||
rest: Buffer;
|
||||
};
|
||||
decode_binary: (buffer: Buffer) => {
|
||||
value: string | Buffer;
|
||||
rest: Buffer;
|
||||
};
|
||||
decode_integer: (buffer: Buffer, count: 1 | 2 | 4, unsigned?: boolean) => {
|
||||
value: number;
|
||||
rest: Buffer;
|
||||
};
|
||||
decode_atom: (buffer: Buffer, count: 1 | 2 | 4) => Partial<any>;
|
||||
decode_binary: (buffer: Buffer) => Partial<string | Buffer>;
|
||||
decode_integer: (buffer: Buffer, count: 1 | 2 | 4, unsigned?: boolean) => Partial<number>;
|
||||
decode_big: (buffer: Buffer, count: 1 | 2 | 4) => {
|
||||
value: number;
|
||||
rest: Buffer;
|
||||
};
|
||||
decode_float: (buffer: Buffer) => {
|
||||
value: number;
|
||||
rest: Buffer;
|
||||
};
|
||||
decode_new_float: (buffer: Buffer) => {
|
||||
value: number;
|
||||
rest: Buffer;
|
||||
};
|
||||
decode_string: (buffer: Buffer) => {
|
||||
value: string;
|
||||
rest: Buffer;
|
||||
};
|
||||
decode_list: (buffer: Buffer) => {
|
||||
value: any[];
|
||||
rest: Buffer;
|
||||
};
|
||||
decode_map: (buffer: Buffer) => {
|
||||
value: Record<string, any>;
|
||||
rest: Buffer;
|
||||
};
|
||||
decode_tuple: (buffer: Buffer, count: 1 | 2 | 4) => {
|
||||
value: {
|
||||
type: string;
|
||||
length: number;
|
||||
value: any[];
|
||||
toString: () => string;
|
||||
toLocaleString(): string;
|
||||
pop(): any;
|
||||
push(...items: any[]): number;
|
||||
concat(...items: ConcatArray<any>[]): any[];
|
||||
concat(...items: any[]): any[];
|
||||
join(separator?: string | undefined): string;
|
||||
reverse(): any[];
|
||||
shift(): any;
|
||||
slice(start?: number | undefined, end?: number | undefined): any[];
|
||||
sort(compareFn?: ((a: any, b: any) => number) | undefined): any[];
|
||||
splice(start: number, deleteCount?: number | undefined): any[];
|
||||
splice(start: number, deleteCount: number, ...items: any[]): any[];
|
||||
unshift(...items: any[]): number;
|
||||
indexOf(searchElement: any, fromIndex?: number | undefined): number;
|
||||
lastIndexOf(searchElement: any, fromIndex?: number | undefined): number;
|
||||
every<S extends any>(predicate: (value: any, index: number, array: any[]) => value is S, thisArg?: any): this is S[];
|
||||
every(predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): boolean;
|
||||
some(predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): boolean;
|
||||
forEach(callbackfn: (value: any, index: number, array: any[]) => void, thisArg?: any): void;
|
||||
map<U>(callbackfn: (value: any, index: number, array: any[]) => U, thisArg?: any): U[];
|
||||
filter<S_1 extends any>(predicate: (value: any, index: number, array: any[]) => value is S_1, thisArg?: any): S_1[];
|
||||
filter(predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): any[];
|
||||
reduce(callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any[]) => any): any;
|
||||
reduce(callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any[]) => any, initialValue: any): any;
|
||||
reduce<U_1>(callbackfn: (previousValue: U_1, currentValue: any, currentIndex: number, array: any[]) => U_1, initialValue: U_1): U_1;
|
||||
reduceRight(callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any[]) => any): any;
|
||||
reduceRight(callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any[]) => any, initialValue: any): any;
|
||||
reduceRight<U_2>(callbackfn: (previousValue: U_2, currentValue: any, currentIndex: number, array: any[]) => U_2, initialValue: U_2): U_2;
|
||||
find<S_2 extends any>(predicate: (value: any, index: number, obj: any[]) => value is S_2, thisArg?: any): S_2 | undefined;
|
||||
find(predicate: (value: any, index: number, obj: any[]) => unknown, thisArg?: any): any;
|
||||
findIndex(predicate: (value: any, index: number, obj: any[]) => unknown, thisArg?: any): number;
|
||||
fill(value: any, start?: number | undefined, end?: number | undefined): any[];
|
||||
copyWithin(target: number, start: number, end?: number | undefined): any[];
|
||||
entries(): IterableIterator<[number, any]>;
|
||||
keys(): IterableIterator<number>;
|
||||
values(): IterableIterator<any>;
|
||||
includes(searchElement: any, fromIndex?: number | undefined): boolean;
|
||||
flatMap<U_3, This = undefined>(callback: (this: This, value: any, index: number, array: any[]) => U_3 | readonly U_3[], thisArg?: This | undefined): U_3[];
|
||||
flat<A, D extends number = 1>(this: A, depth?: D | undefined): FlatArray<A, D>[];
|
||||
at(index: number): any;
|
||||
findLast<S_3 extends any>(predicate: (value: any, index: number, array: any[]) => value is S_3, thisArg?: any): S_3 | undefined;
|
||||
findLast(predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): any;
|
||||
findLastIndex(predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): number;
|
||||
toReversed(): any[];
|
||||
toSorted(compareFn?: ((a: any, b: any) => number) | undefined): any[];
|
||||
toSpliced(start: number, deleteCount: number, ...items: any[]): any[];
|
||||
toSpliced(start: number, deleteCount?: number | undefined): any[];
|
||||
with(index: number, value: any): any[];
|
||||
[Symbol.iterator](): IterableIterator<any>;
|
||||
[Symbol.unscopables]: {
|
||||
[x: number]: boolean | undefined;
|
||||
length?: boolean | undefined;
|
||||
toString?: boolean | undefined;
|
||||
toLocaleString?: boolean | undefined;
|
||||
pop?: boolean | undefined;
|
||||
push?: boolean | undefined;
|
||||
concat?: boolean | undefined;
|
||||
join?: boolean | undefined;
|
||||
reverse?: boolean | undefined;
|
||||
shift?: boolean | undefined;
|
||||
slice?: boolean | undefined;
|
||||
sort?: boolean | undefined;
|
||||
splice?: boolean | undefined;
|
||||
unshift?: boolean | undefined;
|
||||
indexOf?: boolean | undefined;
|
||||
lastIndexOf?: boolean | undefined;
|
||||
every?: boolean | undefined;
|
||||
some?: boolean | undefined;
|
||||
forEach?: boolean | undefined;
|
||||
map?: boolean | undefined;
|
||||
filter?: boolean | undefined;
|
||||
reduce?: boolean | undefined;
|
||||
reduceRight?: boolean | undefined;
|
||||
find?: boolean | undefined;
|
||||
findIndex?: boolean | undefined;
|
||||
fill?: boolean | undefined;
|
||||
copyWithin?: boolean | undefined;
|
||||
entries?: boolean | undefined;
|
||||
keys?: boolean | undefined;
|
||||
values?: boolean | undefined;
|
||||
includes?: boolean | undefined;
|
||||
flatMap?: boolean | undefined;
|
||||
flat?: boolean | undefined;
|
||||
at?: boolean | undefined;
|
||||
findLast?: boolean | undefined;
|
||||
findLastIndex?: boolean | undefined;
|
||||
toReversed?: boolean | undefined;
|
||||
toSorted?: boolean | undefined;
|
||||
toSpliced?: boolean | undefined;
|
||||
with?: boolean | undefined;
|
||||
[Symbol.iterator]?: boolean | undefined;
|
||||
readonly [Symbol.unscopables]?: boolean | undefined;
|
||||
};
|
||||
};
|
||||
rest: Buffer;
|
||||
};
|
||||
decode_nil: (buffer: Buffer) => {
|
||||
value: never[];
|
||||
rest: Buffer;
|
||||
};
|
||||
decode_float: (buffer: Buffer) => Partial<number>;
|
||||
decode_new_float: (buffer: Buffer) => Partial<number>;
|
||||
decode_string: (buffer: Buffer) => Partial<string>;
|
||||
decode_list: (buffer: Buffer) => Partial<any[]>;
|
||||
decode_map: (buffer: Buffer) => Partial<Record<string, any>>;
|
||||
decode_tuple: (buffer: Buffer, count: 1 | 2 | 4) => Partial<any>;
|
||||
decode_nil: (buffer: Buffer) => Partial<[]>;
|
||||
bytesToInt: (buffer: Buffer, length: 1 | 2 | 4, unsigned: boolean) => number;
|
||||
binary_to_list: (str: string) => string[];
|
||||
}
|
||||
/**
|
||||
* Convert object to atom.
|
||||
|
@ -404,3 +296,4 @@ export declare const toTuple: (arr: any[]) => {
|
|||
readonly [Symbol.unscopables]?: boolean | undefined;
|
||||
};
|
||||
};
|
||||
export {};
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
/**
|
||||
* TODO: bigint, large decimals. For right now, only use numbers that fit in
|
||||
* JavaScript number.
|
||||
*/
|
||||
export const Types = {
|
||||
BERT_START: 131,
|
||||
SMALL_ATOM: 119,
|
||||
|
@ -21,7 +25,52 @@ export const Lang = {
|
|||
ELIXIR: 0,
|
||||
ERLANG: 1,
|
||||
};
|
||||
/**
|
||||
* WIP WIP WIP
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
const reviver = (key, value) => {
|
||||
if (typeof value === "object" && value.type === "atom") {
|
||||
return Atom.toAtom(value.value);
|
||||
}
|
||||
else if (typeof value === "object" && value.type === "tuple") {
|
||||
return new Tuple(value.values);
|
||||
}
|
||||
else
|
||||
return value;
|
||||
};
|
||||
const log = (msg) => process.stderr.write(`${msg}\r\n`);
|
||||
/**
|
||||
* Return a subarray of the supplied buffer, minus len bytes from the front.
|
||||
*
|
||||
* @param buffer
|
||||
* @param len Number of bytes to chop off front
|
||||
* @returns Subarray of buffer
|
||||
*/
|
||||
const chopl = (buffer, len = 1) => buffer.subarray(len);
|
||||
export class Atom {
|
||||
value;
|
||||
constructor(value) {
|
||||
this.value = value;
|
||||
}
|
||||
static atoms = {};
|
||||
static toAtom = (value) => {
|
||||
return Atom.atoms[value] || (Atom.atoms[value] = new Atom(value));
|
||||
};
|
||||
}
|
||||
/**
|
||||
* WIP WIP WIP
|
||||
*/
|
||||
export class Tuple {
|
||||
values;
|
||||
constructor(values) {
|
||||
// Yes right now this is only one level deep.
|
||||
this.values = [...values];
|
||||
}
|
||||
}
|
||||
export class Bert {
|
||||
allBinariesAsString;
|
||||
mapKeyAsAtom;
|
||||
|
@ -56,7 +105,7 @@ export class Bert {
|
|||
};
|
||||
#decode = (buffer) => {
|
||||
const t = buffer[0];
|
||||
buffer = buffer.subarray(1);
|
||||
buffer = chopl(buffer);
|
||||
switch (t) {
|
||||
case Types.SMALL_ATOM:
|
||||
return this.decode_atom(buffer, 1);
|
||||
|
@ -96,7 +145,7 @@ export class Bert {
|
|||
if (buffer[0] !== Types.BERT_START) {
|
||||
throw new Error("Invalid BERT start magic");
|
||||
}
|
||||
const obj = this.#decode(buffer.subarray(1));
|
||||
const obj = this.#decode(chopl(buffer));
|
||||
if (obj.rest.length !== 0) {
|
||||
throw new Error(`Invalid BERT, remainder was: ${obj.rest.length}`);
|
||||
}
|
||||
|
@ -253,7 +302,7 @@ export class Bert {
|
|||
};
|
||||
decode_atom = (buffer, count) => {
|
||||
const size = this.bytesToInt(buffer, count, true);
|
||||
buffer = buffer.subarray(count);
|
||||
buffer = chopl(buffer, count);
|
||||
let value = buffer.toString("utf8", 0, size);
|
||||
if (value === "true") {
|
||||
value = true;
|
||||
|
@ -276,33 +325,33 @@ export class Bert {
|
|||
}
|
||||
return {
|
||||
value,
|
||||
rest: buffer.subarray(size),
|
||||
rest: chopl(buffer, size),
|
||||
};
|
||||
};
|
||||
decode_binary = (buffer) => {
|
||||
const size = this.bytesToInt(buffer, 4, true);
|
||||
buffer = buffer.subarray(4);
|
||||
buffer = chopl(buffer, 4);
|
||||
const bin = Buffer.alloc(size);
|
||||
buffer.copy(bin, 0, 0, size);
|
||||
return {
|
||||
value: this.convention === Lang.ELIXIR && this.allBinariesAsString
|
||||
? bin.toString("utf-8")
|
||||
: bin,
|
||||
rest: buffer.subarray(size),
|
||||
rest: chopl(buffer, size),
|
||||
};
|
||||
};
|
||||
decode_integer = (buffer, count, unsigned = false) => {
|
||||
return {
|
||||
value: this.bytesToInt(buffer, count, unsigned),
|
||||
rest: buffer.subarray(count),
|
||||
rest: chopl(buffer, count),
|
||||
};
|
||||
};
|
||||
decode_big = (buffer, count) => {
|
||||
const size = this.bytesToInt(buffer, count, false);
|
||||
buffer = buffer.subarray(count);
|
||||
const size = this.bytesToInt(buffer, count, true);
|
||||
buffer = chopl(buffer, count);
|
||||
let num = 0;
|
||||
const isNegative = buffer[0] === 1;
|
||||
buffer = buffer.subarray(1);
|
||||
buffer = chopl(buffer);
|
||||
for (let i = size - 1; i >= 0; --i) {
|
||||
const n = buffer[i];
|
||||
if (num === 0) {
|
||||
|
@ -317,35 +366,35 @@ export class Bert {
|
|||
}
|
||||
return {
|
||||
value: num,
|
||||
rest: buffer.subarray(size),
|
||||
rest: chopl(buffer, size),
|
||||
};
|
||||
};
|
||||
decode_float = (buffer) => {
|
||||
const size = 31;
|
||||
return {
|
||||
value: parseFloat(buffer.toString("utf8", 0, size)),
|
||||
rest: buffer.subarray(size),
|
||||
rest: chopl(buffer, size),
|
||||
};
|
||||
};
|
||||
decode_new_float = (buffer) => {
|
||||
return {
|
||||
value: buffer.readDoubleBE(0),
|
||||
rest: buffer.subarray(8),
|
||||
rest: chopl(buffer, 8),
|
||||
};
|
||||
};
|
||||
decode_string = (buffer) => {
|
||||
const sizeLen = this.convention === Lang.ELIXIR ? 4 : 2;
|
||||
const size = this.bytesToInt(buffer, sizeLen, true);
|
||||
buffer = buffer.subarray(sizeLen);
|
||||
buffer = chopl(buffer, sizeLen);
|
||||
return {
|
||||
value: buffer.toString("utf8", 0, size),
|
||||
rest: buffer.subarray(size),
|
||||
rest: chopl(buffer, size),
|
||||
};
|
||||
};
|
||||
decode_list = (buffer) => {
|
||||
const arr = [];
|
||||
const size = this.bytesToInt(buffer, 4, true);
|
||||
buffer = buffer.subarray(4);
|
||||
buffer = chopl(buffer, 4);
|
||||
for (let i = 0; i < size; ++i) {
|
||||
const el = this.#decode(buffer);
|
||||
arr.push(el.value);
|
||||
|
@ -355,7 +404,7 @@ export class Bert {
|
|||
if (lastChar !== Types.NIL) {
|
||||
throw new Error("List does not end with NIL");
|
||||
}
|
||||
buffer = buffer.subarray(1);
|
||||
buffer = chopl(buffer);
|
||||
return {
|
||||
value: arr,
|
||||
rest: buffer,
|
||||
|
@ -364,7 +413,7 @@ export class Bert {
|
|||
decode_map = (buffer) => {
|
||||
const map = {};
|
||||
const size = this.bytesToInt(buffer, 4, true);
|
||||
buffer = buffer.subarray(4);
|
||||
buffer = chopl(buffer, 4);
|
||||
for (let i = 0; i < size; ++i) {
|
||||
let el = this.#decode(buffer);
|
||||
const key = el.value;
|
||||
|
@ -381,7 +430,7 @@ export class Bert {
|
|||
decode_tuple = (buffer, count) => {
|
||||
const arr = [];
|
||||
const size = this.bytesToInt(buffer, count, true);
|
||||
buffer = buffer.subarray(count);
|
||||
buffer = chopl(buffer, count);
|
||||
for (let i = 0; i < size; ++i) {
|
||||
const el = this.#decode(buffer);
|
||||
arr.push(el.value);
|
||||
|
@ -409,12 +458,6 @@ export class Bert {
|
|||
return unsigned ? buffer.readUInt32BE(0) : buffer.readInt32BE(0);
|
||||
}
|
||||
};
|
||||
binary_to_list = (str) => {
|
||||
const ret = [];
|
||||
for (let i = 0; i < str.length; ++i)
|
||||
ret.push(str[i]);
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert object to atom.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Bert } from "./bert.js";
|
||||
import { Duplex } from "node:stream";
|
||||
const log = (msg) => process.stderr.write(`${msg}\r\n`);
|
||||
export class Port extends Duplex {
|
||||
bert;
|
||||
originalStdout;
|
||||
|
@ -17,7 +18,7 @@ export class Port extends Duplex {
|
|||
const lenBytes = process.stdin.read(4);
|
||||
if (lenBytes) {
|
||||
const termLen = this.bert.bytesToInt(lenBytes, 4, true);
|
||||
process.stderr.write(`Got incoming term length: ${termLen} (bytes: <<${lenBytes.toString('hex').match(/../g).map((hex) => parseInt(`0x${hex}`).toString()).join(', ')}>>)\n`);
|
||||
log(`Got incoming term length: ${termLen} (bytes: <<${lenBytes.toString('hex').match(/../g).map((hex) => parseInt(`0x${hex}`).toString()).join(', ')}>>).`);
|
||||
const termBytes = process.stdin.read(termLen);
|
||||
if (termBytes) {
|
||||
const decoded = this.bert.decode(termBytes);
|
||||
|
@ -25,7 +26,7 @@ export class Port extends Duplex {
|
|||
return decoded;
|
||||
}
|
||||
else {
|
||||
process.stderr.write(`Term read got erroneous null.\n`);
|
||||
log("Term read got erroneous null.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +46,7 @@ export class Port extends Duplex {
|
|||
return true;
|
||||
}
|
||||
catch (error) {
|
||||
process.stderr.write(`Error writing: ${error}\n`);
|
||||
log(`Error writing: ${error}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
132
src/bert.ts
132
src/bert.ts
|
@ -1,3 +1,8 @@
|
|||
/**
|
||||
* TODO: bigint, large decimals. For right now, only use numbers that fit in
|
||||
* JavaScript number.
|
||||
*/
|
||||
|
||||
export const Types = {
|
||||
BERT_START: 131,
|
||||
SMALL_ATOM: 119,
|
||||
|
@ -23,8 +28,63 @@ export const Lang = {
|
|||
ERLANG: 1,
|
||||
} as const;
|
||||
|
||||
interface Partial<Type> {
|
||||
value: Type;
|
||||
rest: Buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* WIP WIP WIP
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
const reviver = (key: string, value: any) => {
|
||||
if (typeof value === "object" && value.type === "atom") {
|
||||
return Atom.toAtom(value.value);
|
||||
}
|
||||
else if (typeof value === "object" && value.type === "tuple") {
|
||||
return new Tuple(value.values);
|
||||
}
|
||||
else return value;
|
||||
};
|
||||
|
||||
const log = (msg: string) => process.stderr.write(`${msg}\r\n`);
|
||||
|
||||
/**
|
||||
* Return a subarray of the supplied buffer, minus len bytes from the front.
|
||||
*
|
||||
* @param buffer
|
||||
* @param len Number of bytes to chop off front
|
||||
* @returns Subarray of buffer
|
||||
*/
|
||||
const chopl = (buffer: Buffer, len = 1) => buffer.subarray(len);
|
||||
|
||||
export class Atom {
|
||||
public readonly value;
|
||||
private constructor(value: string) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private static atoms: Record<string, Atom> = {};
|
||||
|
||||
public static toAtom = (value: string) => {
|
||||
return Atom.atoms[value] || (Atom.atoms[value] = new Atom(value));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* WIP WIP WIP
|
||||
*/
|
||||
export class Tuple {
|
||||
public readonly values;
|
||||
constructor(values: any[]) {
|
||||
// Yes right now this is only one level deep.
|
||||
this.values = [...values];
|
||||
}
|
||||
}
|
||||
|
||||
export class Bert {
|
||||
private allBinariesAsString;
|
||||
private mapKeyAsAtom;
|
||||
|
@ -74,7 +134,7 @@ export class Bert {
|
|||
|
||||
#decode = (buffer: Buffer): any => {
|
||||
const t = buffer[0];
|
||||
buffer = buffer.subarray(1);
|
||||
buffer = chopl(buffer);
|
||||
|
||||
switch (t) {
|
||||
case Types.SMALL_ATOM:
|
||||
|
@ -117,7 +177,7 @@ export class Bert {
|
|||
throw new Error("Invalid BERT start magic");
|
||||
}
|
||||
|
||||
const obj = this.#decode(buffer.subarray(1));
|
||||
const obj = this.#decode(chopl(buffer));
|
||||
|
||||
if (obj.rest.length !== 0) {
|
||||
throw new Error(`Invalid BERT, remainder was: ${obj.rest.length}`);
|
||||
|
@ -191,7 +251,8 @@ export class Bert {
|
|||
buffer.writeUInt8(offset - 1, 1);
|
||||
numBuffer.copy(buffer, 2, 0, offset);
|
||||
return buffer.subarray(0, 2 + offset);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
buffer[0] = Types.LARGE_BIG;
|
||||
buffer.writeUInt32BE(offset - 1, 1);
|
||||
numBuffer.copy(buffer, 5, 0, offset);
|
||||
|
@ -297,9 +358,9 @@ export class Bert {
|
|||
return buffer;
|
||||
};
|
||||
|
||||
decode_atom = (buffer: Buffer, count: 1 | 2 | 4) => {
|
||||
decode_atom = (buffer: Buffer, count: 1 | 2 | 4): Partial<any> => {
|
||||
const size = this.bytesToInt(buffer, count, true);
|
||||
buffer = buffer.subarray(count);
|
||||
buffer = chopl(buffer, count);
|
||||
let value: any = buffer.toString("utf8", 0, size);
|
||||
if (value === "true") {
|
||||
value = true;
|
||||
|
@ -327,13 +388,13 @@ export class Bert {
|
|||
|
||||
return {
|
||||
value,
|
||||
rest: buffer.subarray(size),
|
||||
rest: chopl(buffer, size),
|
||||
};
|
||||
};
|
||||
|
||||
decode_binary = (buffer: Buffer) => {
|
||||
decode_binary = (buffer: Buffer): Partial<string | Buffer> => {
|
||||
const size = this.bytesToInt(buffer, 4, true);
|
||||
buffer = buffer.subarray(4);
|
||||
buffer = chopl(buffer, 4);
|
||||
const bin = Buffer.alloc(size);
|
||||
buffer.copy(bin, 0, 0, size);
|
||||
return {
|
||||
|
@ -341,31 +402,32 @@ export class Bert {
|
|||
this.convention === Lang.ELIXIR && this.allBinariesAsString
|
||||
? bin.toString("utf-8")
|
||||
: bin,
|
||||
rest: buffer.subarray(size),
|
||||
rest: chopl(buffer, size),
|
||||
};
|
||||
};
|
||||
|
||||
decode_integer = (buffer: Buffer, count: 1 | 2 | 4, unsigned = false) => {
|
||||
decode_integer = (buffer: Buffer, count: 1 | 2 | 4, unsigned = false): Partial<number> => {
|
||||
return {
|
||||
value: this.bytesToInt(buffer, count, unsigned),
|
||||
rest: buffer.subarray(count),
|
||||
rest: chopl(buffer, count),
|
||||
};
|
||||
};
|
||||
|
||||
decode_big = (buffer: Buffer, count: 1 | 2 | 4) => {
|
||||
const size = this.bytesToInt(buffer, count, false);
|
||||
buffer = buffer.subarray(count);
|
||||
const size = this.bytesToInt(buffer, count, true);
|
||||
buffer = chopl(buffer, count);
|
||||
|
||||
let num = 0;
|
||||
const isNegative = buffer[0] === 1;
|
||||
|
||||
buffer = buffer.subarray(1);
|
||||
buffer = chopl(buffer);
|
||||
|
||||
for (let i = size - 1; i >= 0; --i) {
|
||||
const n = buffer[i];
|
||||
if (num === 0) {
|
||||
num = n;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
num = num * 256 + n;
|
||||
}
|
||||
}
|
||||
|
@ -375,41 +437,41 @@ export class Bert {
|
|||
|
||||
return {
|
||||
value: num,
|
||||
rest: buffer.subarray(size),
|
||||
rest: chopl(buffer, size),
|
||||
};
|
||||
};
|
||||
|
||||
decode_float = (buffer: Buffer) => {
|
||||
decode_float = (buffer: Buffer): Partial<number> => {
|
||||
const size = 31;
|
||||
|
||||
return {
|
||||
value: parseFloat(buffer.toString("utf8", 0, size)),
|
||||
rest: buffer.subarray(size),
|
||||
rest: chopl(buffer, size),
|
||||
};
|
||||
};
|
||||
|
||||
decode_new_float = (buffer: Buffer) => {
|
||||
decode_new_float = (buffer: Buffer): Partial<number> => {
|
||||
return {
|
||||
value: buffer.readDoubleBE(0),
|
||||
rest: buffer.subarray(8),
|
||||
rest: chopl(buffer, 8),
|
||||
};
|
||||
};
|
||||
|
||||
decode_string = (buffer: Buffer) => {
|
||||
decode_string = (buffer: Buffer): Partial<string> => {
|
||||
const sizeLen = this.convention === Lang.ELIXIR ? 4 : 2;
|
||||
const size = this.bytesToInt(buffer, sizeLen, true);
|
||||
buffer = buffer.subarray(sizeLen);
|
||||
buffer = chopl(buffer, sizeLen);
|
||||
|
||||
return {
|
||||
value: buffer.toString("utf8", 0, size),
|
||||
rest: buffer.subarray(size),
|
||||
rest: chopl(buffer, size),
|
||||
};
|
||||
};
|
||||
|
||||
decode_list = (buffer: Buffer) => {
|
||||
decode_list = (buffer: Buffer): Partial<any[]> => {
|
||||
const arr = [];
|
||||
const size = this.bytesToInt(buffer, 4, true);
|
||||
buffer = buffer.subarray(4);
|
||||
buffer = chopl(buffer, 4);
|
||||
|
||||
for (let i = 0; i < size; ++i) {
|
||||
const el = this.#decode(buffer);
|
||||
|
@ -423,7 +485,7 @@ export class Bert {
|
|||
throw new Error("List does not end with NIL");
|
||||
}
|
||||
|
||||
buffer = buffer.subarray(1);
|
||||
buffer = chopl(buffer);
|
||||
|
||||
return {
|
||||
value: arr,
|
||||
|
@ -431,11 +493,11 @@ export class Bert {
|
|||
};
|
||||
};
|
||||
|
||||
decode_map = (buffer: Buffer) => {
|
||||
decode_map = (buffer: Buffer): Partial<Record<string, any>> => {
|
||||
const map: Record<string, any> = {};
|
||||
const size = this.bytesToInt(buffer, 4, true);
|
||||
|
||||
buffer = buffer.subarray(4);
|
||||
buffer = chopl(buffer, 4);
|
||||
|
||||
for (let i = 0; i < size; ++i) {
|
||||
let el = this.#decode(buffer);
|
||||
|
@ -451,22 +513,23 @@ export class Bert {
|
|||
};
|
||||
};
|
||||
|
||||
decode_tuple = (buffer: Buffer, count: 1 | 2 | 4) => {
|
||||
decode_tuple = (buffer: Buffer, count: 1 | 2 | 4): Partial<any> => {
|
||||
const arr = [];
|
||||
const size = this.bytesToInt(buffer, count, true);
|
||||
buffer = buffer.subarray(count);
|
||||
buffer = chopl(buffer, count);
|
||||
for (let i = 0; i < size; ++i) {
|
||||
const el = this.#decode(buffer);
|
||||
arr.push(el.value);
|
||||
buffer = el.rest;
|
||||
}
|
||||
|
||||
return {
|
||||
value: this.toTuple(arr),
|
||||
rest: buffer,
|
||||
};
|
||||
};
|
||||
|
||||
decode_nil = (buffer: Buffer) => {
|
||||
decode_nil = (buffer: Buffer): Partial<[]> => {
|
||||
// nil is an empty list
|
||||
return {
|
||||
value: [],
|
||||
|
@ -484,13 +547,6 @@ export class Bert {
|
|||
return unsigned ? buffer.readUInt32BE(0) : buffer.readInt32BE(0);
|
||||
}
|
||||
};
|
||||
|
||||
binary_to_list = (str: string) => {
|
||||
const ret = [];
|
||||
for (let i = 0; i < str.length; ++i) ret.push(str[i]);
|
||||
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,6 +3,8 @@ import { Duplex } from "node:stream";
|
|||
|
||||
type WriteCallback = (error: Error | null | undefined) => void;
|
||||
|
||||
const log = (msg: string) => process.stderr.write(`${msg}\r\n`);
|
||||
|
||||
export class Port extends Duplex {
|
||||
public readonly bert: Bert;
|
||||
private originalStdout;
|
||||
|
@ -22,7 +24,7 @@ export class Port extends Duplex {
|
|||
const lenBytes = process.stdin.read(4);
|
||||
if (lenBytes) {
|
||||
const termLen = this.bert.bytesToInt(lenBytes, 4, true);
|
||||
process.stderr.write(`Got incoming term length: ${termLen} (bytes: <<${lenBytes.toString('hex').match(/../g).map((hex: string) => parseInt(`0x${hex}`).toString()).join(', ')}>>)\n`);
|
||||
log(`Got incoming term length: ${termLen} (bytes: <<${lenBytes.toString('hex').match(/../g).map((hex: string) => parseInt(`0x${hex}`).toString()).join(', ')}>>).`);
|
||||
const termBytes = process.stdin.read(termLen);
|
||||
|
||||
if (termBytes) {
|
||||
|
@ -31,7 +33,7 @@ export class Port extends Duplex {
|
|||
return decoded;
|
||||
}
|
||||
else {
|
||||
process.stderr.write(`Term read got erroneous null.\n`);
|
||||
log("Term read got erroneous null.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +55,7 @@ export class Port extends Duplex {
|
|||
return true;
|
||||
}
|
||||
catch (error) {
|
||||
process.stderr.write(`Error writing: ${error}\n`);
|
||||
log(`Error writing: ${error}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue