From fcee6d8dc4a66129fd3d187cd0cefa43628c7e52 Mon Sep 17 00:00:00 2001 From: ouyang Date: Mon, 12 Oct 2020 16:16:12 +0800 Subject: [PATCH 1/6] feat: add int/uint/float sub type support & TypedObj --- src/buffer.ts | 15 ++- src/tests.ts | 250 +++++++++++++++++++++++++++++++++++++++++++------- src/types.ts | 77 +++++++++++++++- 3 files changed, 305 insertions(+), 37 deletions(-) diff --git a/src/buffer.ts b/src/buffer.ts index 5e0f047..c35e7db 100644 --- a/src/buffer.ts +++ b/src/buffer.ts @@ -21,7 +21,8 @@ export interface WriteBuffer { putUi32(v: number): void; putUi64(v: number): void; - putF(v: number): void; + putF32(v: number): void; + putF64(v: number): void; ui8array(): Uint8Array; } @@ -49,7 +50,7 @@ export interface ReadBuffer { export function createWriteBuffer(): WriteBuffer { let view = new DataView(new ArrayBuffer(64)); let n = 0; - + function need(x: number): void { if(n+x > view.byteLength) { const arr = new Uint8Array(Math.max(n+x, view.byteLength+64)); @@ -127,7 +128,13 @@ export function createWriteBuffer(): WriteBuffer { n += 8; }, - putF(v: number): void { + putF32(v: number): void { + need(4); + view.setFloat32(n, v); + n += 4; + }, + + putF64(v: number): void { need(8); view.setFloat64(n, v); n += 8; @@ -143,7 +150,7 @@ export function createWriteBuffer(): WriteBuffer { export function createReadBuffer(buf: BufferSource): ReadBuffer { let view = ArrayBuffer.isView(buf) ? new DataView(buf.buffer, buf.byteOffset, buf.byteLength) : new DataView(buf); let n = 0; - + return { peek(): number { return view.getUint8(n); diff --git a/src/tests.ts b/src/tests.ts index a898090..5abd64b 100644 --- a/src/tests.ts +++ b/src/tests.ts @@ -1,13 +1,13 @@ import {test} from "testsome"; import {Tag, posFixintTag, negFixintTag, fixstrTag, fixarrayTag, fixmapTag} from "./tags"; -import {Nil, Bool, Int, Uint, Float, Bytes, Str, Arr, Map, Raw, Time, Any, Struct, Union} from "./types"; +import {Nil, Bool, Int, Uint, Float, Bytes, Str, Arr, Map, Raw, Time, Any, Struct, Union, TypedObj, Int32, Uint32, Uint8, Uint16, Uint64, Float32, Float64, Int8, Int16, Int64} from "./types"; import {encode, decode} from "./index"; test("encode", t => { const tests = [ - // nil + //#region nil { val: undefined, typ: Nil, @@ -33,7 +33,8 @@ test("encode", t => { typ: Nil, bin: [Tag.Nil], }, - // bool + //#endregion + //#region bool { val: true, typ: Bool, @@ -44,7 +45,8 @@ test("encode", t => { typ: Bool, bin: [Tag.False], }, - // int + //#endregion + //#region int { val: 7, typ: Int, @@ -60,52 +62,103 @@ test("encode", t => { typ: Int, bin: [Tag.Int8, 0x80], }, + { + val: -128, + typ: Int8, + bin: [Tag.Int8, 0x80], + }, { val: -32768, typ: Int, bin: [Tag.Int16, 0x80, 0x0], }, + { + val: -32768, + typ: Int16, + bin: [Tag.Int16, 0x80, 0x0], + }, { val: 32767, typ: Int, bin: [Tag.Int16, 0x7f, 0xff], }, + { + val: 32767, + typ: Int16, + bin: [Tag.Int16, 0x7f, 0xff], + }, { val: 2147483647, typ: Int, bin: [Tag.Int32, 0x7f, 0xff, 0xff, 0xff], }, + { + val: 2147483647, + typ: Int32, + bin: [Tag.Int32, 0x7f, 0xff, 0xff, 0xff], + }, { val: -2147483648, typ: Int, bin: [Tag.Int32, 0x80, 0x0, 0x0, 0x0], }, + { + val: -2147483648, + typ: Int32, + bin: [Tag.Int32, 0x80, 0x0, 0x0, 0x0], + }, { val: 2147483648, typ: Int, bin: [Tag.Int64, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00], }, + { + val: 2147483648, + typ: Int64, + bin: [Tag.Int64, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00], + }, { val: 4294967296, typ: Int, bin: [Tag.Int64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00], }, + { + val: 4294967296, + typ: Int64, + bin: [Tag.Int64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00], + }, { val: -2147483649, typ: Int, bin: [Tag.Int64, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff], }, + { + val: -2147483649, + typ: Int64, + bin: [Tag.Int64, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff], + }, { val: 549764202560, typ: Int, bin: [Tag.Int64, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x40], }, + { + val: 549764202560, + typ: Int64, + bin: [Tag.Int64, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x40], + }, { val: -549764202560, typ: Int, bin: [Tag.Int64, 0xff, 0xff, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xc0], }, - // uint + { + val: -549764202560, + typ: Int64, + bin: [Tag.Int64, 0xff, 0xff, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xc0], + }, + //#endregion + //#region uint { val: 7, typ: Uint, @@ -116,33 +169,70 @@ test("encode", t => { typ: Uint, bin: [Tag.Uint8, 0xff], }, + { + val: 255, + typ: Uint8, + bin: [Tag.Uint8, 0xff], + }, { val: 65535, typ: Uint, bin: [Tag.Uint16, 0xff, 0xff], }, + { + val: 65535, + typ: Uint16, + bin: [Tag.Uint16, 0xff, 0xff], + }, { val: 4294967295, typ: Uint, bin: [Tag.Uint32, 0xff, 0xff, 0xff, 0xff], }, + { + val: 4294967295, + typ: Uint32, + bin: [Tag.Uint32, 0xff, 0xff, 0xff, 0xff], + }, { val: 4294967296, typ: Uint, bin: [Tag.Uint64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00], }, + { + val: 4294967296, + typ: Uint64, + bin: [Tag.Uint64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00], + }, { val: 549764202560, typ: Uint, bin: [Tag.Uint64, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x40], }, - // float + { + val: 549764202560, + typ: Uint64, + bin: [Tag.Uint64, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x40], + }, + //#endregion + //#region float { val: 3.141592, typ: Float, bin: [Tag.Float64, 0x40, 0x09, 0x21, 0xfa, 0xfc, 0x8b, 0x00, 0x7a], }, - // bytes + { + val: 1.5, + typ: Float32, + bin: [Tag.Float32, 0x3f, 0xc0, 0x00, 0x00], + }, + { + val: 3.141592, + typ: Float64, + bin: [Tag.Float64, 0x40, 0x09, 0x21, 0xfa, 0xfc, 0x8b, 0x00, 0x7a], + }, + //#endregion + //#region bytes { val: (new Uint8Array(repeat(0x30, 1))).buffer, typ: Bytes, @@ -158,7 +248,8 @@ test("encode", t => { typ: Bytes, bin: [Tag.Bin32, 0x00, 0x01, 0x00, 0x00].concat(repeat(0x30, 65536)), }, - // string + //#endregion + //#region string { val: "0", typ: Str, @@ -199,7 +290,8 @@ test("encode", t => { typ: Str, bin: [Tag.Str32, 0x00, 0x01, 0x00, 0x00].concat(repeat(0x30, 65536)), }, - // array (32 bit not testable due to oom) + //#endregion + //#region array (32 bit not testable due to oom) { val: repeat(13, 7), typ: Arr, @@ -210,19 +302,22 @@ test("encode", t => { typ: Arr, bin: [Tag.Array16, 0xff, 0xff].concat(repeat(posFixintTag(13), 65535)), }, - // map + //#endregion + //#region map { val: {a: 7, b: 13}, typ: Map, bin: [fixmapTag(2), fixstrTag(1), 0x61, posFixintTag(7), fixstrTag(1), 0x62, posFixintTag(13)], }, - // raw + //#endregion + //#region raw { val: (new Uint8Array(repeat(0x30, 7))).buffer, typ: Raw, bin: repeat(0x30, 7), }, - // time + //#endregion + //#region time { val: new Date(Date.UTC(2017, 8, 26, 13, 14, 15)), typ: Time, @@ -233,7 +328,8 @@ test("encode", t => { typ: Time, bin: [Tag.Ext8, 12, 0xff, 0x00, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0xca, 0x52, 0xa7], }, - // any + //#endregion + //#region any { val: undefined, typ: Any, @@ -299,7 +395,8 @@ test("encode", t => { typ: Any, bin: [Tag.Ext8, 12, 0xff, 0x00, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0xca, 0x52, 0xa7], }, - // struct + //#endregion + //#region struct { val: { foo: 7, @@ -311,7 +408,8 @@ test("encode", t => { }), bin: [fixmapTag(2), posFixintTag(1), posFixintTag(7), posFixintTag(3), fixstrTag(1), 0x37], }, - // union + //#endregion + //#region union { val: 7, typ: Union({ @@ -330,6 +428,42 @@ test("encode", t => { }), bin: [fixarrayTag(2), posFixintTag(13), fixstrTag(1), 0x37], }, + //#endregion + //#region typedObj + { + val: { + a: 7, + b: '7', + }, + typ: TypedObj({ + a: Int, + b: Str, + }), + bin: [fixmapTag(2), fixstrTag(1), 0x61, posFixintTag(7), fixstrTag(1), 0x62, fixstrTag(1), 0x37], + }, + { + val: { + a: 2147483647, + b: '7', + }, + typ: TypedObj({ + a: Int32, + b: Str, + }), + bin: [fixmapTag(2), fixstrTag(1), 0x61, Tag.Int32, 0x7f, 0xff, 0xff, 0xff, fixstrTag(1), 0x62, fixstrTag(1), 0x37], + }, + { + val: { + a: 1, + b: 2, + }, + typ: TypedObj({ + a: Int32, + b: Uint32, + }), + bin: [fixmapTag(2), fixstrTag(1), 0x61, Tag.Int32, 0x00, 0x00, 0x00, 0x01, fixstrTag(1), 0x62, Tag.Uint32, 0x00, 0x00, 0x00, 0x02], + }, + //#endregion ]; for(let i = 0; i < tests.length; ++i) { @@ -338,23 +472,24 @@ test("encode", t => { const bin = encode(test.val, test.typ); const expected = new Uint8Array(test.bin); if(!bufEqual(bin, expected)) { - t.error(`unexpected encoding at ${i} for '${test.val}': ${fmtBuf(bin)}, expected ${fmtBuf(expected)}`); + t.error(`unexpected encoding at ${i} for '${JSON.stringify(test.val)}': ${fmtBuf(bin)}, expected ${fmtBuf(expected)}`); } } catch(e) { - t.error(`unexpected encoding error at ${i} for '${test.val}': ${e}`); + t.error(`unexpected encoding error at ${i} for '${JSON.stringify(test.val)}': ${e}`); } } }); test("decode", t => { const tests = [ - // nil + //#region nil { bin: [Tag.Nil], typ: Nil, val: null, }, - // bool + //#endregion + //#region bool { bin: [Tag.Nil], typ: Bool, @@ -370,7 +505,8 @@ test("decode", t => { typ: Bool, val: true, }, - // int + //#endregion + //#region int { bin: [posFixintTag(7)], typ: Int, @@ -451,7 +587,8 @@ test("decode", t => { typ: Int, val: 4992121274275, }, - // uint + //#endregion + //#region uint { bin: [posFixintTag(7)], typ: Int, @@ -502,7 +639,8 @@ test("decode", t => { typ: Int, val: 4992121274275, }, - // float + //#endregion + //#region float { bin: [Tag.Nil], typ: Float, @@ -518,7 +656,8 @@ test("decode", t => { typ: Float, val: 3.141592, }, - // bytes + //#endregion + //#region bytes { bin: [fixstrTag(5), 0x30, 0x30, 0x30, 0x30, 0x30], typ: Bytes, @@ -543,7 +682,8 @@ test("decode", t => { val: new Uint8Array(repeat(0x30, 65536)), eq: (x, y) => bufEqual(new Uint8Array(x), y), }, - // string + //#endregion + //#region string { bin: [fixstrTag(2), 0xc3, 0xa4], typ: Str, @@ -579,7 +719,8 @@ test("decode", t => { typ: Str, val: repeats("0", 65536), }, - // array + //#endregion + //#region array { bin: [fixarrayTag(2), posFixintTag(7), fixstrTag(1), 0x30], typ: Arr, @@ -598,7 +739,8 @@ test("decode", t => { val: ["∞"], eq: arrayEqual, }, - // map + //#endregion + //#region map { bin: [fixmapTag(1), fixstrTag(1), 0x61, posFixintTag(7)], typ: Map, @@ -617,7 +759,8 @@ test("decode", t => { val: {"inf": "∞"}, eq: objectEqual, }, - // raw + //#endregion + //#region raw { bin: [Tag.True], typ: Raw, @@ -768,7 +911,8 @@ test("decode", t => { val: new Uint8Array([fixmapTag(3), Tag.Nil, Tag.Nil, Tag.Nil, Tag.Nil, Tag.Nil, Tag.Nil]), eq: (x, y) => bufEqual(new Uint8Array(x), y), }, - // time + //#endregion + //#region time { bin: [Tag.FixExt4, 0xff, 0x59, 0xca, 0x52, 0xa7], typ: Time, @@ -787,7 +931,8 @@ test("decode", t => { val: new Date(Date.UTC(2017, 8, 26, 13, 14, 15, 16)), eq: dateEqual, }, - // any + //#endregion + //#region any { bin: [Tag.Nil], typ: Any, @@ -955,7 +1100,8 @@ test("decode", t => { val: new Date(Date.UTC(2017, 8, 26, 13, 14, 15, 16)), eq: dateEqual, }, - // struct + //#endregion + //#region struct { bin: [fixmapTag(2), posFixintTag(1), posFixintTag(7), posFixintTag(3), fixstrTag(1), 0x37], typ: Struct({ @@ -968,7 +1114,8 @@ test("decode", t => { }, eq: objectEqual, }, - // union + //#endregion + //#region union { bin: [fixarrayTag(2), posFixintTag(4), posFixintTag(7)], typ: Union({ @@ -987,6 +1134,45 @@ test("decode", t => { }), val: "7", }, + //#endregion + //#region typedObj + { + bin: [fixmapTag(2), fixstrTag(1), 0x61, posFixintTag(7), fixstrTag(1), 0x62, fixstrTag(1), 0x37], + typ: TypedObj({ + a: Int, + b: Str, + }), + val: { + a: 7, + b: '7', + }, + eq: objectEqual, + }, + { + bin: [fixmapTag(2), fixstrTag(1), 0x61, Tag.Int32, 0x7f, 0xff, 0xff, 0xff, fixstrTag(1), 0x62, fixstrTag(1), 0x37], + typ: TypedObj({ + a: Int32, + b: Str, + }), + val: { + a: 2147483647, + b: '7', + }, + eq: objectEqual, + }, + { + bin: [fixmapTag(2), fixstrTag(1), 0x61, Tag.Int32, 0x7f, 0xff, 0xff, 0xff, fixstrTag(1), 0x62, Tag.Uint32, 0xff, 0xff, 0xff, 0xff], + typ: TypedObj({ + a: Int32, + b: Uint32, + }), + val: { + a: 2147483647, + b: 4294967295, + }, + eq: objectEqual, + }, + //#endregion ]; for(let i = 0; i < tests.length; ++i) { @@ -996,7 +1182,7 @@ test("decode", t => { const val = decode(bin, test.typ); const eq = opEqual(test); if(!eq(val, test.val)) { - t.error(`unexpected decoding at ${i} for '${fmtBuf(bin)}': ${val}, expected ${test.val}`); + t.error(`unexpected decoding at ${i} for '${fmtBuf(bin)}': ${JSON.stringify(val)}, expected ${JSON.stringify(test.val)}`); } } catch(e) { t.error(`unexpected decoding error at ${i} for '${fmtBuf(bin)}': ${e}`); diff --git a/src/types.ts b/src/types.ts index 2a87170..db6c4b9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -148,6 +148,12 @@ export const Int: Type = { }; +export const Int8 = createSubType(Tag.Int8, Int); +export const Int16 = createSubType(Tag.Int16, Int); +export const Int32 = createSubType(Tag.Int32, Int); +export const Int64 = createSubType(Tag.Int64, Int); + + export const Uint: Type = { enc(buf: WriteBuffer, v: number): void { if(v < 0) { @@ -178,11 +184,16 @@ export const Uint: Type = { }, }; +export const Uint8 = createSubType(Tag.Uint8, Uint); +export const Uint16 = createSubType(Tag.Uint16, Uint); +export const Uint32 = createSubType(Tag.Uint32, Uint); +export const Uint64 = createSubType(Tag.Uint64, Uint); + export const Float: Type = { enc(buf: WriteBuffer, v: number): void { buf.putUi8(Tag.Float64); - buf.putF(v); + buf.putF64(v); }, dec(buf: ReadBuffer): number { @@ -201,6 +212,10 @@ export const Float: Type = { }; +export const Float64 = Float; + +export const Float32 = createSubType(Tag.Float32, Float); + export const Bytes: Type = { enc(buf: WriteBuffer, v: ArrayBuffer): void { putBlob(buf, v, Tag.Bin8); @@ -331,6 +346,31 @@ export function TypedMap(keyT: Type, valueT: Type): Collect }; } +export function TypedObj(objT: Obj>): Collection>> { + return { + encHeader: putMapHeader, + decHeader: getMapHeader, + + enc(buf: WriteBuffer, v: Obj>): void { + const props = Object.keys(v); + putMapHeader(buf, props.length); + props.forEach(p => { + Str.enc(buf, p) + objT[p].enc(buf, v[p]) + }); + }, + + dec(buf: ReadBuffer): Obj> { + const res = {}; + for(let n = getMapHeader(buf); n > 0; --n) { + const k = Str.dec(buf); + res[k] = objT[k].dec(buf); + } + return res; + }, + }; +} + export function structEncoder(fields: Fields): EncodeFunc { const ordinals = Object.keys(fields); @@ -509,3 +549,38 @@ function tagType(tag: Tag): Type { throw new TypeError(`unsupported tag ${tag}`); } } + +function createSubType(tag: Tag, type: Type) { + return { + enc(buf: WriteBuffer, v: number): void { + buf.putUi8(tag); + + switch(tag) { + case Tag.Nil: break; + + // signed int types + case Tag.Int8: buf.putI8(v); break; + case Tag.Int16: buf.putI16(v); break; + case Tag.Int32: buf.putI32(v); break; + case Tag.Int64: buf.putI64(v); break; + + // unsigned int types + case Tag.Uint8: buf.putUi8(v); break; + case Tag.Uint16: buf.putUi16(v); break; + case Tag.Uint32: buf.putUi32(v); break; + case Tag.Uint64: buf.putUi64(v); break; + + // float types + case Tag.Float32: buf.putF32(v); break; + case Tag.Float64: buf.putF64(v); break; + + default: + typeError(tag, ""); + } + }, + + dec(buf: ReadBuffer): number { + return type.dec(buf); + }, + } +} From 1e34e1e3bfea83a6c56b6fb721213a467a5e6919 Mon Sep 17 00:00:00 2001 From: ouyang Date: Mon, 12 Oct 2020 16:20:50 +0800 Subject: [PATCH 2/6] fix: add export --- src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/index.ts b/src/index.ts index 3a899d7..31876e6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ import { Type, Collection, Obj, Nil, Bool, Int, Uint, Float, Bytes, Str, TypedArr, TypedMap, Time, Any, Arr, Map, Struct, Union, + Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64, Float32, Float64, structEncoder, structDecoder, unionEncoder, unionDecoder, } from "./types"; import { @@ -13,6 +14,7 @@ export { WriteBuffer, ReadBuffer, Type, Collection, Obj, Nil, Bool, Int, Uint, Float, Bytes, Str, TypedArr, TypedMap, Time, Any, Arr, Map, Struct, Union, + Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64, Float32, Float64, structEncoder, structDecoder, unionEncoder, unionDecoder, encode, decode, }; From 280f7637d2b038d5544df959c0590b7f2f72d1f0 Mon Sep 17 00:00:00 2001 From: ouyang Date: Mon, 12 Oct 2020 16:22:08 +0800 Subject: [PATCH 3/6] patch export --- src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 31876e6..6a1cced 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ import { Type, Collection, Obj, - Nil, Bool, Int, Uint, Float, Bytes, Str, TypedArr, TypedMap, Time, Any, Arr, Map, Struct, Union, + Nil, Bool, Int, Uint, Float, Bytes, Str, TypedArr, TypedMap, TypedObj, Time, Any, Arr, Map, Struct, Union, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64, Float32, Float64, structEncoder, structDecoder, unionEncoder, unionDecoder, } from "./types"; @@ -13,7 +13,7 @@ import { export { WriteBuffer, ReadBuffer, Type, Collection, Obj, - Nil, Bool, Int, Uint, Float, Bytes, Str, TypedArr, TypedMap, Time, Any, Arr, Map, Struct, Union, + Nil, Bool, Int, Uint, Float, Bytes, Str, TypedArr, TypedMap, TypedObj, Time, Any, Arr, Map, Struct, Union, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64, Float32, Float64, structEncoder, structDecoder, unionEncoder, unionDecoder, encode, decode, From 6349b75218a05234239405b692625511532e3186 Mon Sep 17 00:00:00 2001 From: ouyang Date: Mon, 12 Oct 2020 17:19:25 +0800 Subject: [PATCH 4/6] fix: TypedObj's type error --- src/types.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/types.ts b/src/types.ts index db6c4b9..7accad6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -346,12 +346,12 @@ export function TypedMap(keyT: Type, valueT: Type): Collect }; } -export function TypedObj(objT: Obj>): Collection>> { +export function TypedObj(objT: Obj>): Collection { return { encHeader: putMapHeader, decHeader: getMapHeader, - enc(buf: WriteBuffer, v: Obj>): void { + enc(buf: WriteBuffer, v: T): void { const props = Object.keys(v); putMapHeader(buf, props.length); props.forEach(p => { @@ -360,13 +360,13 @@ export function TypedObj(objT: Obj>): Collection>> { }); }, - dec(buf: ReadBuffer): Obj> { + dec(buf: ReadBuffer): T { const res = {}; for(let n = getMapHeader(buf); n > 0; --n) { const k = Str.dec(buf); res[k] = objT[k].dec(buf); } - return res; + return res as T; }, }; } From a7bdc982fd2c3261ef8dc82d99a22822cf0b06a7 Mon Sep 17 00:00:00 2001 From: ouyang Date: Mon, 12 Oct 2020 17:30:04 +0800 Subject: [PATCH 5/6] test: add Uint32 overflow test --- src/tests.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tests.ts b/src/tests.ts index 5abd64b..654141e 100644 --- a/src/tests.ts +++ b/src/tests.ts @@ -194,6 +194,11 @@ test("encode", t => { typ: Uint32, bin: [Tag.Uint32, 0xff, 0xff, 0xff, 0xff], }, + { + val: 4294967296, + typ: Uint32, + bin: [Tag.Uint32, 0x00, 0x00, 0x00, 0x00], + }, { val: 4294967296, typ: Uint, From 610f99a20b484286413e38a15c0de1a69a21d6bf Mon Sep 17 00:00:00 2001 From: ouyang Date: Thu, 15 Oct 2020 13:18:07 +0800 Subject: [PATCH 6/6] fix: apply suggestions and fixnum #5 --- src/types.ts | 197 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 117 insertions(+), 80 deletions(-) diff --git a/src/types.ts b/src/types.ts index 7accad6..30d124b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -88,25 +88,15 @@ export const Bool: Type = { export const Int: Type = { enc(buf: WriteBuffer, v: number): void { - if(-128 <= v && v <= 127) { - if(v >= 0) { - buf.putUi8(posFixintTag(v)); - } else if(v > -32) { - buf.putUi8(negFixintTag(v)); - } else { - buf.putUi8(Tag.Int8); - buf.putUi8(v); - } - } else if(-32768 <= v && v <= 32767) { - buf.putI8(Tag.Int16); - buf.putI16(v); - } else if(-2147483648 <= v && v <= 2147483647) { - buf.putI8(Tag.Int32); - buf.putI32(v); - } else { - buf.putI8(Tag.Int64); - buf.putI64(v); - } + if (-128 <= v && v <= 127) { + Int8.enc(buf, v); + } else if (-32768 <= v && v <= 32767) { + Int16.enc(buf, v); + } else if (-2147483648 <= v && v <= 2147483647) { + Int32.enc(buf, v); + } else { + Int64.enc(buf, v); + } }, dec(buf: ReadBuffer): number { @@ -148,31 +138,65 @@ export const Int: Type = { }; -export const Int8 = createSubType(Tag.Int8, Int); -export const Int16 = createSubType(Tag.Int16, Int); -export const Int32 = createSubType(Tag.Int32, Int); -export const Int64 = createSubType(Tag.Int64, Int); +export const Int8: Type = { + enc(buf: WriteBuffer, v: number): void { + if (v >= 0) { + buf.putUi8(posFixintTag(v)); + } else if (v > -32) { + buf.putUi8(negFixintTag(v)); + } else { + buf.putUi8(Tag.Int8); + buf.putUi8(v); + } + }, + + dec: Int.dec, +}; + + +export const Int16: Type = { + enc(buf: WriteBuffer, v: number): void { + buf.putI8(Tag.Int16); + buf.putI16(v); + }, + + dec: Int.dec, +}; + + +export const Int32: Type = { + enc(buf: WriteBuffer, v: number): void { + buf.putI8(Tag.Int32); + buf.putI32(v); + }, + + dec: Int.dec, +}; + + +export const Int64: Type = { + enc(buf: WriteBuffer, v: number): void { + buf.putI8(Tag.Int64); + buf.putI64(v); + }, + + dec: Int.dec, +}; export const Uint: Type = { enc(buf: WriteBuffer, v: number): void { - if(v < 0) { - throw new Error(`not an uint: ${v}`); - } else if(v <= 127) { - buf.putUi8(posFixintTag(v)); - } else if(v <= 255) { - buf.putUi8(Tag.Uint8); - buf.putUi8(v); - } else if(v <= 65535) { - buf.putUi8(Tag.Uint16); - buf.putUi16(v); - } else if(v <= 4294967295) { - buf.putUi8(Tag.Uint32); - buf.putUi32(v); - } else { - buf.putUi8(Tag.Uint64); - buf.putUi64(v); - } + if (v < 0) { + throw new Error(`not an uint: ${v}`); + } else if (v <= 255) { + Uint8.enc(buf, v); + } else if (v <= 65535) { + Uint16.enc(buf, v); + } else if (v <= 4294967295) { + Uint32.enc(buf, v); + } else { + Uint64.enc(buf, v); + } }, dec(buf: ReadBuffer): number { @@ -184,10 +208,49 @@ export const Uint: Type = { }, }; -export const Uint8 = createSubType(Tag.Uint8, Uint); -export const Uint16 = createSubType(Tag.Uint16, Uint); -export const Uint32 = createSubType(Tag.Uint32, Uint); -export const Uint64 = createSubType(Tag.Uint64, Uint); + +export const Uint8: Type = { + enc(buf: WriteBuffer, v: number): void { + if (v <= 127) { + buf.putUi8(posFixintTag(v)); + } else { + buf.putUi8(Tag.Uint8); + buf.putUi8(v); + } + }, + + dec: Uint.dec, +}; + + +export const Uint16: Type = { + enc(buf: WriteBuffer, v: number): void { + buf.putUi8(Tag.Uint16); + buf.putUi16(v); + }, + + dec: Uint.dec, +}; + + +export const Uint32: Type = { + enc(buf: WriteBuffer, v: number): void { + buf.putUi8(Tag.Uint32); + buf.putUi32(v); + }, + + dec: Uint.dec, +}; + + +export const Uint64: Type = { + enc(buf: WriteBuffer, v: number): void { + buf.putUi8(Tag.Uint64); + buf.putUi64(v); + }, + + dec: Uint.dec, +}; export const Float: Type = { @@ -214,7 +277,16 @@ export const Float: Type = { export const Float64 = Float; -export const Float32 = createSubType(Tag.Float32, Float); + +export const Float32: Type = { + enc(buf: WriteBuffer, v: number): void { + buf.putUi8(Tag.Float32); + buf.putF32(v); + }, + + dec: Float.dec, +}; + export const Bytes: Type = { enc(buf: WriteBuffer, v: ArrayBuffer): void { @@ -549,38 +621,3 @@ function tagType(tag: Tag): Type { throw new TypeError(`unsupported tag ${tag}`); } } - -function createSubType(tag: Tag, type: Type) { - return { - enc(buf: WriteBuffer, v: number): void { - buf.putUi8(tag); - - switch(tag) { - case Tag.Nil: break; - - // signed int types - case Tag.Int8: buf.putI8(v); break; - case Tag.Int16: buf.putI16(v); break; - case Tag.Int32: buf.putI32(v); break; - case Tag.Int64: buf.putI64(v); break; - - // unsigned int types - case Tag.Uint8: buf.putUi8(v); break; - case Tag.Uint16: buf.putUi16(v); break; - case Tag.Uint32: buf.putUi32(v); break; - case Tag.Uint64: buf.putUi64(v); break; - - // float types - case Tag.Float32: buf.putF32(v); break; - case Tag.Float64: buf.putF64(v); break; - - default: - typeError(tag, ""); - } - }, - - dec(buf: ReadBuffer): number { - return type.dec(buf); - }, - } -}