Comparing version 2.1.0 to 2.2.0
{ | ||
"name": "compactr", | ||
"version": "2.1.0", | ||
"version": "2.2.0", | ||
"description": "Schema based serialization made easy", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -15,3 +15,3 @@ <h1 align="center"> | ||
[![Compactr](https://img.shields.io/npm/v/compactr.svg)](https://www.npmjs.com/package/compactr) | ||
[![Node](https://img.shields.io/badge/node->%3D4.0-blue.svg)](https://nodejs.org) | ||
[![Node](https://img.shields.io/badge/node->%3D6.0-blue.svg)](https://nodejs.org) | ||
[![Build Status](https://travis-ci.org/compactr/compactr.js.svg?branch=master)](https://travis-ci.org/compactr/compactr.js) | ||
@@ -24,5 +24,7 @@ [![Gitter](https://img.shields.io/gitter/room/compactr/compactr.svg)](https://gitter.im/compactr/compactr) | ||
Protocol Buffers are awesome. Having schemas to deflate and inflate data while maintaining some kind of validation is a great concept. Compactr's goal is to build on that to better suit Node development and reduce repetition by allowing you to build schemas for your data directly in your scripting language. For example, if you have a DB schema for a model, you could use that directly as a schema for Compactr. | ||
Protocol Buffers are awesome. Having schemas to deflate and inflate data while maintaining some kind of validation is a great concept. Compactr's goal is to build on that to better suit the Javascript ecosystem. | ||
[More](docs/ABOUT.md) | ||
## Install | ||
@@ -52,9 +54,9 @@ | ||
// Get the schema header bytes (for partial loads) | ||
// Get the header bytes | ||
const header = userSchema.headerBytes(); | ||
// Get the partial load bytes | ||
// Get the content bytes | ||
const partial = userSchema.contentBytes(); | ||
// Get the full header + content bytes | ||
// Get the full payload (header + content bytes) | ||
const buffer = userSchema.bytes(); | ||
@@ -65,6 +67,6 @@ | ||
// Decoding (full) | ||
// Decoding a full payload | ||
const content = userSchema.read(buffer); | ||
// Decoding (partial) | ||
// Decoding a partial payload (content) | ||
const content = userSchema.readContent(partial); | ||
@@ -74,27 +76,14 @@ ``` | ||
## Performances | ||
## Speed comparison | ||
``` | ||
[Array] JSON x 188 ops/sec ±2.47% (73 runs sampled) | ||
[Array] Compactr x 248 ops/sec ±3.16% (72 runs sampled) | ||
![Speed](http://res.cloudinary.com/kalm/image/upload/v1507323565/compactr_speed_adhlsk.png) | ||
[Boolean] JSON x 220 ops/sec ±5.04% (71 runs sampled) | ||
[Boolean] Compactr x 731 ops/sec ±7.57% (74 runs sampled) | ||
*Measured against plain JSON serialization + convertion to buffer. Compactr serialization is performed with default settings via the partial (content only) load method* | ||
[Float] JSON x 159 ops/sec ±3.41% (70 runs sampled) | ||
[Float] Compactr x 476 ops/sec ±1.58% (85 runs sampled) | ||
[Integer] JSON x 264 ops/sec ±1.79% (79 runs sampled) | ||
[Integer] Compactr x 885 ops/sec ±1.36% (84 runs sampled) | ||
[Object] JSON x 139 ops/sec ±1.89% (76 runs sampled) | ||
[Object] Compactr x 169 ops/sec ±1.52% (80 runs sampled) | ||
## Size comparison | ||
[String] JSON x 107 ops/sec ±6.86% (64 runs sampled) | ||
[String] Compactr x 167 ops/sec ±4.86% (72 runs sampled) | ||
``` | ||
![Size](http://res.cloudinary.com/kalm/image/upload/v1507323565/compactr_bytes_cbjxka.png) | ||
## Size comparison | ||
JSON: `{"id":123,"name":"John"}`: 24 bytes | ||
@@ -101,0 +90,0 @@ |
@@ -31,6 +31,6 @@ /** Decoding utilities */ | ||
function string(encoding, bytes) { | ||
function string(bytes) { | ||
let res = []; | ||
for (let i = 0; i < bytes.length; i += encoding) { | ||
res.push(unsigned(bytes.slice(i, i + encoding))); | ||
for (let i = 0; i < bytes.length; i += 2) { | ||
res.push(unsigned(bytes.subarray(i, i + 2))); | ||
} | ||
@@ -40,8 +40,24 @@ return fromChar.apply(null, res); | ||
function char8(bytes) { | ||
let res = []; | ||
for (let i = 0; i < bytes.length; i += 1) { | ||
res.push(unsigned(bytes.subarray(i, i + 1))); | ||
} | ||
return fromChar.apply(null, res); | ||
} | ||
function char32(bytes) { | ||
let res = []; | ||
for (let i = 0; i < bytes.length; i += 4) { | ||
res.push(unsigned(bytes.subarray(i, i + 4))); | ||
} | ||
return fromChar.apply(null, res); | ||
} | ||
function array(schema, bytes) { | ||
const ret = []; | ||
for (let i = 0; i < bytes.length;) { | ||
const size = unsigned(bytes.slice(i, i + schema.count)); | ||
const size = unsigned(bytes.subarray(i, i + schema.count)); | ||
i = (i + schema.count); | ||
ret.push(schema.transformOut(bytes.slice(i, i + size))); | ||
ret.push(schema.transformOut(bytes.subarray(i, i + size))); | ||
i = (i + size); | ||
@@ -86,6 +102,6 @@ } | ||
double, | ||
string: string.bind(null, 2), | ||
char8: string.bind(null, 1), | ||
char16: string.bind(null, 2), | ||
char32: string.bind(null, 4), | ||
string, | ||
char8, | ||
char16: string, | ||
char32, | ||
array, | ||
@@ -92,0 +108,0 @@ object, |
@@ -16,2 +16,3 @@ /** Encoding utilities */ | ||
const eOut = pow(2, 1022) * bias; | ||
const fastPush = Array.prototype.push; | ||
@@ -45,3 +46,3 @@ /* Methods -------------------------------------------------------------------*/ | ||
for (let i = 0; i < val.length; i++) { | ||
chars.push.apply(chars, encoding(val.charCodeAt(i))); | ||
fastPush.apply(chars, encoding(val.charCodeAt(i))); | ||
} | ||
@@ -56,4 +57,4 @@ | ||
let encoded = schema.transformIn(val[i]); | ||
ret.push.apply(ret, schema.getSize(encoded.length)); | ||
ret.push.apply(ret, encoded); | ||
fastPush.apply(ret, schema.getSize(encoded.length)); | ||
fastPush.apply(ret, encoded); | ||
} | ||
@@ -64,3 +65,3 @@ return ret; | ||
function object(schema, val) { | ||
return schema.write(val).array(); | ||
return schema.write(val).buffer(); | ||
} | ||
@@ -67,0 +68,0 @@ |
@@ -23,3 +23,3 @@ /** Data reader component */ | ||
for (let i = 0; i < keys; i++) { | ||
caret = readKey(bytes, caret); | ||
caret = readKey(bytes, caret, i); | ||
} | ||
@@ -31,9 +31,9 @@ scope.contentBegins = caret; | ||
function readKey(bytes, caret) { | ||
function readKey(bytes, caret, index) { | ||
const key = getSchemaDef(bytes[caret]); | ||
scope.header.push({ | ||
scope.header[index] = { | ||
key, | ||
size: key.size || Decoder.unsigned(bytes.slice(caret + 1, caret + key.count + 1)) | ||
}); | ||
size: key.size || Decoder.unsigned(bytes.subarray(caret + 1, caret + key.count + 1)) | ||
}; | ||
return caret + key.count + 1; | ||
@@ -51,4 +51,9 @@ } | ||
const ret = {}; | ||
if (scope.options.keyOrder === true) { | ||
for (let i = 0; i < scope.items.length; i++) { | ||
ret[scope.items[i]] = undefined; | ||
} | ||
} | ||
for (let i = 0; i < scope.header.length; i++) { | ||
ret[scope.header[i].key.name] = scope.header[i].key.transformOut(bytes.slice(caret, caret + scope.header[i].size)); | ||
ret[scope.header[i].key.name] = scope.header[i].key.transformOut(bytes.subarray(caret, caret + scope.header[i].size)); | ||
caret += scope.header[i].size; | ||
@@ -55,0 +60,0 @@ } |
@@ -15,3 +15,3 @@ /** Schema parsing component */ | ||
function Schema(schema) { | ||
function Schema(schema, options = { keyOrder: false }) { | ||
const sizeRef = { | ||
@@ -40,6 +40,7 @@ boolean: 1, | ||
items: Object.keys(schema), | ||
headerBytes: [], | ||
contentBytes: [], | ||
headerBytes: [0], | ||
contentBytes: [0], | ||
header: [], | ||
contentBegins: 0 | ||
contentBegins: 0, | ||
options | ||
}; | ||
@@ -46,0 +47,0 @@ scope.indices = preformat(schema); |
@@ -5,2 +5,6 @@ /** Data writer component */ | ||
/* Local variables -----------------------------------------------------------*/ | ||
const fastPush = Array.prototype.push; | ||
/* Methods -------------------------------------------------------------------*/ | ||
@@ -11,3 +15,4 @@ | ||
function write(data, options) { | ||
clear(); | ||
scope.headerBytes = [0]; | ||
scope.contentBytes = []; | ||
@@ -34,11 +39,18 @@ const keys = filterKeys(data); | ||
scope.headerBytes.push(scope.indices[key].index); | ||
scope.headerBytes.push.apply(scope.headerBytes, scope.indices[key].getSize(encoded.length)); | ||
scope.contentBytes.push.apply(scope.contentBytes, encoded); | ||
fastPush.apply(scope.headerBytes, scope.indices[key].getSize(encoded.length)); | ||
let res = encoded; | ||
if (scope.indices[key].size !== null) { | ||
if (scope.indices[key].size !== encoded.length) { | ||
if(scope.indices[key].size > encoded.length) { | ||
res = new Array(scope.indices[key].size).fill(0); | ||
res.splice(0, encoded.length, ...encoded); | ||
} | ||
else { | ||
res = encoded.slice(0, scope.indices[key].size); | ||
} | ||
} | ||
} | ||
fastPush.apply(scope.contentBytes, res); | ||
} | ||
function clear() { | ||
scope.headerBytes = [0]; | ||
scope.contentBytes = []; | ||
} | ||
function sizes(data) { | ||
@@ -66,5 +78,6 @@ const s = {}; | ||
function concat(header, content) { | ||
// return [...header, ...content]; | ||
const res = []; | ||
res.push.apply(res, header); | ||
res.push.apply(res, content); | ||
fastPush.apply(res, header); | ||
fastPush.apply(res, content); | ||
return res; | ||
@@ -85,15 +98,3 @@ } | ||
function headerArray() { | ||
return scope.headerBytes; | ||
} | ||
function contentArray() { | ||
return scope.contentBytes; | ||
} | ||
function array() { | ||
return concat(scope.headerBytes, scope.contentBytes); | ||
} | ||
return { write, headerBuffer, headerArray, contentBuffer, contentArray, buffer, array, sizes }; | ||
return { write, headerBuffer, contentBuffer, buffer, sizes }; | ||
} | ||
@@ -100,0 +101,0 @@ |
7249812
14
486
104