blob: 061d2bdfe4b7ed7cd619c24d011e2e840baccb0c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
/*****************************************************************************/
/* */
/* Data */
/* */
/*****************************************************************************/
/**
* Constructs a proton.Data instance.
* @classdesc
* The Data class provides an interface for decoding, extracting, creating, and
* encoding arbitrary AMQP data. A Data object contains a tree of AMQP values.
* Leaf nodes in this tree correspond to scalars in the AMQP type system such as
* ints<INT> or strings<STRING>. Non-leaf nodes in this tree correspond to compound
* values in the AMQP type system such as lists<LIST>, maps<MAP>, arrays<ARRAY>,
* or described values<DESCRIBED>. The root node of the tree is the Data object
* itself and can have an arbitrary number of children.
* <p>
* A Data object maintains the notion of the current sibling node and a current
* parent node. Siblings are ordered within their parent. Values are accessed
* and/or added by using the next, prev, enter, and exit methods to navigate to
* the desired location in the tree and using the supplied variety of put* and
* get* methods to access or add a value of the desired type.
* <p>
* The put* methods will always add a value after the current node in the tree.
* If the current node has a next sibling the put* method will overwrite the value
* on this node. If there is no current node or the current node has no next
* sibling then one will be added. The put* methods always set the added/modified
* node to the current node. The get* methods read the value of the current node
* and do not change which node is current.
* @constructor proton.Data
* @param {number} data an optional pointer to a pn_data_t instance. If supplied
* the underlying data is "owned" by another object (for example a Message)
* and that object is assumed to be responsible for freeing the data if
* necessary. If no data is supplied then the Data is stand-alone and the
* client application is responsible for freeing the underlying data via
* a call to free().
* @param {boolean} decodeBinaryAsString if set decode any AMQP Binary payload
* objects as strings. This can be useful as the data in Binary objects
* will be overwritten with subsequent calls to get, so they must be
* explicitly copied. Needless to say it is only safe to set this flag if
* you know that the data you are dealing with is actually a string, for
* example C/C++ applications often seem to encode strings as AMQP binary,
* a common cause of interoperability problems.
*/
Module['Data'] = function(data, decodeBinaryAsString) { // Data Constructor.
if (!data) {
this._data = _pn_data(16); // Default capacity is 16
this['free'] = function() {
_pn_data_free(this._data);
// Set free to a null function to prevent possibility of a "double free".
this['free'] = function() {};
};
} else {
this._data = data;
this['free'] = function() {};
}
this._decodeBinaryAsString = decodeBinaryAsString;
};
// Expose constructor as package scope variable to make internal calls less verbose.
var Data = Module['Data'];
// Expose prototype as a variable to make method declarations less verbose.
var _Data_ = Data.prototype;
// ************************** Class properties ********************************
Data['NULL'] = 1;
Data['BOOL'] = 2;
Data['UBYTE'] = 3;
Data['BYTE'] = 4;
Data['USHORT'] = 5;
Data['SHORT'] = 6;
Data['UINT'] = 7;
Data['INT'] = 8;
Data['CHAR'] = 9;
Data['ULONG'] = 10;
Data['LONG'] = 11;
Data['TIMESTAMP'] = 12;
Data['FLOAT'] = 13;
Data['DOUBLE'] = 14;
Data['DECIMAL32'] = 15;
Data['DECIMAL64'] = 16;
Data['DECIMAL128'] = 17;
Data['UUID'] = 18;
Data['BINARY'] = 19;
Data['STRING'] = 20;
Data['SYMBOL'] = 21;
Data['DESCRIBED'] = 22;
Data['ARRAY'] = 23;
Data['LIST'] = 24;
Data['MAP'] = 25;
/**
* Look-up table mapping proton-c types to the accessor method used to
* deserialise the type. N.B. this is a simple Array and not a map because the
* types that we get back from pn_data_type are integers from the pn_type_t enum.
* @property {Array<String>} TypeNames ['NULL', 'NULL', 'BOOL', 'UBYTE', 'BYTE',
* 'USHORT', 'SHORT', 'UINT', 'INT', 'CHAR', 'ULONG', 'LONG', 'TIMESTAMP',
* 'FLOAT', 'DOUBLE', 'DECIMAL32', 'DECIMAL64', 'DECIMAL128', 'UUID',
* 'BINARY', 'STRING', 'SYMBOL', 'DESCRIBED', 'ARRAY', 'LIST', 'MAP']
* @memberof! proton.Data
*/
Data['TypeNames'] = [
'NULL', // 0
'NULL', // PN_NULL = 1
'BOOL', // PN_BOOL = 2
'UBYTE', // PN_UBYTE = 3
'BYTE', // PN_BYTE = 4
'USHORT', // PN_USHORT = 5
'SHORT', // PN_SHORT = 6
'UINT', // PN_UINT = 7
'INT', // PN_INT = 8
'CHAR', // PN_CHAR = 9
'ULONG', // PN_ULONG = 10
'LONG', // PN_LONG = 11
'TIMESTAMP', // PN_TIMESTAMP = 12
'FLOAT', // PN_FLOAT = 13
'DOUBLE', // PN_DOUBLE = 14
'DECIMAL32', // PN_DECIMAL32 = 15
'DECIMAL64', // PN_DECIMAL64 = 16
'DECIMAL128', // PN_DECIMAL128 = 17
'UUID', // PN_UUID = 18
'BINARY', // PN_BINARY = 19
'STRING', // PN_STRING = 20
'SYMBOL', // PN_SYMBOL = 21
'DESCRIBED', // PN_DESCRIBED = 22
'ARRAY', // PN_ARRAY = 23
'LIST', // PN_LIST = 24
'MAP' // PN_MAP = 25
];
// *************************** Class methods **********************************
/**
* Test if a given Object is a JavaScript Array.
* @method isArray
* @memberof! proton.Data
* @param {object} o the Object that we wish to test.
* @returns {boolean} true iff the Object is a JavaScript Array.
*/
Data.isArray = Array.isArray || function(o) {
return Object.prototype.toString.call(o) === '[object Array]';
};
/**
* Test if a given Object is a JavaScript Number.
* @method isNumber
* @memberof! proton.Data
* @param {object} o the Object that we wish to test.
* @returns {boolean} true iff the Object is a JavaScript Number.
*/
Data.isNumber = function(o) {
return typeof o === 'number' ||
(typeof o === 'object' && Object.prototype.toString.call(o) === '[object Number]');
};
/**
* Test if a given Object is a JavaScript String.
* @method isString
* @memberof! proton.Data
* @param {object} o the Object that we wish to test.
* @returns {boolean} true iff the Object is a JavaScript String.
*/
Data.isString = function(o) {
return typeof o === 'string' ||
(typeof o === 'object' && Object.prototype.toString.call(o) === '[object String]');
};
/**
* Test if a given Object is a JavaScript Boolean.
* @method isBoolean
* @memberof! proton.Data
* @param {object} o the Object that we wish to test.
* @returns {boolean} true iff the Object is a JavaScript Boolean.
*/
Data.isBoolean = function(o) {
return typeof o === 'boolean' ||
(typeof o === 'object' && Object.prototype.toString.call(o) === '[object Boolean]');
};
// ************************* Protected methods ********************************
// We use the dot notation rather than associative array form for protected
// methods so they are visible to this "package", but the Closure compiler will
// minify and obfuscate names, effectively making a defacto "protected" method.
/**
* This helper method checks the supplied error code, converts it into an
* exception and throws the exception. This method will try to use the message
* populated in pn_data_error(), if present, but if not it will fall
* back to using the basic error code rendering from pn_code().
* @param code the error code to check.
*/
_Data_._check = function(code) {
if (code < 0) {
var errno = this['getErrno']();
var message = errno ? this['getError']() : Pointer_stringify(_pn_code(code));
throw new Module['DataError'](message);
} else {
return code;
}
};
// *************************** Public methods *********************************
/**
* @method getErrno
* @memberof! proton.Data#
* @returns {number} the most recent error message code.
*/
_Data_['getErrno'] = function() {
return _pn_data_errno(this._data);
};
/**
* @method getError
* @memberof! proton.Data#
* @returns {string} the most recent error message as a String.
*/
_Data_['getError'] = function() {
return Pointer_stringify(_pn_error_text(_pn_data_error(this._data)));
};
/**
* Clears the data object.
* @method clear
* @memberof! proton.Data#
*/
_Data_['clear'] = function() {
_pn_data_clear(this._data);
};
/**
* Clears current node and sets the parent to the root node. Clearing the current
* node sets it _before_ the first node, calling next() will advance to the first node.
* @method rewind
* @memberof! proton.Data#
*/
_Data_['rewind'] = function() {
_pn_data_rewind(this._data);
};
/**
* Advances the current node to its next sibling and returns its type. If there
* is no next sibling the current node remains unchanged and null is returned.
* @method next
* @memberof! proton.Data#
* @returns {number} the type of the next sibling or null.
*/
_Data_['next'] = function() {
var found = _pn_data_next(this._data);
if (found) {
return this.type();
} else {
return null;
}
};
/**
* Advances the current node to its previous sibling and returns its type. If there
* is no previous sibling the current node remains unchanged and null is returned.
* @method prev
* @memberof! proton.Data#
* @returns {number} the type of the previous sibling or null.
*/
_Data_['prev'] = function() {
var found = _pn_data_prev(this._data);
if (found) {
return this.type();
} else {
return null;
}
};
/**
* Sets the parent node to the current node and clears the current node. Clearing
* the current node sets it _before_ the first child, next() advances to the first child.
* @method enter
* @memberof! proton.Data#
*/
_Data_['enter'] = function() {
return (_pn_data_enter(this._data) > 0);
};
/**
* Sets the current node to the parent node and the parent node to its own parent.
* @method exit
* @memberof! proton.Data#
*/
_Data_['exit'] = function() {
return (_pn_data_exit(this._data) > 0);
};
/**
* Look up a value by name. N.B. Need to use getObject() to retrieve the actual
* value after lookup suceeds.
* @method lookup
* @memberof! proton.Data#
* @param {string} name the name of the property to look up.
* @returns {boolean} true iff the lookup succeeded.
*/
_Data_['lookup'] = function(name) {
var sp = Runtime.stackSave();
var lookup = _pn_data_lookup(this._data, allocate(intArrayFromString(name), 'i8', ALLOC_STACK));
Runtime.stackRestore(sp);
return (lookup > 0);
};
// TODO document - not quite sure what these are for?
_Data_['narrow'] = function() {
_pn_data_narrow(this._data);
};
_Data_['widen'] = function() {
_pn_data_widen(this._data);
};
/**
* @method type
* @memberof! proton.Data#
* @returns {number} the type of the current node or null if the type is unknown.
*/
_Data_['type'] = function() {
var dtype = _pn_data_type(this._data);
if (dtype === -1) {
return null;
} else {
return dtype;
}
};
/**
* Return a Binary representation of the data encoded in AMQP format. N.B. the
* returned {@link proton.Data.Binary} "owns" the underlying raw data and is thus
* responsible for freeing it or passing it to a method that consumes a Binary
* such as {@link proton.Data.decode} or {@link proton.Data.putBINARY}.
* @method encode
* @memberof! proton.Data#
* @returns {proton.Data.Binary} a representation of the data encoded in AMQP format.
*/
_Data_['encode'] = function() {
var size = 1024;
while (true) {
var bytes = _malloc(size); // Allocate storage from emscripten heap.
var cd = _pn_data_encode(this._data, bytes, size);
if (cd === Module['Error']['OVERFLOW']) {
_free(bytes);
size *= 2;
} else if (cd >= 0) {
return new Data['Binary'](cd, bytes);
} else {
_free(bytes);
this._check(cd);
return;
}
}
};
/**
* Decodes the first value from supplied Binary AMQP data and returns a new
* {@link proton.Data.Binary} containing the remainder of the data or null if
* all the supplied data has been consumed. N.B. this method "consumes" data
* from a {@link proton.Data.Binary} in other words it takes responsibility for
* the underlying data and frees the raw data from the Binary.
* @method decode
* @memberof! proton.Data#
* @param {proton.Data.Binary} encoded the AMQP encoded binary data.
* @returns {proton.Data.Binary} a Binary containing the remaining bytes or null
* if all the data has been consumed.
*/
_Data_['decode'] = function(encoded) {
var start = encoded.start;
var size = encoded.size;
var consumed = this._check(_pn_data_decode(this._data, start, size));
size = size - consumed;
start = _malloc(size); // Allocate storage from emscripten heap.
_memcpy(start, encoded.start + consumed, size);
encoded['free'](); // Free the original Binary.
return size > 0 ? new Data['Binary'](size, start) : null;
};
/**
* Puts a list node. Elements may be filled by entering the list
* node and putting element values.
* <pre>
* var data = new proton.Data();
* data.putLISTNODE();
* data.enter();
* data.putINT(1);
* data.putINT(2);
* data.putINT(3);
* data.exit();
* </pre>
* @method putLISTNODE
* @memberof! proton.Data#
*/
_Data_['putLISTNODE'] = function() {
this._check(_pn_data_put_list(this._data));
};
/**
* Puts a map node. Elements may be filled by entering the map node
* and putting alternating key value pairs.
* <pre>
* var data = new proton.Data();
* data.putMAPNODE();
* data.enter();
* data.putSTRING('key');
* data.putSTRING('value');
* data.exit();
* </pre>
* @method putMAPNODE
* @memberof! proton.Data#
*/
_Data_['putMAPNODE'] = function() {
this._check(_pn_data_put_map(this._data));
};
/**
* Puts an array node. Elements may be filled by entering the array node and
* putting the element values. The values must all be of the specified array
* element type. If an array is described then the first child value of the array
* is the descriptor and may be of any type.
* <pre>
* var data = new proton.Data();
* data.putARRAYNODE(false, proton.Data.INT);
* data.enter();
* data.putINT(1);
* data.putINT(2);
* data.putINT(3);
* data.exit();
*
* data.putARRAYNODE(true, proton.Data.DOUBLE);
* data.enter();
* data.putSYMBOL('array-descriptor');
* data.putDOUBLE(1.1);
* data.putDOUBLE(1.2);
* data.putDOUBLE(1.3);
* data.exit();
* </pre>
* @method putARRAYNODE
* @param {boolean} described specifies whether the array is described.
* @param {number} type the type of the array elements.
* @memberof! proton.Data#
*/
_Data_['putARRAYNODE'] = function(described, type) {
this._check(_pn_data_put_array(this._data, described, type));
};
/**
* Puts a described node. A described node has two children, the descriptor and
* value. These are specified by entering the node and putting the desired values.
* <pre>
* var data = new proton.Data();
* data.putDESCRIBEDNODE();
* data.enter();
* data.putSYMBOL('value-descriptor');
* data.putSTRING('the value');
* data.exit();
* </pre>
* @method putDESCRIBEDNODE
* @memberof! proton.Data#
*/
_Data_['putDESCRIBEDNODE'] = function() {
this._check(_pn_data_put_described(this._data));
};
/**
* Puts a null value.
* @method putNULL
* @memberof! proton.Data#
*/
_Data_['putNULL'] = function() {
this._check(_pn_data_put_null(this._data));
};
/**
* Puts a boolean value.
* @method putBOOL
* @memberof! proton.Data#
* @param {boolean} b a boolean value.
*/
_Data_['putBOOL'] = function(b) {
this._check(_pn_data_put_bool(this._data, b));
};
/**
* Puts a unsigned byte value.
* @method putUBYTE
* @memberof! proton.Data#
* @param {number} ub an integral value.
*/
_Data_['putUBYTE'] = function(ub) {
this._check(_pn_data_put_ubyte(this._data, ub));
};
/**
* Puts a signed byte value.
* @method putBYTE
* @memberof! proton.Data#
* @param {number} b an integral value.
*/
_Data_['putBYTE'] = function(b) {
this._check(_pn_data_put_byte(this._data, b));
};
/**
* Puts a unsigned short value.
* @method putUSHORT
* @memberof! proton.Data#
* @param {number} us an integral value.
*/
_Data_['putUSHORT'] = function(us) {
this._check(_pn_data_put_ushort(this._data, us));
};
/**
* Puts a signed short value.
* @method putSHORT
* @memberof! proton.Data#
* @param {number} s an integral value.
*/
_Data_['putSHORT'] = function(s) {
this._check(_pn_data_put_short(this._data, s));
};
/**
* Puts a unsigned integer value.
* @method putUINT
* @memberof! proton.Data#
* @param {number} ui an integral value.
*/
_Data_['putUINT'] = function(ui) {
this._check(_pn_data_put_uint(this._data, ui));
};
/**
* Puts a signed integer value.
* @method putINT
* @memberof! proton.Data#
* @param {number} i an integral value.
*/
_Data_['putINT'] = function(i) {
this._check(_pn_data_put_int(this._data, i));
};
/**
* Puts a signed char value.
* @method putCHAR
* @memberof! proton.Data#
* @param {(string|number)} c a single character expressed either as a string or a number.
*/
_Data_['putCHAR'] = function(c) {
c = Data.isString(c) ? c.charCodeAt(0) : c;
this._check(_pn_data_put_char(this._data, c));
};
/**
* Puts a unsigned long value. N.B. large values can suffer from a loss of
* precision as JavaScript numbers are restricted to 64 bit double values.
* @method putULONG
* @memberof! proton.Data#
* @param {number} ul an integral value.
*/
_Data_['putULONG'] = function(ul) {
// If the supplied number exceeds the range of Data.Long invert it before
// constructing the Data.Long.
ul = (ul >= Data.Long.TWO_PWR_63_DBL_) ? (ul = -(Data.Long.TWO_PWR_64_DBL_ - ul)) : ul;
var long = Data.Long.fromNumber(ul);
this._check(_pn_data_put_ulong(this._data, long.getLowBitsUnsigned(), long.getHighBits()));
};
/**
* Puts a signed long value. N.B. large values can suffer from a loss of
* precision as JavaScript numbers are restricted to 64 bit double values.
* @method putLONG
* @memberof! proton.Data#
* @param {number} i an integral value.
*/
_Data_['putLONG'] = function(l) {
var long = Data.Long.fromNumber(l);
this._check(_pn_data_put_long(this._data, long.getLowBitsUnsigned(), long.getHighBits()));
};
/**
* Puts a timestamp.
* @method putTIMESTAMP
* @memberof! proton.Data#
* @param {(number|Date)} d a Date value.
*/
_Data_['putTIMESTAMP'] = function(d) {
// Note that a timestamp is a 64 bit number so we have to use a proton.Data.Long.
var timestamp = Data.Long.fromNumber(d.valueOf());
this._check(_pn_data_put_timestamp(this._data, timestamp.getLowBitsUnsigned(), timestamp.getHighBits()));
};
/**
* Puts a float value. N.B. converting between floats and doubles is imprecise
* so the resulting value might not quite be what you expect.
* @method putFLOAT
* @memberof! proton.Data#
* @param {number} f a floating point value.
*/
_Data_['putFLOAT'] = function(f) {
this._check(_pn_data_put_float(this._data, f));
};
/**
* Puts a double value.
* @method putDOUBLE
* @memberof! proton.Data#
* @param {number} d a floating point value.
*/
_Data_['putDOUBLE'] = function(d) {
this._check(_pn_data_put_double(this._data, d));
};
/**
* Puts a decimal32 value.
* @method putDECIMAL32
* @memberof! proton.Data#
* @param {number} d a decimal32 value.
*/
_Data_['putDECIMAL32'] = function(d) {
this._check(_pn_data_put_decimal32(this._data, d));
};
/**
* Puts a decimal64 value.
* @method putDECIMAL64
* @memberof! proton.Data#
* @param {number} d a decimal64 value.
*/
_Data_['putDECIMAL64'] = function(d) {
this._check(_pn_data_put_decimal64(this._data, d));
};
/**
* Puts a decimal128 value.
* @method putDECIMAL128
* @memberof! proton.Data#
* @param {number} d a decimal128 value.
*/
_Data_['putDECIMAL128'] = function(d) {
this._check(_pn_data_put_decimal128(this._data, d));
};
/**
* Puts a UUID value.
* @method putUUID
* @memberof! proton.Data#
* @param {proton.Data.Uuid} u a uuid value
*/
_Data_['putUUID'] = function(u) {
var sp = Runtime.stackSave();
this._check(_pn_data_put_uuid(this._data, allocate(u['uuid'], 'i8', ALLOC_STACK)));
Runtime.stackRestore(sp);
};
/**
* Puts a binary value consuming the underlying raw data in the process.
* @method putBINARY
* @memberof! proton.Data#
* @param {proton.Data.Binary} b a binary value.
*/
_Data_['putBINARY'] = function(b) {
var sp = Runtime.stackSave();
// The implementation here is a bit "quirky" due to some low-level details
// of the interaction between emscripten and LLVM and the use of pn_bytes.
// The JavaScript code below is basically a binding to:
//
// pn_data_put_binary(data, pn_bytes(b.size, b.start));
// Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
// the low-level code handles this *by pointer* so we first need to allocate
// 8 bytes storage for {size, start} on the emscripten stack and then we
// pass the pointer to that storage as the first parameter to the pn_bytes.
var bytes = allocate(8, 'i8', ALLOC_STACK);
_pn_bytes(bytes, b.size, b.start);
// The compiled pn_data_put_binary takes the pn_bytes_t by reference not value.
this._check(_pn_data_put_binary(this._data, bytes));
// After calling _pn_data_put_binary the underlying Data object "owns" the
// binary data, so we can call free on the proton.Data.Binary instance to
// release any storage it has acquired back to the emscripten heap.
b['free']();
Runtime.stackRestore(sp);
};
/**
* Puts a unicode string value.
* @method putSTRING
* @memberof! proton.Data#
* @param {string} s a unicode string value.
*/
_Data_['putSTRING'] = function(s) {
var sp = Runtime.stackSave();
// The implementation here is a bit "quirky" due to some low-level details
// of the interaction between emscripten and LLVM and the use of pn_bytes.
// The JavaScript code below is basically a binding to:
//
// pn_data_put_string(data, pn_bytes(strlen(text), text));
// First create an array from the JavaScript String using the intArrayFromString
// helper function (from emscripten/src/preamble.js). We use this idiom in a
// few places but here we create array as a separate var as we need its length.
var array = intArrayFromString(s, true); // The true means don't add NULL.
// Allocate temporary storage for the array on the emscripten stack.
var str = allocate(array, 'i8', ALLOC_STACK);
// Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
// the low-level code handles this *by pointer* so we first need to allocate
// 8 bytes storage for {size, start} on the emscripten stack and then we
// pass the pointer to that storage as the first parameter to the pn_bytes.
var bytes = allocate(8, 'i8', ALLOC_STACK);
_pn_bytes(bytes, array.length, str);
// The compiled pn_data_put_string takes the pn_bytes_t by reference not value.
this._check(_pn_data_put_string(this._data, bytes));
Runtime.stackRestore(sp);
};
/**
* Puts a symbolic value. According to the AMQP 1.0 Specification Symbols are
* values from a constrained domain. Although the set of possible domains is
* open-ended, typically the both number and size of symbols in use for any
* given application will be small, e.g. small enough that it is reasonable to
* cache all the distinct values. Symbols are encoded as ASCII characters.
* @method putSYMBOL
* @memberof! proton.Data#
* @param {proton.Data.Symbol|string} s the symbol name.
*/
_Data_['putSYMBOL'] = function(s) {
var sp = Runtime.stackSave();
// The implementation here is a bit "quirky" due to some low-level details
// of the interaction between emscripten and LLVM and the use of pn_bytes.
// The JavaScript code below is basically a binding to:
//
// pn_data_put_symbol(data, pn_bytes(strlen(text), text));
// First create an array from the JavaScript String using the intArrayFromString
// helper function (from emscripten/src/preamble.js). We use this idiom in a
// few places but here we create array as a separate var as we need its length.
var array = intArrayFromString(s, true); // The true means don't add NULL.
// Allocate temporary storage for the array on the emscripten stack.
var str = allocate(array, 'i8', ALLOC_STACK);
// Here's the quirky bit, pn_bytes actually returns pn_bytes_t *by value* but
// the low-level code handles this *by pointer* so we first need to allocate
// 8 bytes storage for {size, start} on the emscripten stack and then we
// pass the pointer to that storage as the first parameter to the pn_bytes.
var bytes = allocate(8, 'i8', ALLOC_STACK);
_pn_bytes(bytes, array.length, str);
// The compiled pn_data_put_symbol takes the pn_bytes_t by reference not value.
this._check(_pn_data_put_symbol(this._data, bytes));
Runtime.stackRestore(sp);
};
/**
* If the current node is a list node, return the number of elements,
* otherwise return zero. List elements can be accessed by entering
* the list.
* <pre>
* var count = data.getLISTNODE();
* data.enter();
* for (var i = 0; i < count; i++) {
* var type = data.next();
* if (type === proton.Data.STRING) {
* console.log(data.getSTRING());
* }
* }
* data.exit();
* </pre>
* @method getLISTNODE
* @memberof! proton.Data#
* @returns {number} the number of elements if the current node is a list,
* zero otherwise.
*/
_Data_['getLISTNODE'] = function() {
return _pn_data_get_list(this._data);
};
/**
* If the current node is a map, return the number of child elements,
* otherwise return zero. Key value pairs can be accessed by entering
* the map.
* <pre>
* var count = data.getMAPNODE();
* data.enter();
* for (var i = 0; i < count/2; i++) {
* var type = data.next();
* if (type === proton.Data.STRING) {
* console.log(data.getSTRING());
* }
* }
* data.exit();
* </pre>
* @method getMAPNODE
* @memberof! proton.Data#
* @returns {number} the number of elements if the current node is a list,
* zero otherwise.
*/
_Data_['getMAPNODE'] = function() {
return _pn_data_get_map(this._data);
};
/**
* If the current node is an array, return an object containing the tuple of the
* element count, a boolean indicating whether the array is described, and the
* type of each element, otherwise return {count: 0, described: false, type: null).
* Array data can be accessed by entering the array.
* <pre>
* // Read an array of strings with a symbolic descriptor
* var metadata = data.getARRAYNODE();
* var count = metadata.count;
* data.enter();
* data.next();
* console.log("Descriptor:" + data.getSYMBOL());
* for (var i = 0; i < count; i++) {
* var type = data.next();
* console.log("Element:" + data.getSTRING());
* }
* data.exit();
* </pre>
* @method getARRAYNODE
* @memberof! proton.Data#
* @returns {object} the tuple of the element count, a boolean indicating whether
* the array is described, and the type of each element.
*/
_Data_['getARRAYNODE'] = function() {
var count = _pn_data_get_array(this._data);
var described = (_pn_data_is_array_described(this._data) > 0);
var type = _pn_data_get_array_type(this._data);
type = (type == -1) ? null : type;
return {'count': count, 'described': described, 'type': type};
};
/**
* Checks if the current node is a described node. The descriptor and value may
* be accessed by entering the described node.
* <pre>
* // read a symbolically described string
* assert(data.isDESCRIBEDNODE()); // will error if the current node is not described
* data.enter();
* console.log(data.getSYMBOL());
* console.log(data.getSTRING());
* data.exit();
* </pre>
* @method isDESCRIBEDNODE
* @memberof! proton.Data#
* @returns {boolean} true iff the current node is a described, false otherwise.
*/
_Data_['isDESCRIBEDNODE'] = function() {
return _pn_data_is_described(this._data);
};
/**
* @method getNULL
* @memberof! proton.Data#
* @returns a null value.
*/
_Data_['getNULL'] = function() {
return null;
};
/**
* Checks if the current node is a null.
* @method isNULL
* @memberof! proton.Data#
* @returns {boolean} true iff the current node is null.
*/
_Data_['isNULL'] = function() {
return (_pn_data_is_null(this._data) > 0);
};
/**
* @method getBOOL
* @memberof! proton.Data#
* @returns {boolean} a boolean value if the current node is a boolean, returns
* false otherwise.
*/
_Data_['getBOOL'] = function() {
return (_pn_data_get_bool(this._data) > 0);
};
/**
* @method getUBYTE
* @memberof! proton.Data#
* @returns {number} value if the current node is an unsigned byte, returns 0 otherwise.
*/
_Data_['getUBYTE'] = function() {
return _pn_data_get_ubyte(this._data) & 0xFF; // & 0xFF converts to unsigned;
};
/**
* @method getBYTE
* @memberof! proton.Data#
* @returns {number} value if the current node is a signed byte, returns 0 otherwise.
*/
_Data_['getBYTE'] = function() {
return _pn_data_get_byte(this._data);
};
/**
* @method getUSHORT
* @memberof! proton.Data#
* @returns {number} value if the current node is an unsigned short, returns 0 otherwise.
*/
_Data_['getUSHORT'] = function() {
return _pn_data_get_ushort(this._data) & 0xFFFF; // & 0xFFFF converts to unsigned;
};
/**
* @method getSHORT
* @memberof! proton.Data#
* @returns {number} value if the current node is a signed short, returns 0 otherwise.
*/
_Data_['getSHORT'] = function() {
return _pn_data_get_short(this._data);
};
/**
* @method getUINT
* @memberof! proton.Data#
* @returns {number} value if the current node is an unsigned int, returns 0 otherwise.
*/
_Data_['getUINT'] = function() {
var value = _pn_data_get_uint(this._data);
return (value > 0) ? value : 4294967296 + value; // 4294967296 == 2^32
};
/**
* @method getINT
* @memberof! proton.Data#
* @returns {number} value if the current node is a signed int, returns 0 otherwise.
*/
_Data_['getINT'] = function() {
return _pn_data_get_int(this._data);
};
/**
* @method getCHAR
* @memberof! proton.Data#
* @returns {string} the character represented by the unicode value of the current node.
*/
_Data_['getCHAR'] = function() {
return String.fromCharCode(_pn_data_get_char(this._data));
};
/**
* Retrieve an unsigned long value. N.B. large values can suffer from a loss of
* precision as JavaScript numbers are restricted to 64 bit double values.
* @method getULONG
* @memberof! proton.Data#
* @returns {proton.Data.Long} value if the current node is an unsigned long, returns 0 otherwise.
*/
_Data_['getULONG'] = function() {
var low = _pn_data_get_ulong(this._data);
var high = Runtime.getTempRet0();
var long = new Data.Long(low, high);
long = long.toNumber();
return (long >= 0) ? long : Data.Long.TWO_PWR_64_DBL_ + long;
};
/**
* Retrieve a signed long value. N.B. large values can suffer from a loss of
* precision as JavaScript numbers are restricted to 64 bit double values.
* @method getLONG
* @memberof! proton.Data#
* @returns {proton.Data.Long} value if the current node is a signed long, returns 0 otherwise.
*/
_Data_['getLONG'] = function() {
// Getting the long is a little tricky as it is a 64 bit number. The way
// emscripten handles this is to return the low 32 bits directly and pass
// the high 32 bits via the tempRet0 variable. We use Data.Long to hold
// the 64 bit number and Data.Long.toNumber() to convert it back into a
// JavaScript number.
var low = _pn_data_get_long(this._data);
var high = Runtime.getTempRet0();
var long = new Data.Long(low, high);
long = long.toNumber();
return long;
};
/**
* @method getTIMESTAMP
* @memberof! proton.Data#
* @returns {Date} a native JavaScript Date instance representing the timestamp.
*/
_Data_['getTIMESTAMP'] = function() {
// Getting the timestamp is a little tricky as it is a 64 bit number. The way
// emscripten handles this is to return the low 32 bits directly and pass
// the high 32 bits via the tempRet0 variable. We use Data.Long to hold
// the 64 bit number and Data.Long.toNumber() to convert it back into a
// JavaScript number.
var low = _pn_data_get_timestamp(this._data);
var high = Runtime.getTempRet0();
var long = new Data.Long(low, high);
long = long.toNumber();
return new Date(long);
};
/**
* Retrieves a float value. N.B. converting between floats and doubles is imprecise
* so the resulting value might not quite be what you expect.
* @method getFLOAT
* @memberof! proton.Data#
* @returns {number} value if the current node is a float, returns 0 otherwise.
*/
_Data_['getFLOAT'] = function() {
return _pn_data_get_float(this._data);
};
/**
* @method getDOUBLE
* @memberof! proton.Data#
* @returns {number} value if the current node is a double, returns 0 otherwise.
*/
_Data_['getDOUBLE'] = function() {
return _pn_data_get_double(this._data);
};
/**
* @method getDECIMAL32
* @memberof! proton.Data#
* @returns {number} value if the current node is a decimal32, returns 0 otherwise.
*/
_Data_['getDECIMAL32'] = function() {
console.log("getDECIMAL32 not properly implemented yet");
return _pn_data_get_decimal32(this._data);
};
/**
* @method getDECIMAL64
* @memberof! proton.Data#
* @returns {number} value if the current node is a decimal64, returns 0 otherwise.
*/
_Data_['getDECIMAL64'] = function() {
console.log("getDECIMAL64 not properly implemented yet");
return _pn_data_get_decimal64(this._data);
};
/**
* @method getDECIMAL128
* @memberof! proton.Data#
* @returns {number} value if the current node is a decimal128, returns 0 otherwise.
*/
_Data_['getDECIMAL128'] = function() {
console.log("getDECIMAL128 not properly implemented yet");
return _pn_data_get_decimal128(this._data);
};
/**
* @method getUUID
* @memberof! proton.Data#
* @returns {proton.Data.Uuid} value if the current node is a UUID, returns null otherwise.
*/
_Data_['getUUID'] = function() {
var sp = Runtime.stackSave();
// Here's the quirky bit, pn_data_get_uuid actually returns pn_uuid_t
// *by value* but the low-level code handles this *by pointer* so we first
// need to allocate 16 bytes storage for pn_uuid_t on the emscripten stack
// and then we pass the pointer to that storage as the first parameter to the
// compiled pn_data_get_uuid.
var bytes = allocate(16, 'i8', ALLOC_STACK); // pn_uuid_t is 16 bytes.
_pn_data_get_uuid(bytes, this._data);
// Create a new UUID from the bytes
var uuid = new Data['Uuid'](bytes);
// Tidy up the memory that we allocated on emscripten's stack.
Runtime.stackRestore(sp);
return uuid;
};
/**
* @method getBINARY
* @memberof! proton.Data#
* @returns {proton.Data.Binary} value if the current node is a Binary, returns null otherwise.
*/
_Data_['getBINARY'] = function() {
var sp = Runtime.stackSave();
// The implementation here is a bit "quirky" due to some low-level details
// of the interaction between emscripten and LLVM and the use of pn_bytes.
// The JavaScript code below is basically a binding to:
//
// pn_bytes bytes = pn_data_get_binary(data);
// Here's the quirky bit, pn_data_get_binary actually returns pn_bytes_t
// *by value* but the low-level code handles this *by pointer* so we first
// need to allocate 8 bytes storage for {size, start} on the emscripten stack
// and then we pass the pointer to that storage as the first parameter to the
// compiled pn_data_get_binary.
var bytes = allocate(8, 'i8', ALLOC_STACK);
_pn_data_get_binary(bytes, this._data);
// The bytes variable is really of type pn_bytes_t* so we use emscripten's
// getValue() call to retrieve the size and then the start pointer.
var size = getValue(bytes, 'i32');
var start = getValue(bytes + 4, '*');
// Create a proton.Data.Binary from the pn_bytes_t information.
var binary = new Data['Binary'](size, start);
// Tidy up the memory that we allocated on emscripten's stack.
Runtime.stackRestore(sp);
// If _decodeBinaryAsString is set return the stringified form of the Binary.
if (this._decodeBinaryAsString) {
return binary.toString();
} else {
return binary;
}
};
/**
* Gets a unicode String value from the current node.
* @method getSTRING
* @memberof! proton.Data#
* @returns {string} value if the current node is a String, returns "" otherwise.
*/
_Data_['getSTRING'] = function() {
var sp = Runtime.stackSave();
// The implementation here is a bit "quirky" due to some low-level details
// of the interaction between emscripten and LLVM and the use of pn_bytes.
// The JavaScript code below is basically a binding to:
//
// pn_bytes bytes = pn_data_get_string(data);
// Here's the quirky bit, pn_data_get_string actually returns pn_bytes_t
// *by value* but the low-level code handles this *by pointer* so we first
// need to allocate 8 bytes storage for {size, start} on the emscripten stack
// and then we pass the pointer to that storage as the first parameter to the
// compiled pn_data_get_string.
var bytes = allocate(8, 'i8', ALLOC_STACK);
_pn_data_get_string(bytes, this._data);
// The bytes variable is really of type pn_bytes_t* so we use emscripten's
// getValue() call to retrieve the size and then the start pointer.
var size = getValue(bytes, 'i32');
var start = getValue(bytes + 4, '*');
// Create a native JavaScript String from the pn_bytes_t information.
var string = Pointer_stringify(start, size);
// Tidy up the memory that we allocated on emscripten's stack.
Runtime.stackRestore(sp);
return string;
};
/**
* Gets a symbolic value. According to the AMQP 1.0 Specification Symbols are
* values from a constrained domain. Although the set of possible domains is
* open-ended, typically the both number and size of symbols in use for any
* given application will be small, e.g. small enough that it is reasonable to
* cache all the distinct values. Symbols are encoded as ASCII characters.
* @method getSYMBOL
* @memberof! proton.Data#
* @returns {proton.Data.Symbol} value if the current node is a Symbol, returns "" otherwise.
*/
_Data_['getSYMBOL'] = function() {
var sp = Runtime.stackSave();
// The implementation here is a bit "quirky" due to some low-level details
// of the interaction between emscripten and LLVM and the use of pn_bytes.
// The JavaScript code below is basically a binding to:
//
// pn_bytes bytes = pn_data_get_symbol(data);
// Here's the quirky bit, pn_data_get_symbol actually returns pn_bytes_t
// *by value* but the low-level code handles this *by pointer* so we first
// need to allocate 8 bytes storage for {size, start} on the emscripten stack
// and then we pass the pointer to that storage as the first parameter to the
// compiled pn_data_get_symbol.
var bytes = allocate(8, 'i8', ALLOC_STACK);
_pn_data_get_symbol(bytes, this._data);
// The bytes variable is really of type pn_bytes_t* so we use emscripten's
// getValue() call to retrieve the size and then the start pointer.
var size = getValue(bytes, 'i32');
var start = getValue(bytes + 4, '*');
// Create a native JavaScript String from the pn_bytes_t information.
var string = Pointer_stringify(start, size);
// Tidy up the memory that we allocated on emscripten's stack.
Runtime.stackRestore(sp);
return new Data['Symbol'](string);
};
/**
* Performs a deep copy of the current {@link proton.Data} instance and returns it
* @method copy
* @memberof! proton.Data#
* @returns {proton.Data} a copy of the current {@link proton.Data} instance.
*/
_Data_['copy'] = function() {
var copy = new Data();
this._check(_pn_data_copy(copy._data, this._data));
return copy;
};
/**
* Format the encoded AMQP Data into a string representation and return it.
* @method format
* @memberof! proton.Data#
* @returns {string} a formatted string representation of the encoded Data.
*/
_Data_['format'] = function() {
var sp = Runtime.stackSave();
var sizeptr = allocate(4, 'i32', ALLOC_STACK);
var size = 1024; // Pass by reference variable - need to use setValue to initialise it.
while (true) {
setValue(sizeptr, size, 'i32'); // Set pass by reference variable.
var bytes = _malloc(size); // Allocate storage from emscripten heap.
var err = _pn_data_format(this._data, bytes, sizeptr);
var size = getValue(sizeptr, 'i32'); // Dereference the real size value;
if (err === Module['Error']['OVERFLOW']) {
_free(bytes);
size *= 2;
} else {
var string = Pointer_stringify(bytes, size);
_free(bytes);
// Tidy up the memory that we allocated on emscripten's stack.
Runtime.stackRestore(sp);
this._check(err)
return string;
}
}
};
/**
* Print the internal state of the {@link proton.Data} in human readable form.
* TODO. This seems to "crash" if compound nodes such as DESCRIBED, MAP or LIST
* are present in the tree, this is most likely a problem with the underlying C
* implementation as all the other navigation and format methods work - need to
* check by testing with some native C code.
* @method dump
* @memberof! proton.Data#
*/
_Data_['dump'] = function() {
_pn_data_dump(this._data);
};
/**
* Serialise a Native JavaScript Object into an AMQP Map.
* @method putMAP
* @memberof! proton.Data#
* @param {object} object the Native JavaScript Object that we wish to serialise.
*/
_Data_['putMAP'] = function(object) {
this['putMAPNODE']();
this['enter']();
for (var key in object) {
if (object.hasOwnProperty(key)) {
this['putObject'](key);
this['putObject'](object[key]);
}
}
this['exit']();
};
/**
* Deserialise from an AMQP Map into a Native JavaScript Object.
* @method getMAP
* @memberof! proton.Data#
* @returns {object} the deserialised Native JavaScript Object.
*/
_Data_['getMAP'] = function() {
if (this['enter']()) {
var result = {};
while (this['next']()) {
var key = this['getObject']();
var value = null;
if (this['next']()) {
value = this['getObject']();
}
result[key] = value;
}
this['exit']();
return result;
}
};
/**
* Serialise a Native JavaScript Array into an AMQP List.
* @method putLIST
* @memberof! proton.Data#
* @param {Array} array the Native JavaScript Array that we wish to serialise.
*/
_Data_['putLIST'] = function(array) {
this['putLISTNODE']();
this['enter']();
for (var i = 0, len = array.length; i < len; i++) {
this['putObject'](array[i]);
}
this['exit']();
};
/**
* Deserialise from an AMQP List into a Native JavaScript Array.
* @method getLIST
* @memberof! proton.Data#
* @returns {Array} the deserialised Native JavaScript Array.
*/
_Data_['getLIST'] = function() {
if (this['enter']()) {
var result = [];
while (this['next']()) {
result.push(this['getObject']());
}
this['exit']();
return result;
}
};
/**
* Serialise a proton.Data.Described into an AMQP Described.
* @method putDESCRIBED
* @memberof! proton.Data#
* @param {proton.Data.Described} d the proton.Data.Described that we wish to serialise.
*/
_Data_['putDESCRIBED'] = function(d) {
this['putDESCRIBEDNODE']();
this['enter']();
this['putObject'](d['descriptor']);
this['putObject'](d['value']);
this['exit']();
};
/**
* Deserialise from an AMQP Described into a proton.Data.Described.
* @method getDESCRIBED
* @memberof! proton.Data#
* @returns {proton.Data.Described} the deserialised proton.Data.Described.
*/
_Data_['getDESCRIBED'] = function() {
if (this['enter']()) {
this['next']();
var descriptor = this['getObject']();
this['next']();
var value = this['getObject']();
this['exit']();
return new Data['Described'](value, descriptor);
}
};
/**
* Serialise a proton.Data.Array or JavaScript TypedArray into an AMQP Array.
* @method putARRAY
* @memberof! proton.Data#
* @param {object} a the proton.Data.Array or TypedArray that we wish to serialise.
*/
_Data_['putARRAY'] = function(a) {
var type = 1;
var descriptor = 'TypedArray';
var array = a;
if (a instanceof Data['Array']) { // Array is a proton.Data.Array
type = Data[a['type']]; // Find the integer type from its name string.
descriptor = a['descriptor'];
array = a['elements'];
} else { // Array is a Native JavaScript TypedArray so work out the right type.
if (a instanceof Int8Array) {
type = Data['BYTE'];
} else if (a instanceof Uint8Array || a instanceof Uint8ClampedArray) {
type = Data['UBYTE'];
} else if (a instanceof Int16Array) {
type = Data['SHORT'];
} else if (a instanceof Uint16Array) {
type = Data['USHORT'];
} else if (a instanceof Int32Array) {
type = Data['INT'];
} else if (a instanceof Uint32Array) {
type = Data['UINT'];
} else if (a instanceof Float32Array) {
type = Data['FLOAT'];
} else if (a instanceof Float64Array) {
type = Data['DOUBLE'];
}
}
var described = descriptor != null;
this['putARRAYNODE'](described, type);
this['enter']();
if (described) {
this['putObject'](descriptor);
}
var putter = 'put' + Data['TypeNames'][type];
for (var i = 0, len = array.length; i < len; i++) {
var value = array[i];
value = (value instanceof Data.TypedNumber) ? value.value : value;
this[putter](value);
}
this['exit']();
};
/**
* Deserialise from an AMQP Array into a proton.Data.Array.
* @method getARRAY
* @memberof! proton.Data#
* @returns {proton.Data.Array} the deserialised proton.Data.Array.
*/
_Data_['getARRAY'] = function() {
var metadata = this['getARRAYNODE']();
var count = metadata['count'];
var described = metadata['described'];
var type = metadata['type'];
if (type === null) {
return null;
}
var elements = null;
if (typeof ArrayBuffer === 'function') {
if (type === Data['BYTE']) {
elements = new Int8Array(count);
} else if (type === Data['UBYTE']) {
elements = new Uint8Array(count);
} else if (type === Data['SHORT']) {
elements = new Int16Array(count);
} else if (type === Data['USHORT']) {
elements = new Uint16Array(count);
} else if (type === Data['INT']) {
elements = new Int32Array(count);
} else if (type === Data['UINT']) {
elements = new Uint32Array(count);
} else if (type === Data['FLOAT']) {
elements = new Float32Array(count);
} else if (type === Data['DOUBLE']) {
elements = new Float64Array(count);
} else {
elements = new Array(count);
}
} else {
elements = new Array(count);
}
if (this['enter']()) {
var descriptor; // Deliberately initialised as undefined not null.
if (described) {
this['next']();
descriptor = this['getObject']();
}
for (var i = 0; i < count; i++) {
this['next']();
elements[i] = this['getObject']();
}
this['exit']();
if (descriptor === 'TypedArray') {
return elements;
} else {
return new Data['Array'](type, elements, descriptor);
}
}
};
/**
* This method is the entry point for serialising native JavaScript types into
* AMQP types. In an ideal world there would be a nice clean one to one mapping
* and we could employ a look-up table but in practice the JavaScript type system
* doesn't really lend itself to that and we have to employ extra checks,
* heuristics and inferences.
* @method putObject
* @memberof! proton.Data#
* @param {object} obj the JavaScript Object or primitive to be serialised.
*/
_Data_['putObject'] = function(obj) {
//console.log("Data.putObject " + obj);
if (obj == null) { // == Checks for null and undefined.
this['putNULL']();
} else if (Data.isString(obj)) {
var quoted = obj.match(/(['"])[^'"]*\1/);
if (quoted) { // If a quoted string extract the string inside the quotes.
obj = quoted[0].slice(1, -1);
}
this['putSTRING'](obj);
} else if (obj instanceof Date) {
this['putTIMESTAMP'](obj);
} else if (obj instanceof Data['Uuid']) {
this['putUUID'](obj);
} else if (obj instanceof Data['Binary']) {
this['putBINARY'](obj);
} else if (obj instanceof Data['Symbol']) {
this['putSYMBOL'](obj);
} else if (obj instanceof Data['Described']) {
this['putDESCRIBED'](obj);
} else if (obj instanceof Data['Array']) {
this['putARRAY'](obj);
} else if (obj.buffer && (typeof ArrayBuffer === 'function') &&
obj.buffer instanceof ArrayBuffer) {
this['putARRAY'](obj);
} else if (obj instanceof Data.TypedNumber) { // Dot notation used for "protected" inner class.
// Call the appropriate serialisation method based upon the numerical type.
this['put' + obj.type](obj.value);
} else if (Data.isNumber(obj)) {
/**
* This block encodes standard JavaScript numbers by making some inferences.
* Encoding JavaScript numbers is surprisingly complex and has several
* gotchas. The code here tries to do what the author believes is the
* most "intuitive" encoding of the native JavaScript Number. It first
* tries to identify if the number is an integer or floating point type
* by checking if the number modulo 1 is zero (i.e. if it has a remainder
* then it's a floating point type, which is encoded here as a double).
* If the number is an integer type a test is made to check if it is a
* 32 bit Int value. N.B. gotcha - JavaScript automagically coerces floating
* point numbers with a zero Fractional Part into an *exact* integer so
* numbers like 1.0, 100.0 etc. will be encoded as int or long here,
* which is unlikely to be what is wanted. There's no easy "transparent"
* way around this. The TypedNumber approach above allows applications
* to express more explicitly what is required, for example (1.0).float()
* (1).ubyte(), (5).long() etc.
*/
if (obj % 1 === 0) {
if (obj === (obj|0)) { // the |0 coerces to a 32 bit value.
// 32 bit integer - encode as an INT.
this['putINT'](obj);
} else { // Longer than 32 bit - encode as a Long.
this['putLONG'](obj);
}
} else { // Floating point type - encode as a Double
this['putDOUBLE'](obj);
}
} else if (Data.isBoolean(obj)) {
this['putBOOL'](obj);
} else if (Data.isArray(obj)) { // Native JavaScript Array
this['putLIST'](obj);
} else {
this['putMAP'](obj);
}
};
/**
* @method getObject
* @memberof! proton.Data#
* @returns {object} the JavaScript Object or primitive being deserialised.
*/
_Data_['getObject'] = function() {
var type = Data['TypeNames'][this.type()];
type = type ? type : 'NULL';
var getter = 'get' + type;
return this[getter]();
};