项目作者: discord

项目描述 :
High Performance Erlang Term Format Packer
高级语言: Python
项目地址: git://github.com/discord/erlpack.git
创建时间: 2015-12-16T02:03:44Z
项目社区:https://github.com/discord/erlpack

开源协议:Other

下载


Erlpack

Erlpack is a fast encoder and decoder for the Erlang Term Format (version 131) for Python and JavaScript.

JavaScript

Things that can be packed:

  • [X] Null
  • [X] Booleans
  • [X] Strings
  • Atoms
  • [X] Unicode Strings
  • [X] Floats
  • [X] Integers
  • Longs
  • Longs over 64 bits
  • [X] Objects
  • [X] Arrays
  • Tuples
  • PIDs
  • Ports
  • Exports
  • References

How to pack:

  1. let erlpack = require("erlpack");
  2. packed = erlpack.pack({'a': true, 'list': ['of', 3, 'things', 'to', 'pack']});

How to unpack:

Note: Unpacking requires the binary data be a Uint8Array or Buffer. For those using electron/libchromium see the gotcha below.

  1. let erlpack = require("erlpack");
  2. let unpacked = null;
  3. let packed = new Buffer('', 'binary');
  4. try {
  5. unpacked = erlpack.unpack(packed);
  6. }
  7. catch (e) {
  8. // got an exception parsing
  9. }

Libchromium / Electron Gotcha

Some versions of libchromium replace the native data type backing TypedArrays with a custom data type called
blink::WebArrayBuffer. To keep erlpack’ dependencies simple this data type is not supported directly. If you’re using
Electron / Libchromium you need to convert the blink::WebArrayBuffer into a node::Buffer before passing to erlpack. You will
need to add this code into your native package somewhere:

  1. v8::Local<v8::Value> ConvertToNodeBuffer(const v8::Local<v8::Object>& blinkArray)
  2. {
  3. if (node::Buffer::HasInstance(blinkArray)) {
  4. return blinkArray;
  5. }
  6. else if (blinkArray->IsArrayBufferView()) {
  7. auto byteArray = v8::ArrayBufferView::Cast(*blinkArray);
  8. return node::Buffer::Copy(v8::Isolate::GetCurrent(), (const char*)byteArray->Buffer()->GetContents().Data(), byteArray->ByteLength()).ToLocalChecked();
  9. }
  10. return v8::Local<v8::Primitive>(v8::Null(v8::Isolate::GetCurrent()));
  11. }

Then in JavaScript something like:

  1. let packed = NativeUtils.convertToNodeBuffer(new Uint8Array(binaryPayload));
  2. // unpack now using erlpack.unpack(packed)

Python

Things that can be packed:

  • [X] None
  • [X] Booleans
  • [X] Strings
  • [X] Atoms
  • [X] Unicode Strings
  • [X] Floats
  • [X] Integers
  • [X] Longs
  • Longs over 64 bits
  • [X] Dictionaries
  • [X] Lists
  • [X] Tuples
  • [X] User Types (via an encode hook)
  • PIDs
  • Ports
  • Exports
  • References

How to pack:

  1. from erlpack import pack
  2. packed = pack(["thing", "to", "pack"])

How to unpack:

  1. from erlpack import unpack
  2. unpacked = unpack(packed)

How to pack an atom:

  1. from erlpack import Atom, pack
  2. packed = pack(Atom('hello'))

How to use an encode hook.

  1. from erlpack import ErlangTermEncoder
  2. def encode_hook(obj):
  3. if isinstance(obj, datetime.datetime):
  4. return obj.isoformat()
  5. encoder = ErlangTermEncoder(encode_hook=encode_hook)
  6. packed = encoder.pack(datetime.datetime(2015, 12, 25, 12, 23, 55))

How to make custom types packable.

  1. from erlpack import pack, Atom
  2. class User(object):
  3. def __init__(self, name, age):
  4. self.name = name
  5. self.age = age
  6. def __erlpack__(self):
  7. return {
  8. Atom('name'): self.name,
  9. Atom('age'): self.age
  10. }
  11. u = User(name='Jake', age=23)
  12. packed = pack(u)

Go (golang)

Discord has moved away from Go internally and so we do not maintain a version of erlpack in Go ourselves. However, all is
not lost!, please check out: https://github.com/JakeMakesStuff/go-erlpack

Building

Python

Generating the new .cpp files can be accomplished by running python setup.py --use-cython build_ext --inplace.

cython must be installed for this to work.

Testing

  1. Install the development version of erlpack with python setup.py develop.
  2. Install pytest.
  3. Execute pytest py/tests.