You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by rh...@apache.org on 2014/11/28 14:49:48 UTC
[10/51] [abbrv] qpid-proton git commit: Implemented the remainder of
the codec methods and ported the codec unit test suite to test it all
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6aed8542/proton-c/bindings/javascript/binding.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.js b/proton-c/bindings/javascript/binding.js
index 43634d4..08aeb3e 100644
--- a/proton-c/bindings/javascript/binding.js
+++ b/proton-c/bindings/javascript/binding.js
@@ -37,15 +37,16 @@
* from minifying e.g. <pre>Module['Messenger'] = ...</pre>
* Exported Objects can be used in client code using the appropriate namespace:
* <pre>
- * proton = require("proton.js");
+ * proton = require('proton.js');
* var messenger = new proton.Messenger();
* var message = new proton.Message();
* </pre>
* @namespace proton
*/
+
var Module = {
// Prevent emscripten runtime exiting, we will be enabling network callbacks.
- 'noExitRuntime' : true
+ 'noExitRuntime' : true,
};
/*****************************************************************************/
@@ -790,7 +791,7 @@ Module['Message'] = function() { // Message Constructor.
* Application defined Message properties.
* @type map
*/
- this['properties'] = null;
+ this['properties'] = {};
/**
* Message body.
@@ -835,32 +836,35 @@ _Message_._check = function(code) {
* Encode the Message prior to sending on the wire.
*/
_Message_._preEncode = function() {
- if (this.instructions) {
+ // A Message Object may be reused so we create new Data instances and clear
+ // the state for them each time put() gets called.
+ var inst = new Data(_pn_message_instructions(this._message));
+ var ann = new Data(_pn_message_annotations(this._message));
+ var props = new Data(_pn_message_properties(this._message));
+ var body = new Data(_pn_message_body(this._message));
+
+ inst.clear();
+ if (this['instructions']) {
console.log("Encoding instructions");
- var inst = new Data(_pn_message_instructions(this._message));
- inst.clear();
- inst.putObject(this.instructions);
+ inst['putObject'](this['instructions']);
}
- if (this.annotations) {
+ ann.clear();
+ if (this['annotations']) {
console.log("Encoding annotations");
- var ann = new Data(_pn_message_annotations(this._message));
- ann.clear();
- ann.putObject(this.annotations);
+ ann['putObject'](this['annotations']);
}
- if (this.properties) {
+ props.clear();
+ if (this['properties']) {
console.log("Encoding properties");
- var props = new Data(_pn_message_properties(this._message));
- props.clear();
- props.putObject(this.properties);
+ props['putObject'](this['properties']);
}
- if (this.body != null) {
+ body.clear();
+ if (this['body']) {
console.log("Encoding body");
- var body = new Data(_pn_message_body(this._message));
- body.clear();
- body.putObject(this.body);
+ body['putObject'](this['body']);
}
};
@@ -874,27 +878,27 @@ _Message_._postDecode = function() {
var body = new Data(_pn_message_body(this._message));
if (inst.next()) {
- this.instructions = inst.getObject();
+ this['instructions'] = inst['getObject']();
} else {
- this.instructions = {};
+ this['instructions'] = {};
}
if (ann.next()) {
- this.annotations = ann.getObject();
+ this['annotations'] = ann['getObject']();
} else {
- this.annotations = {};
+ this['annotations'] = {};
}
if (props.next()) {
- this.properties = props.getObject();
+ this['properties'] = props['getObject']();
} else {
- this.properties = {};
+ this['properties'] = {};
}
if (body.next()) {
- this.body = body.getObject();
+ this['body'] = body['getObject']();
} else {
- this.body = null;
+ this['body'] = null;
}
};
@@ -933,7 +937,7 @@ _Message_['getError'] = function() {
/**
* @method getAddress
* @memberof! proton.Message#
- * @return {string} the address of the Message.
+ * @returns {string} the address of the Message.
*/
_Message_['getAddress'] = function() {
return Pointer_stringify(_pn_message_get_address(this._message));
@@ -1014,13 +1018,25 @@ _Message_['setSubject'] = function(subject) {
* 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
+ * @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().
*/
Module['Data'] = function(data) { // Data Constructor.
- this._data = data;
-
if (!data) {
- console.log("Warning Data created with null 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() {};
}
};
@@ -1030,62 +1046,89 @@ 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>} GetMappings
+ * @property {Array<String>} TypeNames
* @memberof! proton.Data
*/
-Data.GetMappings = [
- 'getNull', // 0
- 'getNull', // PN_NULL = 1
- 'getBoolean', // PN_BOOL = 2
- 'getUnsignedByte', // PN_UBYTE = 3
- 'getByte', // PN_BYTE = 4
- 'getUnsignedShort', // PN_USHORT = 5
- 'getShort', // PN_SHORT = 6
- 'getUnsignedInteger', // PN_UINT = 7
- 'getInteger', // PN_INT = 8
- 'getChar', // PN_CHAR = 9
- 'getUnsignedLong', // PN_ULONG = 10
- 'getLong', // PN_LONG = 11
- 'getTimestamp', // PN_TIMESTAMP = 12
- 'getFloat', // PN_FLOAT = 13
- 'getDouble', // PN_DOUBLE = 14
- 'getDecimal32', // PN_DECIMAL32 = 15
- 'getDecimal64', // PN_DECIMAL64 = 16
- 'getDecimal128', // PN_DECIMAL128 = 17
- 'getUUID', // PN_UUID = 18
- 'getBinary', // PN_BINARY = 19
- 'getString', // PN_STRING = 20
- 'getSymbol', // PN_SYMBOL = 21
- 'getDescribed', // PN_DESCRIBED = 22
- 'getArray', // PN_ARRAY = 23
- 'getJSArray', // PN_LIST = 24
- 'getDictionary' // PN_MAP = 25
+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 an Array.
+ * 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 an Array.
+ * @returns {boolean} true iff the Object is a JavaScript Array.
*/
Data.isArray = Array.isArray || function(o) {
-console.log("Data.isArray");
return Object.prototype.toString.call(o) === '[object Array]';
};
/**
- * Test if a given Object is a Number.
+ * 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 Number.
+ * @returns {boolean} true iff the Object is a JavaScript Number.
*/
Data.isNumber = function(o) {
return typeof o === 'number' ||
@@ -1093,11 +1136,11 @@ Data.isNumber = function(o) {
};
/**
- * Test if a given Object is a String.
+ * 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 String.
+ * @returns {boolean} true iff the Object is a JavaScript String.
*/
Data.isString = function(o) {
return typeof o === 'string' ||
@@ -1105,11 +1148,11 @@ Data.isString = function(o) {
};
/**
- * Test if a given Object is a Boolean.
+ * 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 Boolean.
+ * @returns {boolean} true iff the Object is a JavaScript Boolean.
*/
Data.isBoolean = function(o) {
return typeof o === 'boolean' ||
@@ -1118,20 +1161,20 @@ Data.isBoolean = function(o) {
// **************************** Inner Classes *********************************
-// --------------------------- proton.Data.UUID -------------------------------
+// --------------------------- proton.Data.Uuid -------------------------------
/**
- * Create a proton.Data.UUID which is a type 4 UUID.
+ * Create a proton.Data.Uuid which is a type 4 UUID.
* @classdesc
* This class represents a type 4 UUID, wich may use crypto libraries to generate
* the UUID if supported by the platform (e.g. node.js or a modern browser)
- * @constructor proton.Data.UUID
+ * @constructor proton.Data.Uuid
* @param u a UUID. If null a type 4 UUID is generated wich may use crypto if
* supported by the platform. If u is an emscripten "pointer" we copy the
* data from that. If u is a JavaScript Array we use it as-is. If u is a
* String then we try to parse that as a UUID.
* @property {Array} uuid is the compact array form of the UUID.
*/
-Data['UUID'] = function(u) { // Data.UUID Constructor.
+Data['Uuid'] = function(u) { // Data.Uuid Constructor.
// Helper to copy from emscriptem allocated storage into JavaScript Array.
function _p2a(p) {
var uuid = new Array(16);
@@ -1167,13 +1210,14 @@ Data['UUID'] = function(u) { // Data.UUID Constructor.
};
/**
+ * Returns the string representation of the proton.Data.Uuid.
* @method toString
- * @memberof! proton.Data.UUID#
+ * @memberof! proton.Data.Uuid#
* @returns {string} the String
* /[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/
- * form of a {@link proton.Data.UUID}.
+ * form of a {@link proton.Data.Uuid}.
*/
-Data['UUID'].prototype.toString = function() {
+Data['Uuid'].prototype.toString = Data['Uuid'].prototype.valueOf = function() {
if (!this.string) { // Check if we've cached the string version.
var i = 0;
var uu = this['uuid'];
@@ -1189,17 +1233,16 @@ Data['UUID'].prototype.toString = function() {
};
/**
- * Compare two instances of proton.Data.UUID for equality.
+ * Compare two instances of proton.Data.Uuid for equality.
* @method equals
- * @memberof! proton.Data.UUID#
- * @param {proton.Data.UUID} rhs the instance we wish to compare this instance with.
+ * @memberof! proton.Data.Uuid#
+ * @param {proton.Data.Uuid} rhs the instance we wish to compare this instance with.
* @returns {boolean} true iff the two compared instances are equal.
*/
-Data['UUID'].prototype['equals'] = function(rhs) {
+Data['Uuid'].prototype['equals'] = function(rhs) {
return this.toString() === rhs.toString();
};
-
// ---------------------------- proton.Data.Symbol ----------------------------
/**
* Create a proton.Data.Symbol.
@@ -1212,7 +1255,6 @@ Data['UUID'].prototype['equals'] = function(rhs) {
*/
Data['Symbol'] = function(s) { // Data.Symbol Constructor.
this.value = s;
- this.length = this.value.length;
};
/**
@@ -1235,54 +1277,178 @@ Data['Symbol'].prototype['equals'] = function(rhs) {
return this.toString() === rhs.toString();
};
+// ---------------------------- proton.Data.Described ----------------------------
+/**
+ * Create a proton.Data.Described.
+ * @classdesc
+ * This class represents an AMQP Described.
+ * @constructor proton.Data.Described
+ * @param {object} value the value of the described type.
+ * @param {string} descriptor an optional string describing the type.
+ * @property {object} value the actual value of the described type.
+ * @property {string} descriptor a string describing the type.
+ */
+Data['Described'] = function(value, descriptor) { // Data.Described Constructor.
+ this['value'] = value;
+ this['descriptor'] = descriptor;
+};
+
+/**
+ * @method toString
+ * @memberof! proton.Data.Described#
+ * @returns {string} the String form of a {@link proton.Data.Described}.
+ */
+Data['Described'].prototype.toString = function() {
+ return 'Described(' + this['value'] + ', ' + this['descriptor'] + ')';
+};
+
+/**
+ * @method valueOf
+ * @memberof! proton.Data.Described#
+ * @returns {object} the value of the {@link proton.Data.Described}.
+ */
+Data['Described'].prototype.valueOf = function() {
+ return this['value'];
+};
+
+/**
+ * Compare two instances of proton.Data.Described for equality.
+ * @method equals
+ * @memberof! proton.Data.Described#
+ * @param {proton.Data.Described} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
+Data['Described'].prototype['equals'] = function(rhs) {
+ if (rhs instanceof Data['Described']) {
+ return ((this['descriptor'] === rhs['descriptor']) && (this['value'] === rhs['value']));
+ } else {
+ return false;
+ }
+};
+
+// ---------------------------- proton.Data.Array ----------------------------
+/**
+ * TODO make this behave more like a native JavaScript Array: http://www.bennadel.com/blog/2292-extending-javascript-arrays-while-keeping-native-bracket-notation-functionality.htm
+ * Create a proton.Data.Array.
+ * @classdesc
+ * This class represents an AMQP Array.
+ * @constructor proton.Data.Array
+ * @param {{string|number)} type the type of the Number either as a string or number.
+ * Stored internally as a string corresponding to one of the TypeNames.
+ * @param {Array|TypedArray} elements the Native JavaScript Array or TypedArray that we wish to serialise.
+ * @param {object} descriptor an optional object describing the type.
+ */
+Data['Array'] = function(type, elements, descriptor) { // Data.Array Constructor.
+ // This block caters for an empty Array or a Described empty Array.
+ if (arguments.length < 2) {
+ descriptor = type;
+ type = 'NULL';
+ elements = [];
+ }
+
+ this['type'] = (typeof type === 'number') ? Data['TypeNames'][type] : type;
+ this['elements'] = elements;
+ this['descriptor'] = descriptor;
+};
+
+/**
+ * @method toString
+ * @memberof! proton.Data.Array#
+ * @returns {string} the String form of a {@link proton.Data.Array}.
+ */
+Data['Array'].prototype.toString = function() {
+ var descriptor = (this['descriptor'] == null) ? '' : ':' + this['descriptor'];
+ return this['type'] + 'Array' + descriptor + '[' + this['elements'] + ']';
+};
+
+/**
+ * @method valueOf
+ * @memberof! proton.Data.Array#
+ * @returns {Array} the elements of the {@link proton.Data.Array}.
+ */
+Data['Array'].prototype.valueOf = function() {
+ return this['elements'];
+};
+
+/**
+ * Compare two instances of proton.Data.Array for equality. N.B. this method
+ * compares the value of every Array element so its performance is O(n).
+ * @method equals
+ * @memberof! proton.Data.Array#
+ * @param {proton.Data.Array} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
+Data['Array'].prototype['equals'] = function(rhs) {
+ if (rhs instanceof Data['Array'] &&
+ // Check the string value of the descriptors.
+ (('' + this['descriptor']) === ('' + rhs['descriptor'])) &&
+ (this['type'] === rhs['type'])) {
+ var elements = this['elements'];
+ var relements = rhs['elements'];
+ var length = elements.length;
+ if (length === relements.length) {
+ for (var i = 0; i < length; i++) {
+ if (elements[i].valueOf() !== relements[i].valueOf()) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+};
+
// ---------------------- JavaScript Number Extensions ------------------------
-Number.prototype['asUnsignedByte'] = function() {
- return new Data.TypedNumber('UnsignedByte', this);
+Number.prototype['ubyte'] = function() {
+ return new Data.TypedNumber('UBYTE', this);
};
-Number.prototype['asByte'] = function() {
- return new Data.TypedNumber('Byte', this);
+Number.prototype['byte'] = function() {
+ return new Data.TypedNumber('BYTE', this);
};
-Number.prototype['asUnsignedShort'] = function() {
- return new Data.TypedNumber('UnsignedShort', this);
+Number.prototype['ushort'] = function() {
+ return new Data.TypedNumber('USHORT', this);
};
-Number.prototype['asShort'] = function() {
- return new Data.TypedNumber('Short', this);
+Number.prototype['short'] = function() {
+ return new Data.TypedNumber('SHORT', this);
};
-Number.prototype['asUnsignedInteger'] = function() {
- return new Data.TypedNumber('UnsignedInteger', this);
+Number.prototype['uint'] = function() {
+ return new Data.TypedNumber('UINT', this);
};
-Number.prototype['asInteger'] = function() {
- return new Data.TypedNumber('Integer', this);
+Number.prototype['int'] = function() {
+ return new Data.TypedNumber('INT', this);
};
-Number.prototype['asUnsignedLong'] = function() {
- return new Data.TypedNumber('UnsignedLong', this);
+Number.prototype['ulong'] = function() {
+ return new Data.TypedNumber('ULONG', this);
};
-Number.prototype['asLong'] = function() {
- return new Data.TypedNumber('Long', this);
+Number.prototype['long'] = function() {
+ return new Data.TypedNumber('LONG', this);
};
-Number.prototype['asFloat'] = function() {
- return new Data.TypedNumber('Float', this);
+Number.prototype['float'] = function() {
+ return new Data.TypedNumber('FLOAT', this);
};
-Number.prototype['asDouble'] = function() {
- return new Data.TypedNumber('Double', this);
+Number.prototype['double'] = function() {
+ return new Data.TypedNumber('DOUBLE', this);
};
-Number.prototype['asChar'] = function() {
- return new Data.TypedNumber('Char', this);
+Number.prototype['char'] = function() {
+ return new Data.TypedNumber('CHAR', this);
};
-String.prototype['asChar'] = function() {
- return new Data.TypedNumber('Char', this.charCodeAt(0));
+String.prototype['char'] = function() {
+ return new Data.TypedNumber('CHAR', this.charCodeAt(0));
};
// ------------------------- proton.Data.TypedNumber --------------------------
@@ -1292,21 +1458,30 @@ String.prototype['asChar'] = function() {
* This class is a simple wrapper class that allows a "type" to be recorded for
* a number. The idea is that the JavaScript Number class is extended with extra
* methods to allow numbers to be "modified" to TypedNumbers, so for example
- * 1.0.asFloat() would modify 1.0 by returning a TypedNumber with type = Float
+ * 1.0.float() would modify 1.0 by returning a TypedNumber with type = FLOAT
* and value = 1. The strings used for type correspond to the names of the Data
- * put* methods e.g. UnsignedByte, Byte, UnsignedShort, Short, UnsignedInteger,
- * Integer, UnsignedLong, Long, Float, Double, Char so that the correct method
- * to call can be easily derived from the TypedNumber's type.
+ * put* methods e.g. UBYTE, BYTE, USHORT, SHORT, UINT, INT, ULONG, LONG, FLOAT,
+ * DOUBLE, CHAR so that the correct method to call can be derived from the type.
* @constructor proton.Data.TypedNumber
- * @param {string} type the type of the Number.
- * @param {number} value the most significant word.
+ * @param {(string|number)} type the type of the Number either as a string or number.
+ * Stored internally as a string corresponding to one of the TypeNames.
+ * @param {number} value the value of the Number.
*/
// Use dot notation as it is a "protected" inner class not exported from the closure.
Data.TypedNumber = function(type, value) { // Data.TypedNumber Constructor.
- this.type = type;
+ this.type = (typeof type === 'number') ? Data['TypeNames'][type] : type;
this.value = value;
};
+/**
+ * @method toString
+ * @memberof! proton.Data.TypedNumber#
+ * @returns {string} the String form of a {@link proton.Data.TypedNumber}.
+ */
+Data.TypedNumber.prototype.toString = Data.TypedNumber.prototype.valueOf = function() {
+ return +this.value;
+};
+
// ----------------------------- proton.Data.Long -----------------------------
/**
* Create a proton.Data.Long.
@@ -1345,7 +1520,7 @@ Data.Long.fromNumber = function(value) {
if (isNaN(value) || !isFinite(value)) {
return Data.Long.ZERO;
} else if (value <= -Data.Long.TWO_PWR_63_DBL_) {
- return Data.MIN_VALUE;
+ return Data.Long.MIN_VALUE;
} else if (value + 1 >= Data.Long.TWO_PWR_63_DBL_) {
return Data.Long.MAX_VALUE;
} else if (value < 0) {
@@ -1470,71 +1645,93 @@ Data.Long.prototype.toNumber = function() {
* @returns {string} the String form of a {@link proton.Data.Long}.
*/
Data.Long.prototype.toString = function() {
- return this.high + ":" + this.getLowBitsUnsigned();
+ return this.high + ':' + this.getLowBitsUnsigned();
};
// ---------------------------- proton.Data.Binary ----------------------------
/**
- * Create a proton.Data.Binary. This constructor takes one or two parameters,
- * size specifies the size in bytes of the Binary buffer, start is a pointer
- * to the data in an internal data store. If start is not specified then size
- * bytes will be allocated in the internal data store and start will point to
- * the start of that block of data.
+ * Create a proton.Data.Binary. This constructor takes one or two parameters.
+ * The first parameter may serve different purposes depending on its type;
+ * If value is a number then it represents the size of the Binary data buffer,
+ * if it is a string then we copy the string to the buffer, if it is an Array
+ * or a TypedArray then we copy the data to the buffer. The optional second
+ * parameter is a pointer to the data in an internal data store. If start is
+ * not specified then the number of bytes specified in the first parameter
+ * will be allocated in the internal data store and start will point to the
+ * start of that block of data.
* @classdesc
* This class represents an AMQP Binary type. This class allows us to create and
* use raw binary data and map it efficiently between JavaScript client code and
- * the underlying implementation, where all data is managed on a virtual heap.
+ * the underlying implementation, where all data is managed on a "virtual heap".
+ * <p>
+ * Client applications should generally not have to care about memory management
+ * as, for most common use cases, client applications would "transfer ownership"
+ * to a "container" which would then "own" the underlying data and free the data
+ * held by the {@link proton.Data.Binary}.
* <p>
- * Client applications should not have to care about memory management. A client
- * should create a {@link proton.Data.Binary} specifying the required size then
- * call getBuffer to access the underlying Uint8Array. When {@link proton.Data.putBinary}
- * is called ownership of the bytes transfers from the Binary to the Data and
- * putBinary can then safely call free. Conversely when receiving data a Binary
- * may be created by {@link proton.Data.getBinary} in this case the Binary is
- * simply a "view" onto the bytes owned by the Data instance. A client application
- * can safely access the bytes from the view, but if it wishes to use the bytes
- * beyond the scope of the Data instance (for example after the next
- * {@link proton.Messenger.get} call then the client must explicitly *copy* the
- * bytes into a new buffer via copyBuffer().
+ * As an example one common use-case would be where client application creates a
+ * {@link proton.Data.Binary} specifying the required size. It would usually then
+ * call getBuffer() to access the underlying Uint8Array. At this point the client
+ * "owns" the data and so would have to call free() if it did nothing more with
+ * the Binary, however when {@link proton.Data.putBINARY} is called the ownership
+ * of the raw data on the virtual heap transfers from the Binary to the Data and
+ * the client no longer needs to call free() itself. In this case the putBINARY()
+ * call transfers ownership and can then safely call free() on the Binary.
+ * <p>
+ * Conversely a common use-case when receiving data is where a Binary may be
+ * created by {@link proton.Data.getBINARY}. In this case the Binary is simply a
+ * "view" onto the bytes owned by the Data instance. A client application can
+ * safely access the bytes from the view, but if it wishes to use the bytes beyond
+ * the scope of the Data instance (e.g. after the next {@link proton.Messenger.get}
+ * call then the client must explicitly *copy* the bytes into a new buffer, for
+ * example via copyBuffer().
+ * <p>
+ * Most of the {@link proton.Data} methods that take {@link proton.Data.Binary}
+ * as a parameter "consume" the underlying data and take responsibility for
+ * freeing it from the heap {@link proton.Data.putBINARY} {@link proton.Data.decode}.
+ * For the methods that return a {@link proton.Data.Binary} the call to
+ * {@link proton.Data.getBINARY}, which is the most common case, returns a Binary
+ * that has a "view" of the underlying data that is actually owned by the Data
+ * instance and thus doesn't need to be explicitly freed on the Binary. The call
+ * to {@link proton.Data.encode} however returns a Binary that represents a *copy*
+ * of the underlying data, in this case (like a client calling new proton.Data.Binary)
+ * the client takes responsibility for freeing the data, unless of course it is
+ * subsequently passed to a method that will consume the data (putBINARY/decode).
* @constructor proton.Data.Binary
- * @param {object} data. If data is a number then it represents the size of the
- * Binary data buffer, if it is a string then we copy the string to the
- * buffer, if it is an Array or a TypedArray then we copy the data to
- * the buffer. N.B. although convenient do bear in mind that every method
- * other than constructing with a size followed by a call to getBuffer will
- * result in some form of additional data copy.
- * @param {number} start an optional data pointer to the start of the Binary data buffer.
- */
-Data['Binary'] = function(data, start) { // Data.Binary Constructor.
+ * @param {(number|string|Array|TypedArray)} value. If value is a number then it
+ * represents the size of the Binary data buffer, if it is a string then
+ * we copy the string to the buffer, if it is an Array or a TypedArray
+ * then we copy the data to the buffer. N.B. although convenient do bear
+ * in mind that using a mechanism other than constructing with a simple
+ * size will result in some form of additional data copy.
+ * @param {number} start an optional pointer to the start of the Binary data buffer.
+ */
+Data['Binary'] = function(value, start) { // Data.Binary Constructor.
/**
* If the start pointer is specified then the underlying binary data is owned
* by another object, so we set the call to free to be a null function. If
* the start pointer is not passed then we allocate storage of the specified
* size on the emscripten heap and set the call to free to free the data from
- * the emscripten heap. We have made the call to free a protected method that
- * is only visible within the scope of the binding closure, clients should
- * not have to call free themselves as the data is either already "owned" by
- * a Data object or is destined to be passed to a Data object, which will in
- * turn take responsibility for calling free once it has taken ownership of
- * the underlying binary data.
+ * the emscripten heap.
*/
- var size = data;
+ var size = value;
if (start) {
- this.free = function() {};
- } else { // Create Binary from Array, ArrayBuffer or TypedArray
- if (Data.isArray(data) ||
- (data instanceof ArrayBuffer) ||
- (data.buffer && data.buffer instanceof ArrayBuffer)) {
- data = new Uint8Array(data);
- size = data.length;
+ this['free'] = function() {};
+ } else { // Create Binary from Array, ArrayBuffer or TypedArray.
+ var hasArrayBuffer = (typeof ArrayBuffer === 'function');
+ if (Data.isArray(value) ||
+ (hasArrayBuffer && value instanceof ArrayBuffer) ||
+ (value.buffer && hasArrayBuffer && value.buffer instanceof ArrayBuffer)) {
+ value = new Uint8Array(value);
+ size = value.length;
start = _malloc(size); // Allocate storage from emscripten heap.
- Module.HEAPU8.set(data, start);
- } else if (Data.isString(data)) { // Create Binary from native string
- data = unescape(encodeURIComponent(data)); // Create a C-like UTF representation.
- size = data.length;
+ Module['HEAPU8'].set(value, start); // Copy the data to the emscripten heap.
+ } else if (Data.isString(value)) { // Create Binary from native string
+ value = unescape(encodeURIComponent(value)); // Create a C-like UTF representation.
+ size = value.length;
start = _malloc(size); // Allocate storage from emscripten heap.
for (var i = 0; i < size; i++) {
- setValue(start + i, data.charCodeAt(i), 'i8', 1);
+ setValue(start + i, value.charCodeAt(i), 'i8', 1);
}
} else { // Create unpopulated Binary of specified size.
// If the type is not a number by this point then an unrecognised data
@@ -1542,7 +1739,13 @@ Data['Binary'] = function(data, start) { // Data.Binary Constructor.
size = Data.isNumber(size) ? size : 0;
start = _malloc(size); // Allocate storage from emscripten heap.
}
- this.free = function() {_free(start);};
+ this['free'] = function() {
+ _free(this.start);
+ this.size = 0;
+ this.start = 0;
+ // Set free to a null function to prevent possibility of a "double free".
+ this['free'] = function() {};
+ };
}
this.size = size;
@@ -1562,16 +1765,28 @@ Data['Binary'].prototype['getBuffer'] = function() {
};
/**
- * Explicitly create a *copy* of the underlying binary data and present a Uint8Array
- * view of that copy. This method should be used if a client application wishes to
- * retain an interest in the binary data for longer than it wishes to retain an
- * interest in say a {@link proton.Message}, if that's not the case getBuffer
- * should be used as that avoids the need to copy the data.
- * @method copyBuffer
+ * Explicitly create a *copy* of the Binary copying the underlying binary data too.
+ * @method copy
+ * @param {number} offset an optional offset into the underlying buffer from
+ * where we want to copy the data, default is zero.
+ * @param {number} n an optional number of bytes to copy, default is this.size - offset.
* @memberof! proton.Data.Binary#
*/
-Data['Binary'].prototype['copyBuffer'] = function() {
- return new Uint8Array(new Uint8Array(HEAPU8.buffer, this.start, this.size));
+Data['Binary'].prototype['copy'] = function(offset, n) {
+ offset = offset | 0;
+ n = n ? n : (this.size - offset);
+
+ if (offset >= this.size) {
+ offset = 0;
+ n = 0;
+ } else if ((offset + n) > this.size) {
+ n = this.size - offset; // Clamp length
+ }
+
+ var start = _malloc(n); // Allocate storage from emscripten heap.
+ _memcpy(start, this.start + offset, n); // Copy the raw data to new buffer.
+
+ return new Data['Binary'](n, start);
};
/**
@@ -1648,9 +1863,8 @@ _Data_['clear'] = function() {
};
/**
- * 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.
+ * 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#
*/
@@ -1659,9 +1873,8 @@ _Data_['rewind'] = function() {
};
/**
- * 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.
+ * 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.
@@ -1671,14 +1884,13 @@ _Data_['next'] = function() {
if (found) {
return this.type();
} else {
- return null;
+ 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.
+ * 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.
@@ -1693,9 +1905,8 @@ _Data_['prev'] = function() {
};
/**
- * Sets the parent node to the current node and clears the current node.
- * Clearing the current node sets it _before_ the first child,
- * call next() advances to the first child.
+ * 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#
*/
@@ -1704,8 +1915,7 @@ _Data_['enter'] = function() {
};
/**
- * Sets the current node to the parent node and the parent node to
- * its own parent.
+ * Sets the current node to the parent node and the parent node to its own parent.
* @method exit
* @memberof! proton.Data#
*/
@@ -1713,10 +1923,13 @@ _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();
@@ -1725,6 +1938,7 @@ _Data_['lookup'] = function(name) {
return (lookup > 0);
};
+// TODO document - not quite sure what these are for?
_Data_['narrow'] = function() {
_pn_data_narrow(this._data);
};
@@ -1733,11 +1947,10 @@ _Data_['widen'] = function() {
_pn_data_widen(this._data);
};
-
/**
* @method type
* @memberof! proton.Data#
- * @returns the type of the current node or null if the type is unknown.
+ * @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);
@@ -1748,218 +1961,322 @@ _Data_['type'] = function() {
}
};
-// TODO encode and decode
+/**
+ * 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 type
+ * @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;
+ }
+ }
+};
/**
- * Puts a list value. Elements may be filled by entering the list
+ * 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 contianing 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>
- * data = new Data();
- * data.putList();
+ * var data = new proton.Data();
+ * data.putLISTNODE();
* data.enter();
- * data.putInt(1);
- * data.putInt(2);
- * data.putInt(3);
+ * data.putINT(1);
+ * data.putINT(2);
+ * data.putINT(3);
* data.exit();
* </pre>
- * @method putList
+ * @method putLISTNODE
* @memberof! proton.Data#
*/
-_Data_['putList'] = function() {
+_Data_['putLISTNODE'] = function() {
this._check(_pn_data_put_list(this._data));
};
/**
- * Puts a map value. Elements may be filled by entering the map node
+ * Puts a map node. Elements may be filled by entering the map node
* and putting alternating key value pairs.
* <pre>
- * data = new Data();
- * data.putMap();
+ * var data = new proton.Data();
+ * data.putMAPNODE();
* data.enter();
- * data.putString("key");
- * data.putString("value");
+ * data.putSTRING('key');
+ * data.putSTRING('value');
* data.exit();
* </pre>
- * @method putMap
+ * @method putMAPNODE
* @memberof! proton.Data#
*/
-_Data_['putMap'] = function() {
+_Data_['putMAPNODE'] = function() {
this._check(_pn_data_put_map(this._data));
};
-// TODO putArray and putDescribed
+/**
+ * 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
+ * @method putNULL
* @memberof! proton.Data#
*/
-_Data_['putNull'] = function() {
+_Data_['putNULL'] = function() {
this._check(_pn_data_put_null(this._data));
};
/**
* Puts a boolean value.
- * @method putBoolean
+ * @method putBOOL
* @memberof! proton.Data#
* @param {boolean} b a boolean value.
*/
-_Data_['putBoolean'] = function(b) {
+_Data_['putBOOL'] = function(b) {
this._check(_pn_data_put_bool(this._data, b));
};
/**
* Puts a unsigned byte value.
- * @method putUnsignedByte
+ * @method putUBYTE
* @memberof! proton.Data#
* @param {number} ub an integral value.
*/
-_Data_['putUnsignedByte'] = function(ub) {
+_Data_['putUBYTE'] = function(ub) {
this._check(_pn_data_put_ubyte(this._data, ub));
};
/**
* Puts a signed byte value.
- * @method putByte
+ * @method putBYTE
* @memberof! proton.Data#
* @param {number} b an integral value.
*/
-_Data_['putByte'] = function(b) {
+_Data_['putBYTE'] = function(b) {
this._check(_pn_data_put_byte(this._data, b));
};
/**
* Puts a unsigned short value.
- * @method putUnsignedShort
+ * @method putUSHORT
* @memberof! proton.Data#
* @param {number} us an integral value.
*/
-_Data_['putUnsignedShort'] = function(us) {
+_Data_['putUSHORT'] = function(us) {
this._check(_pn_data_put_ushort(this._data, us));
};
/**
* Puts a signed short value.
- * @method putShort
+ * @method putSHORT
* @memberof! proton.Data#
* @param {number} s an integral value.
*/
-_Data_['putShort'] = function(s) {
+_Data_['putSHORT'] = function(s) {
this._check(_pn_data_put_short(this._data, s));
};
/**
* Puts a unsigned integer value.
- * @method putUnsignedInteger
+ * @method putUINT
* @memberof! proton.Data#
* @param {number} ui an integral value.
*/
-_Data_['putUnsignedInteger'] = function(ui) {
+_Data_['putUINT'] = function(ui) {
this._check(_pn_data_put_uint(this._data, ui));
};
/**
* Puts a signed integer value.
- * @method putInteger
+ * @method putINT
* @memberof! proton.Data#
* @param {number} i an integral value.
*/
-_Data_['putInteger'] = function(i) {
+_Data_['putINT'] = function(i) {
this._check(_pn_data_put_int(this._data, i));
};
/**
* Puts a signed char value.
- * @method putChar
+ * @method putCHAR
* @memberof! proton.Data#
- * @param {number} c a single character.
+ * @param {(string|number)} c a single character expressed either as a string or a number.
*/
-_Data_['putChar'] = function(c) {
+_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.
- * @method putUnsignedLong
+ * 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_['putUnsignedLong'] = function(ul) {
- this._check(_pn_data_put_ulong(this._data, ul));
+_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.
- * @method putLong
+ * 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) {
-console.log("putLong " + l);
-
+_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
+ * @method putTIMESTAMP
* @memberof! proton.Data#
- * @param {number} t an integral value.
+ * @param {Date} d a Date value.
*/
-_Data_['putTimestamp'] = function(t) {
-console.log("putTimestamp not properly implemented yet");
- this._check(_pn_data_put_timestamp(this._data, t));
+_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.
- * @method putFloat
+ * 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) {
-console.log("putFloat f = " + f);
+_Data_['putFLOAT'] = function(f) {
this._check(_pn_data_put_float(this._data, f));
};
/**
* Puts a double value.
- * @method putDouble
+ * @method putDOUBLE
* @memberof! proton.Data#
* @param {number} d a floating point value.
*/
-_Data_['putDouble'] = function(d) {
+_Data_['putDOUBLE'] = function(d) {
this._check(_pn_data_put_double(this._data, d));
};
/**
* Puts a decimal32 value.
- * @method putDecimal32
+ * @method putDECIMAL32
* @memberof! proton.Data#
* @param {number} d a decimal32 value.
*/
-_Data_['putDecimal32'] = function(d) {
+_Data_['putDECIMAL32'] = function(d) {
this._check(_pn_data_put_decimal32(this._data, d));
};
/**
* Puts a decimal64 value.
- * @method putDecimal64
+ * @method putDECIMAL64
* @memberof! proton.Data#
* @param {number} d a decimal64 value.
*/
-_Data_['putDecimal64'] = function(d) {
+_Data_['putDECIMAL64'] = function(d) {
this._check(_pn_data_put_decimal64(this._data, d));
};
/**
* Puts a decimal128 value.
- * @method putDecimal128
+ * @method putDECIMAL128
* @memberof! proton.Data#
* @param {number} d a decimal128 value.
*/
-_Data_['putDecimal128'] = function(d) {
+_Data_['putDECIMAL128'] = function(d) {
this._check(_pn_data_put_decimal128(this._data, d));
};
@@ -1967,7 +2284,7 @@ _Data_['putDecimal128'] = function(d) {
* Puts a UUID value.
* @method putUUID
* @memberof! proton.Data#
- * @param {proton.Data.UUID} u a uuid value
+ * @param {proton.Data.Uuid} u a uuid value
*/
_Data_['putUUID'] = function(u) {
var sp = Runtime.stackSave();
@@ -1976,12 +2293,12 @@ _Data_['putUUID'] = function(u) {
};
/**
- * Puts a binary value.
- * @method putBinary
+ * 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) {
+_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.
@@ -1999,20 +2316,20 @@ _Data_['putBinary'] = function(b) {
// 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
+ // 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();
+ b['free']();
Runtime.stackRestore(sp);
};
/**
* Puts a unicode string value.
- * @method putString
+ * @method putSTRING
* @memberof! proton.Data#
* @param {string} s a unicode string value.
*/
-_Data_['putString'] = function(s) {
+_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.
@@ -2045,11 +2362,11 @@ _Data_['putString'] = function(s) {
* 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
+ * @method putSYMBOL
* @memberof! proton.Data#
- * @param {proton.Data.Symbol} s the symbol name.
+ * @param {proton.Data.Symbol|string} s the symbol name.
*/
-_Data_['putSymbol'] = function(s) {
+_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.
@@ -2076,116 +2393,220 @@ _Data_['putSymbol'] = function(s) {
Runtime.stackRestore(sp);
};
-// TODO getArray and isDescribed
+/**
+ * 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
+ * @method getNULL
* @memberof! proton.Data#
- * @return a null value.
+ * @returns a null value.
*/
-_Data_['getNull'] = function() {
+_Data_['getNULL'] = function() {
return null;
};
/**
* Checks if the current node is a null.
- * @method isNull
+ * @method isNULL
* @memberof! proton.Data#
* @returns {boolean} true iff the current node is null.
*/
-_Data_['isNull'] = function() {
+_Data_['isNULL'] = function() {
return (_pn_data_is_null(this._data) > 0);
};
/**
- * @method getBoolean
+ * @method getBOOL
* @memberof! proton.Data#
* @returns {boolean} a boolean value if the current node is a boolean, returns
* false otherwise.
*/
-_Data_['getBoolean'] = function() {
+_Data_['getBOOL'] = function() {
return (_pn_data_get_bool(this._data) > 0);
};
/**
- * @method getUnsignedByte
+ * @method getUBYTE
* @memberof! proton.Data#
* @returns {number} value if the current node is an unsigned byte, returns 0 otherwise.
*/
-_Data_['getUnsignedByte'] = function() {
+_Data_['getUBYTE'] = function() {
return _pn_data_get_ubyte(this._data) & 0xFF; // & 0xFF converts to unsigned;
};
/**
- * @method getByte
+ * @method getBYTE
* @memberof! proton.Data#
* @returns {number} value if the current node is a signed byte, returns 0 otherwise.
*/
-_Data_['getByte'] = function() {
+_Data_['getBYTE'] = function() {
return _pn_data_get_byte(this._data);
};
/**
- * @return value if the current node is an unsigned short, returns 0 otherwise.
+ * @method getUSHORT
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is an unsigned short, returns 0 otherwise.
*/
-_Data_['getUnsignedShort'] = function() {
+_Data_['getUSHORT'] = function() {
return _pn_data_get_ushort(this._data) & 0xFFFF; // & 0xFFFF converts to unsigned;
};
/**
- * @method getShort
+ * @method getSHORT
* @memberof! proton.Data#
* @returns {number} value if the current node is a signed short, returns 0 otherwise.
*/
-_Data_['getShort'] = function() {
+_Data_['getSHORT'] = function() {
return _pn_data_get_short(this._data);
};
/**
- * @method getUnsignedInteger
+ * @method getUINT
* @memberof! proton.Data#
* @returns {number} value if the current node is an unsigned int, returns 0 otherwise.
*/
-_Data_['getUnsignedInteger'] = function() {
+_Data_['getUINT'] = function() {
var value = _pn_data_get_uint(this._data);
return (value > 0) ? value : 4294967296 + value; // 4294967296 == 2^32
};
/**
- * @method getInteger
+ * @method getINT
* @memberof! proton.Data#
* @returns {number} value if the current node is a signed int, returns 0 otherwise.
*/
-_Data_['getInteger'] = function() {
- return _pn_data_put_int(this._data);
+_Data_['getINT'] = function() {
+ return _pn_data_get_int(this._data);
};
/**
- * @method getChar
+ * @method getCHAR
* @memberof! proton.Data#
* @returns {string} the character represented by the unicode value of the current node.
*/
-_Data_['getChar'] = function() {
+_Data_['getCHAR'] = function() {
return String.fromCharCode(_pn_data_get_char(this._data));
};
/**
- * @method getUnsignedLong
+ * 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 {number} value if the current node is an unsigned long, returns 0 otherwise.
+ * @returns {proton.Data.Long} value if the current node is an unsigned long, returns 0 otherwise.
*/
-_Data_['getUnsignedLong'] = function() {
-console.log("getUnsignedLong");
- return _pn_data_get_ulong(this._data);
+_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;
};
/**
- * @method getLong
+ * 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 {number} value if the current node is a signed long, returns 0 otherwise.
+ * @returns {proton.Data.Long} value if the current node is a signed long, returns 0 otherwise.
*/
-_Data_['getLong'] = function() {
-console.log("getLong");
+_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
@@ -2195,75 +2616,81 @@ console.log("getLong");
var high = Runtime.getTempRet0();
var long = new Data.Long(low, high);
long = long.toNumber();
-
-console.log("Data.getLong() long = " + long);
-
return long;
};
/**
- * @method getTimestamp
+ * @method getTIMESTAMP
* @memberof! proton.Data#
- * @returns {number} value if the current node is a timestamp, returns 0 otherwise.
+ * @returns {Date} a native JavaScript Date instance representing the timestamp.
*/
-_Data_['getTimestamp'] = function() {
-console.log("getTimestamp not properly implemented yet");
-return 123456;
- //return _pn_data_get_timestamp(this._data);
+_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);
};
/**
- * @method getFloat
+ * 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() {
+_Data_['getFLOAT'] = function() {
return _pn_data_get_float(this._data);
};
/**
- * @method getDouble
+ * @method getDOUBLE
* @memberof! proton.Data#
* @returns {number} value if the current node is a double, returns 0 otherwise.
*/
-_Data_['getDouble'] = function() {
+_Data_['getDOUBLE'] = function() {
return _pn_data_get_double(this._data);
};
/**
- * @method getDecimal32
+ * @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");
+_Data_['getDECIMAL32'] = function() {
+console.log("getDECIMAL32 not properly implemented yet");
return _pn_data_get_decimal32(this._data);
};
/**
- * @method getDecimal64
+ * @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");
+_Data_['getDECIMAL64'] = function() {
+console.log("getDECIMAL64 not properly implemented yet");
return _pn_data_get_decimal64(this._data);
};
/**
- * @method getDecimal128
+ * @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");
+_Data_['getDECIMAL128'] = function() {
+console.log("getDECIMAL128 not properly implemented yet");
return _pn_data_get_decimal128(this._data);
};
/**
* @method getUUID
* @memberof! proton.Data#
- * @return {proton.Data.UUID} value if the current node is a UUID, returns null otherwise.
+ * @returns {proton.Data.Uuid} value if the current node is a UUID, returns null otherwise.
*/
_Data_['getUUID'] = function() {
var sp = Runtime.stackSave();
@@ -2277,7 +2704,7 @@ _Data_['getUUID'] = function() {
_pn_data_get_uuid(bytes, this._data);
// Create a new UUID from the bytes
- var uuid = new Data['UUID'](bytes);
+ var uuid = new Data['Uuid'](bytes);
// Tidy up the memory that we allocated on emscripten's stack.
Runtime.stackRestore(sp);
@@ -2286,11 +2713,11 @@ _Data_['getUUID'] = function() {
};
/**
- * @method getBinary
+ * @method getBINARY
* @memberof! proton.Data#
* @returns {proton.Data.Binary} value if the current node is a Binary, returns null otherwise.
*/
-_Data_['getBinary'] = function() {
+_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.
@@ -2322,11 +2749,11 @@ _Data_['getBinary'] = function() {
/**
* Gets a unicode String value from the current node.
- * @method getString
+ * @method getSTRING
* @memberof! proton.Data#
- * @return {string} value if the current node is a String, returns "" otherwise.
+ * @returns {string} value if the current node is a String, returns "" otherwise.
*/
-_Data_['getString'] = function() {
+_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.
@@ -2362,11 +2789,11 @@ _Data_['getString'] = function() {
* 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
+ * @method getSYMBOL
* @memberof! proton.Data#
- * @return {proton.Data.Symbol} value if the current node is a Symbol, returns "" otherwise.
+ * @returns {proton.Data.Symbol} value if the current node is a Symbol, returns "" otherwise.
*/
-_Data_['getSymbol'] = function() {
+_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.
@@ -2396,18 +2823,65 @@ _Data_['getSymbol'] = function() {
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;
+};
-// TODO copy, format and dump
+/**
+ * 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 size = 1024; // Pass by reference variable - need to use setValue to initialise it.
+ while (true) {
+ setValue(size, size, 'i32'); // Set pass by reference variable.
+ var bytes = _malloc(size); // Allocate storage from emscripten heap.
+ var err = _pn_data_format(this._data, bytes, size);
+ var size = getValue(size, 'i32'); // Dereference the real size value;
+
+ if (err === Module['Error']['OVERFLOW']) {
+ _free(bytes);
+ size *= 2;
+ } else {
+ var string = Pointer_stringify(bytes);
+ _free(bytes);
+ 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 putDictionary
+ * @method putMAP
* @memberof! proton.Data#
* @param {object} object the Native JavaScript Object that we wish to serialise.
*/
-_Data_['putDictionary'] = function(object) {
- this['putMap']();
+_Data_['putMAP'] = function(object) {
+ this['putMAPNODE']();
this['enter']();
for (var key in object) {
if (object.hasOwnProperty(key)) {
@@ -2420,18 +2894,18 @@ _Data_['putDictionary'] = function(object) {
/**
* Deserialise from an AMQP Map into a Native JavaScript Object.
- * @method getDictionary
+ * @method getMAP
* @memberof! proton.Data#
* @returns {object} the deserialised Native JavaScript Object.
*/
-_Data_['getDictionary'] = function() {
+_Data_['getMAP'] = function() {
if (this['enter']()) {
var result = {};
while (this['next']()) {
var key = this['getObject']();
var value = null;
if (this['next']()) {
- value = this['getObject']()
+ value = this['getObject']();
}
result[key] = value;
}
@@ -2442,26 +2916,26 @@ _Data_['getDictionary'] = function() {
/**
* Serialise a Native JavaScript Array into an AMQP List.
- * @method putJSArray
+ * @method putLIST
* @memberof! proton.Data#
* @param {Array} array the Native JavaScript Array that we wish to serialise.
*/
-_Data_['putJSArray'] = function(array) {
- this['putList']();
+_Data_['putLIST'] = function(array) {
+ this['putLISTNODE']();
this['enter']();
for (var i = 0, len = array.length; i < len; i++) {
- this['putObject'](array[i])
+ this['putObject'](array[i]);
}
this['exit']();
};
/**
* Deserialise from an AMQP List into a Native JavaScript Array.
- * @method getJSArray
+ * @method getLIST
* @memberof! proton.Data#
- * @returns {array} the deserialised Native JavaScript Array.
+ * @returns {Array} the deserialised Native JavaScript Array.
*/
-_Data_['getJSArray'] = function() {
+_Data_['getLIST'] = function() {
if (this['enter']()) {
var result = [];
while (this['next']()) {
@@ -2473,6 +2947,150 @@ _Data_['getJSArray'] = function() {
};
/**
+ * 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
@@ -2485,32 +3103,33 @@ _Data_['getJSArray'] = function() {
_Data_['putObject'] = function(obj) {
console.log("Data.putObject");
-
console.log("obj = " + obj);
//console.log("typeof obj = " + (typeof obj));
//console.log("obj prototype = " + Object.prototype.toString.call(obj));
if (obj == null) { // == Checks for null and undefined.
-console.log("obj is null");
- this['putNull']();
+ this['putNULL']();
} else if (Data.isString(obj)) {
-console.log("obj is String");
-
var quoted = obj.match(/(['"])[^'"]*\1/);
- if (quoted) {
- quoted = quoted[0].slice(1, -1);
-console.log("obj is quoted String " + quoted);
- this['putString'](quoted);
- } else {
- // TODO check for stringified numbers.
- this['putString'](obj);
- }
- } else if (obj instanceof Data['UUID']) {
+ 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);
+ this['putBINARY'](obj);
} else if (obj instanceof Data['Symbol']) {
- this['putSymbol'](obj);
+ 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);
@@ -2519,42 +3138,37 @@ console.log("obj is quoted String " + quoted);
* 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
+ * 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. JavaScript automagically coerces floating
- * point numbers with a zero Fractional Part into an exact integer so
+ * 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 require, for example 1.0.asFloat()
- * (1).asUnsignedByte(), (5).asLong() etc.
+ * to express more explicitly what is required, for example (1.0).float()
+ * (1).ubyte(), (5).long() etc.
*/
if (obj % 1 === 0) {
-console.log(obj + " is Integer Type " + (obj|0));
if (obj === (obj|0)) { // the |0 coerces to a 32 bit value.
- // 32 bit integer - encode as an Integer.
-console.log(obj + " is Int ");
- this['putInteger'](obj);
+ // 32 bit integer - encode as an INT.
+ this['putINT'](obj);
} else { // Longer than 32 bit - encode as a Long.
-console.log(obj + " is Long");
- this['putLong'](obj);
+ this['putLONG'](obj);
}
} else { // Floating point type - encode as a Double
-console.log(obj + " is Float Type");
- this['putDouble'](obj);
+ this['putDOUBLE'](obj);
}
} else if (Data.isBoolean(obj)) {
- this['putBoolean'](obj);
+ this['putBOOL'](obj);
} else if (Data.isArray(obj)) { // Native JavaScript Array
- this['putJSArray'](obj);
+ this['putLIST'](obj);
} else {
- this['putDictionary'](obj);
+ this['putMAP'](obj);
}
};
-_Data_.putObject = _Data_['putObject'];
/**
* @method getObject
@@ -2562,18 +3176,10 @@ _Data_.putObject = _Data_['putObject'];
* @returns {object} the JavaScript Object or primitive being deserialised.
*/
_Data_['getObject'] = function() {
-console.log("Data.getObject: not fully implemented yet");
-
- var type = this.type();
-console.log("type = " + type);
-
- var getter = Data.GetMappings[type];
-
-console.log("getter = " + getter);
-
+ var type = Data['TypeNames'][this.type()];
+ type = type ? type : 'NULL';
+ var getter = 'get' + type;
return this[getter]();
};
-_Data_.getObject = _Data_['getObject'];
-
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6aed8542/proton-c/bindings/javascript/data-test.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/data-test.js b/proton-c/bindings/javascript/data-test.js
deleted file mode 100644
index 6904bc9..0000000
--- a/proton-c/bindings/javascript/data-test.js
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.
- *
- */
-
-/**
- * Unit tests for the Data Class.
- * TODO this is just some random stuff at the moment - need to port the python codec test.
- */
-
-// Check if the environment is Node.js and if so import the required library.
-if (typeof exports !== "undefined" && exports !== null) {
- proton = require("../../../bld/proton-c/bindings/javascript/proton.js");
-}
-
-
-try {
-
- var messenger = new proton.Messenger();
-
- console.log("name = " + messenger.getName());
-
- console.log("timeout = " + messenger.getTimeout());
-
- console.log("isBlocking = " + messenger.isBlocking());
-
- messenger.setIncomingWindow(1234);
- console.log("incoming window = " + messenger.getIncomingWindow());
-
- messenger.setOutgoingWindow(5678);
- console.log("outgoing window = " + messenger.getOutgoingWindow());
-
-
- messenger.start();
- console.log("isStopped = " + messenger.isStopped());
-
-
- //messenger.subscribe("amqp://narnia");
- var subscription = messenger.subscribe("amqp://~0.0.0.0");
- console.log("subscription address = " + subscription.getAddress());
-
-
- var message = new proton.Message();
- message.setAddress("amqp://localhost:5672");
- console.log("message address = " + message.getAddress());
-
- message.setSubject("UK.WEATHER");
- console.log("message subject = " + message.getSubject());
-
-
- messenger.stop();
- console.log("isStopped = " + messenger.isStopped());
-
-
-
- message.free();
-
- messenger.free();
-
-} catch(e) {
- console.log("Caught Exception " + e);
-}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org