import { JSON } from "../.."; import { BRACKET_LEFT, BRACKET_RIGHT, BRACE_LEFT, BRACE_RIGHT, CHAR_F, CHAR_T, COMMA, QUOTE, } from "../../custom/chars"; import { isSpace, atoi, scanStringEnd } from "../../util"; function scanSetElementEnd(srcStart: usize, srcEnd: usize): usize { const first = load(srcStart); if (first == QUOTE) { const end = scanStringEnd(srcStart, srcEnd); return end < srcEnd ? end + 2 : 0; } if (first == BRACE_LEFT || first == BRACKET_LEFT) { let depth: i32 = 1; let ptr = srcStart + 2; while (ptr < srcEnd) { const code = load(ptr); if (code == QUOTE) { ptr = scanStringEnd(ptr, srcEnd); if (ptr >= srcEnd) return 0; } else if (code == BRACE_LEFT || code == BRACKET_LEFT) { depth++; } else if (code == BRACE_RIGHT || code == BRACKET_RIGHT) { if (--depth == 0) return ptr + 2; } ptr += 2; } return 0; } let ptr = srcStart; while (ptr < srcEnd) { const code = load(ptr); if (code == COMMA || code == BRACKET_RIGHT) return ptr; ptr += 2; } return 0; } function deserializeSetDirect>( srcStart: usize, srcEnd: usize, out: nonnull, ): usize { if (srcStart >= srcEnd || load(srcStart) != BRACKET_LEFT) throw new Error("Expected '[' at start of set"); srcStart += 2; while (srcStart < srcEnd && isSpace(load(srcStart))) srcStart += 2; if (srcStart >= srcEnd) throw new Error("Unterminated set"); if (load(srcStart) == BRACKET_RIGHT) return srcStart + 2; while (srcStart < srcEnd) { while (srcStart < srcEnd && isSpace(load(srcStart))) srcStart += 2; const code = load(srcStart); // @ts-ignore: type if (isString>()) { if (code != QUOTE) break; const end = scanStringEnd(srcStart, srcEnd); if (end >= srcEnd) break; // @ts-ignore: type out.add(JSON.__deserialize>(srcStart, end + 2)); srcStart = end + 2; // @ts-ignore: type } else if (isBoolean>()) { if (code == CHAR_T) { // @ts-ignore: type out.add(>true); srcStart += 8; } else if (code == CHAR_F) { // @ts-ignore: type out.add(>false); srcStart += 10; } else { break; } // @ts-ignore: type } else if (isInteger>()) { if (code - 48 > 9 && code != 45) break; let ptr = srcStart + 2; while (ptr < srcEnd) { const next = load(ptr); if (next == COMMA || next == BRACKET_RIGHT || isSpace(next)) break; ptr += 2; } // @ts-ignore: type out.add(atoi>(srcStart, ptr)); srcStart = ptr; // @ts-ignore: type } else if (isFloat>()) { if (code - 48 > 9 && code != 45) break; let ptr = srcStart + 2; while (ptr < srcEnd) { const next = load(ptr); if (next == COMMA || next == BRACKET_RIGHT || isSpace(next)) break; ptr += 2; } // @ts-ignore: type out.add(JSON.__deserialize>(srcStart, ptr)); srcStart = ptr; // @ts-ignore: type } else if (isManaged>() || isReference>()) { const end = scanSetElementEnd(srcStart, srcEnd); if (!end) break; // @ts-ignore: type out.add(JSON.__deserialize>(srcStart, end)); srcStart = end; } else { break; } while (srcStart < srcEnd && isSpace(load(srcStart))) srcStart += 2; if (srcStart >= srcEnd) break; const next = load(srcStart); if (next == COMMA) { srcStart += 2; while (srcStart < srcEnd && isSpace(load(srcStart))) srcStart += 2; continue; } if (next == BRACKET_RIGHT) return srcStart + 2; break; } throw new Error("Failed to parse JSON!"); } export function deserializeSet>( srcStart: usize, srcEnd: usize, dst: usize, ): T { const out = changetype>( dst || changetype(instantiate()), ); out.clear(); while (srcEnd > srcStart && isSpace(load(srcEnd - 2))) srcEnd -= 2; if (srcStart >= srcEnd) throw new Error("Input string had zero length or was all whitespace"); const end = deserializeSetDirect(srcStart, srcEnd, out); if (end != srcEnd) throw new Error("Expected ']' at end of set"); return out; } function deserializeSetBody>( srcStart: usize, srcEnd: usize, out: T, ): usize { changetype>(out).clear(); return deserializeSetDirect(srcStart, srcEnd, changetype>(out)); } export function deserializeSetField>( srcStart: usize, srcEnd: usize, dstObj: usize, dstOffset: usize = 0, ): usize { const fieldPtr = dstObj + dstOffset; let out = load(fieldPtr); if (!changetype(out)) { out = changetype(instantiate()); store(fieldPtr, out); } return deserializeSetBody(srcStart, srcEnd, out); }