blob: 5bb2d887f04a4853b21d4d1b429b1f833506d322 [file] [log] [blame] [edit]
/**
* @fileoverview Internal utilities for working with buffers.
* @package
*
* DO NOT USE THIS OUTSIDE OF THIS PACKAGE.
*/
goog.module('jspb.binary.internal_buffer');
const {ByteSource} = goog.require('jspb.binary.bytesource');
const {ByteString} = goog.require('jspb.bytestring');
const {decodeByteArray} = goog.require('jspb.internal_bytes');
const {unsafeByteStringFromUint8Array, unsafeUint8ArrayFromByteString} = goog.require('jspb.unsafe_bytestring');
class Buffer {
constructor(/** !Uint8Array */ buffer, /** boolean */ isImmutable,
/** !ByteString= */ maybeByteString) {
/** @const {!Uint8Array}*/
this.buffer = buffer;
/** @private {!ByteString|undefined} */
this.bufferAsByteStringInternal = maybeByteString;
if (maybeByteString && !isImmutable) {
throw goog.DEBUG ?
new Error('Buffer must be immutable if a ByteString is provided.') :
new Error();
}
/**
* Whether our input must be immutable and we cannot allow callers to
* mutate it.
*
* @const {boolean}
*/
this.isImmutable = isImmutable;
}
/** @return {?ByteString} */
getBufferAsByteStringIfImmutable() {
if (!this.isImmutable) {
throw goog.DEBUG ?
new Error('Cannot get ByteString from mutable buffer.') :
new Error();
}
if (this.buffer == null) return null;
return this.bufferAsByteStringInternal ??=
unsafeByteStringFromUint8Array(this.buffer);
}
}
/**
* Converts any type defined in ByteSource into a Uint8Array.
* @param {!ByteSource|!ByteString} data
* @param {boolean} treatNewDataAsImmutable Whether to treat new data as
* immutable.
* @return {!Buffer} a tuple of the data and
* whether or not this is an immutable reference
*/
function bufferFromSource(data, treatNewDataAsImmutable) {
if (typeof data === 'string') {
return new Buffer(decodeByteArray(data), treatNewDataAsImmutable);
} else if (Array.isArray(data)) {
return new Buffer(new Uint8Array(data), treatNewDataAsImmutable);
} else if (data.constructor === Uint8Array) {
const u8 = /** @type {!Uint8Array}*/ (data);
return new Buffer(u8, /* isImmutable= */ false);
} else if (data.constructor === ArrayBuffer) {
const u8 = new Uint8Array(/** @type {!ArrayBuffer} */ (data));
return new Buffer(u8, /* isImmutable= */ false);
} else if (data.constructor === ByteString) {
const byteString = /** @type {!ByteString} */ (data);
const u8 = unsafeUint8ArrayFromByteString(byteString);
return new Buffer(u8, /* isImmutable= */ true, byteString);
} else if (data instanceof Uint8Array) {
// If this is a node subclass, wrap a new Uint8Array around the buffer to
// ensure jspb code only ever deals with Uint8Array exactly to ensure
// monomorphism.
const u8 = (data.constructor === Uint8Array) ?
data :
new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
return new Buffer(u8, /* isImmutable= */ false);
} else {
throw goog.DEBUG ?
new Error(
'Type not convertible to a Uint8Array, expected a Uint8Array, an ' +
'ArrayBuffer, a base64 encoded string, a ByteString or an Array of ' +
'numbers') :
new Error();
}
}
exports = {
Buffer,
bufferFromSource,
};