Skip to content

Commit 4668c52

Browse files
committed
feat: map deserialization
1 parent 33840f0 commit 4668c52

File tree

5 files changed

+129
-299
lines changed

5 files changed

+129
-299
lines changed

assembly/deserialize/simple/map.ts

+111-108
Original file line numberDiff line numberDiff line change
@@ -1,132 +1,135 @@
1-
import { Virtual } from "as-virtual/assembly";
2-
import { containsCodePoint, unsafeCharCodeAt } from "../../custom/util";
3-
import { CHAR_A, BACK_SLASH, COLON, COMMA, CHAR_E, CHAR_F, CHAR_L, BRACE_LEFT, BRACKET_LEFT, CHAR_N, QUOTE, CHAR_R, BRACE_RIGHT, BRACKET_RIGHT, CHAR_S, CHAR_T, CHAR_U } from "../../custom/chars";
4-
import { deserializeBoolean } from "./bool";
51
import { JSON } from "../..";
6-
import { deserializeString } from "./string";
2+
import { BACK_SLASH, COMMA, CHAR_F, BRACE_LEFT, BRACKET_LEFT, CHAR_N, QUOTE, BRACE_RIGHT, BRACKET_RIGHT, CHAR_T, COLON } from "../../custom/chars";
73
import { isSpace } from "../../util";
8-
import { deserializeInteger } from "./integer";
9-
import { deserializeFloat } from "./float";
104

11-
// @ts-ignore: Decorator valid here
12-
@inline export function deserializeMap<T extends Map>(data: string): T {
13-
const map: nonnull<T> = changetype<nonnull<T>>(__new(offsetof<nonnull<T>>(), idof<nonnull<T>>()));
5+
export function deserializeMap<T extends Map<any, any>>(srcStart: usize, srcEnd: usize, dst: T | null = null): T {
6+
// @ts-ignore: type
7+
if (!isString<indexof<T>>() && !isInteger<indexof<T>>()) ERROR("Map key must be of type string | number!");
8+
dst = dst || changetype<nonnull<T>>(__new(offsetof<nonnull<T>>(), idof<nonnull<T>>()));
9+
console.log("Data: " + str(srcStart, srcEnd));
1410

15-
const key = Virtual.createEmpty<string>();
11+
const srcPtr = srcStart;
12+
let key: string | null = null;
1613
let isKey = false;
1714
let depth = 0;
18-
let outerLoopIndex = 1;
19-
for (; outerLoopIndex < data.length - 1; outerLoopIndex++) {
20-
const char = unsafeCharCodeAt(data, outerLoopIndex);
21-
if (char == BRACKET_LEFT) {
22-
for (let arrayValueIndex = outerLoopIndex; arrayValueIndex < data.length - 1; arrayValueIndex++) {
23-
const char = unsafeCharCodeAt(data, arrayValueIndex);
24-
if (char == BRACKET_LEFT) {
25-
depth++;
26-
} else if (char == BRACKET_RIGHT) {
27-
depth--;
28-
if (depth == 0) {
29-
++arrayValueIndex;
30-
map.set(deserializeMapKey<indexof<T>>(key), JSON.parse<valueof<T>>(data.slice(outerLoopIndex, arrayValueIndex)));
31-
outerLoopIndex = arrayValueIndex;
32-
isKey = false;
33-
break;
15+
let lastIndex = 0;
16+
17+
// while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
18+
// while (srcEnd > srcStart && isSpace(load<u16>(srcEnd))) srcEnd -= 2;
19+
20+
while (srcStart < srcEnd) {
21+
let code = load<u16>(srcStart); // while (isSpace(code)) code = load<u16>(srcStart += 2);
22+
if (key == null) {
23+
if (code == QUOTE && load<u16>(srcStart - 2) !== BACK_SLASH) {
24+
if (isKey) {
25+
key = sliceTo(lastIndex, srcStart);
26+
console.log("Key: " + key);
27+
while (isSpace((code = load<u16>((srcStart += 2))))) {
28+
/* empty */
3429
}
30+
if (code !== COLON) throw new Error("Expected ':' after key at position " + (srcStart - srcPtr).toString());
31+
isKey = false;
32+
} else {
33+
isKey = true; // i don't like this
34+
lastIndex = srcStart + 2;
3535
}
3636
}
37-
} else if (char == BRACE_LEFT) {
38-
for (let objectValueIndex = outerLoopIndex; objectValueIndex < data.length - 1; objectValueIndex++) {
39-
const char = unsafeCharCodeAt(data, objectValueIndex);
40-
if (char == BRACE_LEFT) {
41-
depth++;
42-
} else if (char == BRACE_RIGHT) {
43-
depth--;
44-
if (depth == 0) {
45-
++objectValueIndex;
46-
map.set(deserializeMapKey<indexof<T>>(key), JSON.parse<valueof<T>>(data.slice(outerLoopIndex, objectValueIndex)));
47-
outerLoopIndex = objectValueIndex;
48-
isKey = false;
37+
// isKey = !isKey;
38+
srcStart += 2;
39+
} else {
40+
if (code == QUOTE) {
41+
lastIndex = srcStart;
42+
srcStart += 2;
43+
while (srcStart < srcEnd) {
44+
const code = load<u16>(srcStart);
45+
if (code == QUOTE && load<u16>(srcStart - 2) !== BACK_SLASH) {
46+
while (isSpace(load<u16>((srcStart += 2)))) {
47+
/* empty */
48+
}
49+
console.log("Value (string): " + str(lastIndex, srcStart));
50+
dst.set(key, JSON.__deserialize<valueof<T>>(lastIndex, srcStart));
51+
key = null;
4952
break;
5053
}
54+
srcStart += 2;
5155
}
52-
}
53-
} else if (char == QUOTE) {
54-
let escaping = false;
55-
for (let stringValueIndex = ++outerLoopIndex; stringValueIndex < data.length - 1; stringValueIndex++) {
56-
const char = unsafeCharCodeAt(data, stringValueIndex);
57-
if (char == BACK_SLASH && !escaping) {
58-
escaping = true;
59-
} else {
60-
if (char == QUOTE && !escaping) {
61-
if (isKey == false) {
62-
// perf: we can avoid creating a new string here if the key doesn't contain any escape sequences
63-
if (containsCodePoint(data, BACK_SLASH, outerLoopIndex, stringValueIndex)) {
64-
key.reinst(deserializeString(data, outerLoopIndex - 1, stringValueIndex));
65-
} else {
66-
key.reinst(data, outerLoopIndex, stringValueIndex);
67-
}
68-
isKey = true;
69-
} else {
70-
if (isString<valueof<T>>()) {
71-
const value = deserializeString(data, outerLoopIndex - 1, stringValueIndex);
72-
map.set(deserializeMapKey<indexof<T>>(key), value);
73-
}
74-
isKey = false;
56+
} else if (code - 48 <= 9 || code == 45) {
57+
lastIndex = srcStart;
58+
srcStart += 2;
59+
while (srcStart < srcEnd) {
60+
const code = load<u16>(srcStart);
61+
if (code == COMMA || isSpace(code) || code == BRACE_RIGHT) {
62+
dst.set(key, JSON.__deserialize<valueof<T>>(lastIndex, srcStart));
63+
console.log("Value (number): " + str(lastIndex, srcStart));
64+
while (isSpace(load<u16>((srcStart += 2)))) {
65+
/* empty */
7566
}
76-
outerLoopIndex = ++stringValueIndex;
67+
key = null;
7768
break;
7869
}
79-
escaping = false;
70+
srcStart += 2;
8071
}
81-
}
82-
} else if (char == CHAR_N && unsafeCharCodeAt(data, ++outerLoopIndex) == CHAR_U && unsafeCharCodeAt(data, ++outerLoopIndex) == CHAR_L && unsafeCharCodeAt(data, ++outerLoopIndex) == CHAR_L) {
83-
if (isNullable<valueof<T>>()) {
84-
map.set(deserializeMapKey<indexof<T>>(key), null);
85-
}
86-
isKey = false;
87-
} else if (char == CHAR_T && unsafeCharCodeAt(data, ++outerLoopIndex) == CHAR_R && unsafeCharCodeAt(data, ++outerLoopIndex) == CHAR_U && unsafeCharCodeAt(data, ++outerLoopIndex) == CHAR_E) {
88-
if (isBoolean<valueof<T>>()) {
89-
map.set(deserializeMapKey<indexof<T>>(key), true);
90-
}
91-
isKey = false;
92-
} else if (char == CHAR_F && unsafeCharCodeAt(data, ++outerLoopIndex) == CHAR_A && unsafeCharCodeAt(data, ++outerLoopIndex) == CHAR_L && unsafeCharCodeAt(data, ++outerLoopIndex) == CHAR_S && unsafeCharCodeAt(data, ++outerLoopIndex) == CHAR_E) {
93-
if (isBoolean<valueof<T>>()) {
94-
map.set(deserializeMapKey<indexof<T>>(key), false);
95-
}
96-
isKey = false;
97-
} else if ((char >= 48 && char <= 57) || char == 45) {
98-
let numberValueIndex = ++outerLoopIndex;
99-
for (; numberValueIndex < data.length; numberValueIndex++) {
100-
const char = unsafeCharCodeAt(data, numberValueIndex);
101-
if (char == COLON || char == COMMA || char == BRACE_RIGHT || isSpace(char)) {
102-
if (isInteger<valueof<T>>()) {
103-
map.set(deserializeMapKey<indexof<T>>(key), deserializeInteger<valueof<T>>(data.slice(outerLoopIndex - 1, numberValueIndex)));
104-
} else if (isFloat<valueof<T>>()) {
105-
map.set(deserializeMapKey<indexof<T>>(key), deserializeFloat<valueof<T>>(data.slice(outerLoopIndex - 1, numberValueIndex)));
72+
} else if (code == BRACE_LEFT) {
73+
lastIndex = srcStart;
74+
depth++;
75+
srcStart += 2;
76+
while (srcStart < srcEnd) {
77+
const code = load<u16>(srcStart);
78+
if (((code ^ BRACE_RIGHT) | (code ^ BRACKET_RIGHT)) == 32) {
79+
if (--depth == 0) {
80+
dst.set(key, JSON.__deserialize<valueof<T>>(lastIndex, srcStart));
81+
while (isSpace(load<u16>((srcStart += 2)))) {
82+
/* empty */
83+
}
84+
key = null;
85+
break;
86+
}
87+
} else if (((code ^ BRACE_LEFT) | (code ^ BRACKET_LEFT)) == 220) depth++;
88+
srcStart += 2;
89+
}
90+
} else if (code == CHAR_T) {
91+
if (load<u64>(srcStart) == 28429475166421108) {
92+
dst.set(key, JSON.__deserialize<valueof<T>>(srcStart, srcStart += 8));
93+
console.log("Value (bool): " + str(srcStart - 8, srcStart));
94+
while (isSpace(load<u16>((srcStart += 2)))) {
95+
/* empty */
96+
}
97+
key = null;
98+
}
99+
} else if (code == CHAR_F) {
100+
if (load<u64>(srcStart, 2) == 28429466576093281) {
101+
dst.set(key, JSON.__deserialize<valueof<T>>(srcStart, srcStart += 10));
102+
console.log("Value (bool): " + str(srcStart - 10, srcStart));
103+
while (isSpace(load<u16>((srcStart += 2)))) {
104+
/* empty */
105+
}
106+
key = null;
107+
}
108+
} else if (code == CHAR_N) {
109+
if (load<u64>(srcStart) == 30399761348886638) {
110+
dst.set(key, JSON.__deserialize<valueof<T>>(srcStart, srcStart += 8));
111+
console.log("Value (null): " + str(srcStart - 8, srcStart));
112+
while (isSpace(load<u16>((srcStart += 2)))) {
113+
/* empty */
106114
}
107-
outerLoopIndex = numberValueIndex;
108-
isKey = false;
109-
break;
110115
}
111116
}
112117
}
113118
}
114-
115-
return map;
119+
return dst;
116120
}
117121

118-
//@ts-ignore: Decorator
119-
function deserializeMapKey<T>(key: Virtual<string>): T {
120-
const k = key.copyOut();
121-
if (isString<T>()) {
122-
return k as T;
123-
} else if (isBoolean<T>()) {
124-
return deserializeBoolean(k) as T;
125-
} else if (isInteger<T>()) {
126-
return deserializeInteger<T>(k);
127-
} else if (isFloat<T>()) {
128-
return deserializeFloat<T>(k);
129-
}
130-
131-
throw new Error(`JSON: Cannot parse JSON object to a Map with a key of type ${nameof<T>()}`);
122+
function str(start: usize, end: usize): string {
123+
const size = end - start;
124+
const out = __new(size, idof<string>());
125+
memory.copy(out, start, size);
126+
return changetype<string>(out);
132127
}
128+
129+
// @ts-ignore: Decorator valid here
130+
@inline function sliceTo(srcStart: usize, srcEnd: usize): string {
131+
const dstSize = srcEnd - srcStart;
132+
const dst = __new(dstSize, idof<string>());
133+
memory.copy(dst, srcStart, dstSize);
134+
return changetype<string>(dst);
135+
}

0 commit comments

Comments
 (0)