qtdatastream-web
v0.0.1
Published
Browser-native TypeScript (de)serializer for Qt's QDataStream format
Maintainers
Readme
qtdatastream-web
A TypeScript (de)serializer for Qt's QDataStream
format that runs natively in the browser — built only on Uint8Array,
DataView, BigInt, and TextEncoder/TextDecoder. No Buffer, no Node
streams, no polyfills.
Supported types: QBool, QShort, QInt, QInt64, QUInt, QUInt64,
QDouble, QMap, QList, QString, QVariant, QStringList, QByteArray,
QUserType, QDateTime, QTime, QChar, QInvalid.
Install
npm install qtdatastream-webThe package ships ES modules and TypeScript declarations. There is no default runtime dependency.
Quick start
import { read, write } from 'qtdatastream-web';
// Serialize a value to a Uint8Array...
const bytes = write({ AString: 'BString', CString: 42 });
// ...and read it back.
const value = read(bytes); // { AString: 'BString', CString: 42 }write/read operate on a single QVariant with no framing — convenient for
reading from and writing to files. Input to read may be a Uint8Array,
ArrayBuffer, any TypedArray, or a number[]; output is always a
Uint8Array.
Reading a file in the browser
import { read } from 'qtdatastream-web';
const file = input.files[0];
const value = read(await file.arrayBuffer());Writing a file in the browser
import { write } from 'qtdatastream-web';
const blob = new Blob([write(value)], { type: 'application/octet-stream' });
const url = URL.createObjectURL(blob);API
import {
read, write, // single QVariant, no length prefix
readAll, // read every QVariant until the buffer is exhausted
readPacket, writePacket, // QVariant prefixed with a 4-byte big-endian length
ReadBuffer, // sequential big-endian reader over a byte buffer
types, // all Q* type classes + Types enum
util, // str(), date <-> Julian day, deep mapping
bytes, // low-level byte/encoding helpers
serialization, // Serializable / serialize decorators
} from 'qtdatastream-web';Submodules are also importable directly, e.g. qtdatastream-web/types.
Type inference
JavaScript values are coerced to Qt types automatically.
| JavaScript | QClass | |------------|---------------------------------| | string | QString | | number | QUInt (configurable) | | bigint | QInt64 | | boolean | QBool | | Array | QList<QVariant<?>> | | Date | QDateTime | | Map | QMap | | Object | QMap |
Force any value into a specific Qt type with <QClass>.from:
import { types } from 'qtdatastream-web';
const qbytearray = types.QByteArray.from('hello'); // string written as a QByteArrayChange the default class plain numbers coerce to:
import { types } from 'qtdatastream-web';
types.QVariant.coerceNumbersTo(types.Types.DOUBLE); // numbers now serialize as QDoubleReading back to JavaScript
| QClass | JavaScript | |-------------|----------------| | QString | string | | QUInt/QInt/QShort/QDouble/QTime | number | | QUInt64/QInt64 | bigint | | QBool | boolean | | QList | Array | | QStringList | Array<string> | | QByteArray | Uint8Array | | QMap | Object | | QUserType | Object | | QDateTime | Date | | QChar | string | | QInvalid | undefined |
64-bit integers are read as
bigintand may be written asbigintornumber.
QUserType
QUserType covers Qt's user-defined types (QVariant::UserType). Register a
parser/serializer for each type by name before use.
import { types } from 'qtdatastream-web';
const { QUserType, Types } = types;
// Simple usertype backed by a single Qt type
QUserType.register('NetworkId', Types.INT);
// Structured usertype (parsing order is preserved)
QUserType.register('BufferInfo', [
{ id: Types.INT },
{ network: Types.INT },
{ type: Types.SHORT },
{ name: Types.BYTEARRAY },
]);
// Usertypes may nest other usertypes by name (declare the referenced one first)
QUserType.register('BufferInfoContainer', [
{ id: Types.INT },
{ bufferInfo: 'BufferInfo' },
]);Writing a usertype value:
import { write, types } from 'qtdatastream-web';
const bytes = write({
BufferInfo: new types.QUserType('BufferInfo', {
id: 2,
network: 4,
type: 5,
name: 'BufferInfo name',
}),
});Decorators
Classes can declare their serialization shape with decorators. These use the
legacy decorator syntax, so enable experimentalDecorators in your
tsconfig.json (or the equivalent Babel plugin).
import { types, Serializable, serialize } from 'qtdatastream-web';
const { QString, QUInt, Types, QUserType } = types;
QUserType.register('Network::Server', Types.MAP);
@Serializable('Network::Server')
class Server {
@serialize(QString, { in: 'HostIn', out: 'HostOut' })
host?: string;
@serialize(QUInt, 'Port')
port = 6667;
@serialize(QUInt)
sslVersion = 0;
constructor(args: Partial<Server>) {
Object.assign(this, args);
}
}Serializable's argument (the usertype name) is optional; without it, instances
export as a QMap. If a serializable class implements _export(), its return
value is serialized instead of the instance's own attributes.
Development
yarn install
yarn build # compile to dist/
yarn typecheck # type-check without emitting
yarn test # run the test suite (Vitest)
yarn test:watch # run Vitest in watch modeCredits
This project is based on the original node-qtdatastream by Joël Charles, whose work defines the QDataStream encoding implemented here.
License
MIT.
