printData = async (data, indent) => {
	if (!Array.isArray(data)) throw new Error("Not an array");
	if (Buffer.isBuffer(data[0])) {
		for (const b of data) {
			if (typeof b === "function") {
				const innerData = await b();
				const info = /** @type {SizeInfo} */ (lazySizes.shift());
				const sizeInfo = `${(info.size / 1048576).toFixed(2)} MiB + ${(
					info.lazySize / 1048576
				).toFixed(2)} lazy MiB`;
				console.log(`${indent}= lazy ${sizeInfo} {`);
				await printData(innerData, `${indent}  `);
				console.log(`${indent}}`);
			} else {
				console.log(`${indent}= ${b.toString("hex")}`);
			}
		}
		return;
	}
	const referencedValues = new Map();
	const referencedValuesCounters = new Map();
	const referencedTypes = new Map();
	let currentReference = 0;
	let currentTypeReference = 0;
	let i = 0;
	const read = () => data[i++];
	/**
	 * @param {string} content content
	 */
	const printLine = content => {
		console.log(`${indent}${content}`);
	};
	printLine(`Version: ${read()}`);
	while (i < data.length) {
		const item = read();
		if (item === ESCAPE) {
			const nextItem = read();
			if (nextItem === ESCAPE_ESCAPE_VALUE) {
				printLine("null");
			} else if (nextItem === ESCAPE_UNDEFINED) {
				printLine("undefined");
			} else if (nextItem === ESCAPE_END_OBJECT) {
				indent = indent.slice(0, -2);
				printLine(`} = #${currentReference++}`);
			} else if (typeof nextItem === "number" && nextItem < 0) {
				const ref = currentReference + nextItem;
				const value = referencedValues.get(ref);
				referencedValuesCounters.set(
					ref,
					(referencedValuesCounters.get(ref) || 0) + 1
				);
				if (value) {
					printLine(
						`Reference ${nextItem} => ${JSON.stringify(value)} #${ref}`
					);
				} else {
					printLine(`Reference ${nextItem} => #${ref}`);
				}
			} else {
				const request = nextItem;
				if (typeof request === "number") {
					const ref = currentTypeReference - request;
					printLine(
						`Object (Reference ${request} => ${referencedTypes.get(
							ref
						)} @${ref}) {`
					);
				} else {
					const name = read();
					referencedTypes.set(currentTypeReference, `${request} / ${name}`);
					printLine(
						`Object (${request} / ${name} @${currentTypeReference++}) {`
					);
				}
				indent += "  ";
			}
		} else if (typeof item === "string") {
			if (item !== "") {
				referencedValues.set(currentReference, item);
				printLine(`${JSON.stringify(item)} = #${currentReference++}`);
			} else {
				printLine('""');
			}
		} else if (Buffer.isBuffer(item)) {
			printLine(`buffer ${item.toString("hex")} = #${currentReference++}`);
		} else if (typeof item === "function") {
			const innerData = await item();
			if (!SerializerMiddleware.isLazy(item, binaryMiddleware)) {
				const info = /** @type {SizeInfo} */ (lazySizes.shift());
				const sizeInfo = `${(info.size / 1048576).toFixed(2)} MiB + ${(
					info.lazySize / 1048576
				).toFixed(2)} lazy MiB`;
				printLine(`lazy-file ${sizeInfo} {`);
			} else {
				printLine("lazy-inline {");
			}
			await printData(innerData, `${indent}  `);
			printLine("}");
		} else {
			printLine(String(item));
		}
	}
	const refCounters = Array.from(referencedValuesCounters);
	refCounters.sort(([a, A], [b, B]) => B - A);
	printLine("SUMMARY: top references:");
	for (const [ref, count] of refCounters.slice(10)) {
		const value = referencedValues.get(ref);
		if (value) {
			printLine(`- #${ref} x ${count} = ${JSON.stringify(value)}`);
		} else {
			printLine(`- #${ref} x ${count}`);
		}
	}
}
@param {Array<EXPECTED_ANY>} data data
@param {string} indent indent
@returns {Promise<void>} promise