PSON decoder example using namespaced imports

This commit is contained in:
dcodeIO
2017-12-30 05:11:58 +01:00
parent c67f87a988
commit 2888ba14ad
41 changed files with 1283 additions and 336 deletions

19
examples/pson/README.md Normal file
View File

@ -0,0 +1,19 @@
PSON decoder in WebAssembly
===========================
An [AssemblyScript](http://assemblyscript.org) example. Decodes a [PSON](https://github.com/dcodeIO/PSON) encoded buffer.
Instructions
------------
To build [assembly/pson.ts](./assembly/pson.ts) to an untouched and an optimized `.wasm` including their respective `.wast` representations, run:
```
$> npm run build
```
Afterwards, to run the included test, do:
```
$> npm test
```

View File

@ -0,0 +1,156 @@
const enum Token {
ZERO = 0x00,
MAX = 0xEF,
NULL = 0xf0,
TRUE = 0xf1,
FALSE = 0xf2,
EOBJECT = 0xf3,
EARRAY = 0xf4,
ESTRING = 0xf5,
OBJECT = 0xf6,
ARRAY = 0xf7,
INTEGER = 0xf8,
LONG = 0xf9,
FLOAT = 0xfa,
DOUBLE = 0xfb,
STRING = 0xfc,
STRING_ADD = 0xfd,
STRING_GET = 0xfe,
BINARY = 0xff
}
namespace pson {
export declare function onNull(): void;
export declare function onTrue(): void;
export declare function onFalse(): void;
export declare function onEObject(): void;
export declare function onEArray(): void;
export declare function onEString(): void;
export declare function onObject(size: u32): void;
export declare function onArray(size: u32): void;
export declare function onInteger(value: i32): void;
export declare function onLong(valueLow: i32, valueHigh: i32): void;
export declare function onFloat(value: f32): void;
export declare function onDouble(value: f64): void;
export declare function onString(offset: usize, length: u32): void;
export declare function onBinary(offset: usize, length: u32): void;
export declare function onTruncated(): void;
}
var offset: usize = 0;
export function decode(length: usize): void {
offset = 0;
while (offset < length)
decodeValue();
if (offset != length)
pson.onTruncated();
}
function decodeValue(): void {
var token: u32 = load<u8>(offset++);
var size: u32;
var long: u64;
switch (token) {
case Token.NULL:
pson.onNull();
break;
case Token.TRUE:
pson.onTrue();
break;
case Token.FALSE:
pson.onFalse();
break;
case Token.EOBJECT:
pson.onEObject();
break;
case Token.EARRAY:
pson.onEArray();
break;
case Token.ESTRING:
pson.onEString();
break;
case Token.OBJECT:
pson.onObject(size = readVarint32());
while (size--) {
decodeValue();
decodeValue();
}
break;
case Token.ARRAY:
pson.onArray(size = readVarint32());
while (size--)
decodeValue();
break;
case Token.INTEGER:
pson.onInteger(((size = readVarint32()) >> 1) ^ -(size & 1));
break;
case Token.LONG:
long = ((long = readVarint64()) >> 1) ^ -(long & 1);
pson.onLong(<i32>long, <i32>(long >>> 32));
break;
case Token.FLOAT:
pson.onFloat(load<f32>(offset));
offset += 4;
break;
case Token.DOUBLE:
pson.onDouble(load<f64>(offset));
offset += 8;
break;
case Token.STRING:
size = readVarint32();
pson.onString(offset, size);
offset += size;
break;
case Token.STRING_ADD:
case Token.STRING_GET:
// could be implemented via imports as well, but isn't necessary for this example
throw new Error("not implemented");
case Token.BINARY:
size = readVarint32();
pson.onBinary(offset, size);
offset += size;
break;
default: // small integer?
if (token > Token.MAX)
throw new Error("unexpected token");
pson.onInteger((token >> 1) ^ -(token & 1));
break;
}
}
function readVarint32(): u32 {
var value: u32 = 0;
var shift: u32 = 0;
do {
var b = load<u8>(offset++);
value |= <u32>(b & 0x7f) << (7 * shift++);
} while (b & 0x80);
return value;
}
function readVarint64(): u64 {
var value: u64 = 0;
var shift: u64 = 0;
do {
var b = load<u8>(offset++);
value |= <u64>(b & 0x7f) << (7 * shift++);
} while (b & 0x80);
return value;
}

View File

@ -0,0 +1,6 @@
{
"extends": "../../../std/assembly.json",
"include": [
"./**/*.ts"
]
}

71
examples/pson/index.js Normal file
View File

@ -0,0 +1,71 @@
var fs = require("fs");
// Define imports. Just logs to console for the sake of this example.
var pson = {
onNull: function() {
console.log("null");
},
onTrue: function() {
console.log("true");
},
onFalse: function() {
console.log("false");
},
onEObject: function() {
console.log("{}");
},
onEArray: function() {
console.log("[]");
},
onEString: function() {
console.log("\"\"");
},
onObject: function(size) {
console.log("{" + size + "}")
},
onArray: function(size) {
console.log("[" + size + "]");
},
onInteger: function(value) {
console.log("integer: " + value);
},
onLong: function(valueLow, valueHigh) {
console.log("long: " + valueLow + ", " + valueHigh);
},
onFloat: function(value) {
console.log("float: " + value);
},
onDouble: function(value) {
console.log("double: " + value);
},
onString: function(offset, length) {
console.log("string(length=" + length + "): " + new Buffer(mem.slice(offset, offset + length)).toString());
},
onBinary: function(offset, length) {
console.log("binary(length=" + length + "): " + mem.slice(offset, offset + length));
},
onTruncated: function() {
console.log("buffer is truncated :-(");
}
};
// Instantiate the module
var mod = new WebAssembly.Module(fs.readFileSync(__dirname + "/pson.optimized.wasm"));
var ins = new WebAssembly.Instance(mod, { pson: pson });
var mem = new Uint8Array(ins.exports.memory.buffer);
// Export API
exports.decode = function(buffer) {
// grow memory if necessary
if (mem.length < buffer.length) {
ins.exports.memory.grow(Math.ceil((buffer.length - mem.length) / 65536));
mem = new Uint8Array(ins.exports.memory.buffer);
}
// copy buffer to memory
mem.set(buffer);
// start decoding (calls the imports defined above)
ins.exports.decode(buffer.length);
}

View File

@ -0,0 +1,14 @@
{
"name": "@assemblyscript/pson-example",
"version": "1.0.0",
"private": true,
"scripts": {
"build": "npm run build:untouched && npm run build:optimized",
"build:untouched": "asc assembly/pson.ts -b pson.untouched.wasm -t pson.untouched.wast --validate",
"build:optimized": "asc -O assembly/pson.ts -b pson.optimized.wasm -t pson.optimized.wast --validate",
"test": "node tests"
},
"devDependencies": {
"pson": "^2.0.0"
}
}

View File

@ -0,0 +1,24 @@
var Long = require("long");
var psonJS = require("pson");
var psonWASM = require("..");
// encode in JS
var buf = new psonJS.Encoder().encode({
emptyObject: {},
emptyArray: [],
emptyString: "",
object: {
aSmallInt: 42,
anInt: 9000,
aLong: Long.MIN_VALUE.add(1)
},
array: [
0.25, // fits into float
0.1 // always a double
],
binary: Buffer.from([1, 2, 3])
}).toBuffer();
// decode in WASM
psonWASM.decode(buf);