Skip to content
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

Store maps directly as objects #23

Merged
merged 1 commit into from
Sep 2, 2024
Merged
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
8 changes: 0 additions & 8 deletions deno.json

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "libshv-js",
"version": "3.1.6",
"version": "3.2.0",
"description": "Typescript implementation of libshv",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
Expand Down
57 changes: 34 additions & 23 deletions src/chainpack.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {utf8ToString} from './cpon';
import {type RpcValue, type RpcValueType, type DateTime, Decimal, Double, IMap, Int, MetaMap, RpcValueWithMetaData, ShvMap, UInt, withOffset} from './rpcvalue';
import {type RpcValue, type RpcValueType, type DateTime, Decimal, Double, type IMap, Int, type MetaMap, RpcValueWithMetaData, type ShvMap, UInt, withOffset, shvMapType} from './rpcvalue';
import {UnpackContext, PackContext} from './cpcontext';

enum PackingSchema {
Expand Down Expand Up @@ -297,19 +297,24 @@ class ChainPackReader {
}

readMetaMap() {
return this.implReadMap(MetaMap);
return this.implReadMap('metamap');
}

readMap() {
return this.implReadMap(ShvMap);
return this.implReadMap('map');
}

readIMap() {
return this.implReadMap(IMap);
return this.implReadMap('imap');
}

private implReadMap<MapType extends MetaMap | ShvMap | IMap>(MapTypeCtor: new () => MapType) {
const map = new MapTypeCtor();
private implReadMap(map_type: 'map'): ShvMap;
private implReadMap(map_type: 'imap'): IMap;
private implReadMap(map_type: 'metamap'): MetaMap;
private implReadMap(map_type: 'map' | 'imap' | 'metamap') {
const map: ShvMap | IMap | MetaMap = {
[shvMapType]: map_type,
};
while (true) {
const b = this.ctx.peekByte();
if (b as PackingSchema === PackingSchema.Term) {
Expand All @@ -318,14 +323,14 @@ class ChainPackReader {
}
const key = this.read();
const val = this.read();
if (map instanceof MetaMap && typeof key === 'string') {
map.value[key] = val;
} else if (map instanceof MetaMap && key instanceof Int) {
map.value[Number(key)] = val;
} else if (map instanceof ShvMap && typeof key === 'string') {
map.value[key] = val;
} else if (map instanceof IMap && key instanceof Int) {
map.value[Number(key)] = val;
if (map[shvMapType] === 'metamap' && typeof key === 'string') {
map[key] = val;
} else if (map[shvMapType] === 'metamap' && key instanceof Int) {
map[Number(key)] = val;
} else if (map[shvMapType] === 'map' && typeof key === 'string') {
map[key] = val;
} else if (map[shvMapType] === 'imap' && key instanceof Int) {
map[Number(key)] = val;
} else {
throw new TypeError('Malformed map, invalid key');
}
Expand Down Expand Up @@ -371,15 +376,21 @@ class ChainPackWriter {
case Array.isArray(rpc_val):
this.writeList(rpc_val);
break;
case rpc_val instanceof IMap:
this.writeIMap(rpc_val);
break;
case rpc_val instanceof ShvMap:
this.writeMap(rpc_val);
break;
case rpc_val instanceof Date:
this.writeDateTime(rpc_val);
break;
case rpc_val instanceof Double:
throw new Error('writing doubles not implemented');
case typeof rpc_val === 'object':
switch (rpc_val[shvMapType]) {
case 'imap':
this.writeIMap(rpc_val);
break;
case 'map':
this.writeMap(rpc_val);
break;
}
break;
default:
console.log('Can\'t serialize', rpc_val);
throw new Error('Can\'t serialize');
Expand Down Expand Up @@ -545,19 +556,19 @@ class ChainPackWriter {
}

writeMapContent(map: MetaMap | ShvMap | IMap) {
for (const [key, value] of Object.entries(map.value)) {
for (const [key, value] of Object.entries(map)) {
if (value === undefined) {
continue;
}

if (map instanceof IMap) {
if (map[shvMapType] === 'imap') {
const int_key = Number(key);
if (Number.isNaN(int_key)) {
throw new TypeError('Invalid NaN IMap key');
}

this.writeInt(new Int(int_key));
} else if (map instanceof MetaMap) {
} else if (map[shvMapType] === 'metamap') {
const int_key = Number(key);
if (Number.isNaN(int_key)) {
this.writeJSString(key.toString());
Expand Down
59 changes: 34 additions & 25 deletions src/cpon.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {type RpcValue, type RpcValueType, type DateTime, type List, Decimal, Double, IMap, Int, MetaMap, RpcValueWithMetaData, ShvMap, UInt, withOffset} from './rpcvalue';
import {type RpcValue, type RpcValueType, type DateTime, type List, Decimal, Double, type IMap, Int, type MetaMap, RpcValueWithMetaData, type ShvMap, UInt, withOffset, shvMapType, isShvMap, isIMap} from './rpcvalue';
import {PackContext, UnpackContext} from './cpcontext';

const hexify = (byte: number) => {
Expand Down Expand Up @@ -412,15 +412,15 @@ class CponReader {
}

readMetaMap() {
return this.implReadMap(MetaMap, '>'.codePointAt(0)!);
return this.implReadMap('metamap', '>'.codePointAt(0)!);
}

readMap() {
return this.implReadMap(ShvMap, '}'.codePointAt(0)!);
return this.implReadMap('map', '}'.codePointAt(0)!);
}

readIMap() {
return this.implReadMap(IMap, '}'.codePointAt(0)!);
return this.implReadMap('imap', '}'.codePointAt(0)!);
}

readInt() {
Expand Down Expand Up @@ -550,8 +550,13 @@ class CponReader {
return new Int(is_neg ? -mantisa : mantisa);
}

private implReadMap<MapType extends MetaMap | ShvMap | IMap>(MapTypeCtor: new () => MapType, terminator: number) {
const map = new MapTypeCtor();
private implReadMap(map_type: 'map', terminator: number): ShvMap;
private implReadMap(map_type: 'imap', terminator: number): IMap;
private implReadMap(map_type: 'metamap', terminator: number): MetaMap;
private implReadMap(map_type: 'map' | 'imap' | 'metamap', terminator: number) {
const map: MetaMap | ShvMap | IMap = {
[shvMapType]: map_type,
};
this.ctx.getByte(); // eat start
while (true) {
this.skipWhitespace();
Expand All @@ -568,14 +573,14 @@ class CponReader {
this.skipWhitespace();
const val = this.read();

if (map instanceof MetaMap && typeof key === 'string') {
map.value[key] = val;
} else if (map instanceof MetaMap && (key instanceof UInt || key instanceof Int)) {
map.value[Number(key)] = val;
} else if (map instanceof ShvMap && typeof key === 'string') {
map.value[key] = val;
} else if (map instanceof IMap && (key instanceof UInt || key instanceof Int)) {
map.value[Number(key)] = val;
if (map[shvMapType] === 'metamap' && typeof key === 'string') {
map[key] = val;
} else if (map[shvMapType] === 'metamap' && (key instanceof UInt || key instanceof Int)) {
map[Number(key)] = val;
} else if (map[shvMapType] === 'map' && typeof key === 'string') {
map[key] = val;
} else if (map[shvMapType] === 'imap' && (key instanceof UInt || key instanceof Int)) {
map[Number(key)] = val;
} else {
throw new TypeError('Malformed map, invalid key');
}
Expand Down Expand Up @@ -625,15 +630,19 @@ class CponWriter {
case Array.isArray(rpc_val):
this.writeList(rpc_val);
break;
case rpc_val instanceof IMap:
this.writeIMap(rpc_val);
break;
case rpc_val instanceof ShvMap:
this.writeMap(rpc_val);
break;
case rpc_val instanceof Date:
this.writeDateTime(rpc_val);
break;
case typeof rpc_val === 'object':
switch (rpc_val[shvMapType]) {
case 'imap':
this.writeIMap(rpc_val);
break;
case 'map':
this.writeMap(rpc_val);
break;
}
break;
default:
console.log('Can\'t serialize rpc value', rpc_val);
throw new Error('Can\'t serialize rpc value');
Expand Down Expand Up @@ -761,7 +770,7 @@ class CponWriter {
this.increaseIndentIfNotOneLiner(map);
this.doIndentIfNotOneliner(map);
let first = true;
for (const [key, value] of Object.entries(map.value)) {
for (const [key, value] of Object.entries(map)) {
if (value === undefined) {
continue;
}
Expand All @@ -771,14 +780,14 @@ class CponWriter {
}
first = false;

if (map instanceof IMap) {
if (map[shvMapType] === 'imap') {
const int_key = Number(key);
if (Number.isNaN(int_key)) {
throw new TypeError('Invalid NaN IMap key');
}

this.writeInt(new Int(int_key));
} else if (map instanceof MetaMap) {
} else if (map[shvMapType] === 'metamap') {
const int_key = Number(key);
if (Number.isNaN(int_key)) {
this.ctx.putByte('"'.codePointAt(0)!);
Expand Down Expand Up @@ -881,10 +890,10 @@ class CponWriter {
const keyThreshold = Array.isArray(value) ? 10 : 5;

if (Array.isArray(value)) {
return value.length <= keyThreshold && !(value.some(x => Array.isArray(x) || x instanceof ShvMap || x instanceof IMap));
return value.length <= keyThreshold && !(value.some(x => Array.isArray(x) || isShvMap(x) || isIMap(x)));
}

return Object.keys(value.value).length <= keyThreshold && !(Object.values(value.value).some(x => Array.isArray(x) || x instanceof ShvMap || x instanceof IMap));
return Object.keys(value).length <= keyThreshold && !(Object.values(value).some(x => Array.isArray(x) || isShvMap(x) || isIMap(x)));
}

private increaseIndentIfNotOneLiner(value: MetaMap | ShvMap | IMap | List) {
Expand Down
Loading
Loading