Skip to content

Commit

Permalink
Simplify InputStream constructor in JS (#3102)
Browse files Browse the repository at this point in the history
  • Loading branch information
bernardnormier authored Nov 8, 2024
1 parent 45b3661 commit 5cb7dfc
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 232 deletions.
55 changes: 0 additions & 55 deletions js/src/Ice/InputStream.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,6 @@ declare module "ice" {
* The InputStream class provides methods for decoding Slice encoded data from a stream of bytes.
*/
class InputStream {
/**
* Constructs an empty input stream that uses the default encoding version 1.1.
*
* @remarks An InputStream constructed without a communicator cannot be used to unmarshal proxies,
* or class instances.
*/
constructor();

/**
* Constructs an input stream that uses the default encoding version 1.1, and the given buffer.
*
* @param buffer The buffer containing the encoded data.
*
* @remarks An InputStream constructed without a communicator cannot be used to unmarshal proxies,
* or class instances.
*/
constructor(buffer: Uint8Array);

/**
* Constructs an empty input stream that uses the communicator's encoding version 1.1.
*
* @param communicator The communicator that provides the encoding version, the logger, and the value
* factory manager.
*/
constructor(communicator: Communicator);

/**
* Constructs input stream that uses the communicator's encoding version 1.1, and the given buffer.
*
Expand All @@ -43,35 +17,6 @@ declare module "ice" {
*/
constructor(communicator: Communicator, buffer: Uint8Array);

/**
* Constructs an empty input stream that uses the given encoding version.
*
* @param encoding The encoding version.
*
* @remarks An InputStream constructed without a communicator cannot be used to unmarshal proxies,
* or class instances.
*/
constructor(encoding: EncodingVersion);

/**
* Constructs an input stream that uses the given encoding version, and the given buffer.
*
* @param encoding The encoding version.
* @param buffer The buffer containing the encoded data.
*
* @remarks An InputStream constructed without a communicator cannot be used to unmarshal proxies,
* or class instances.
*/
constructor(encoding: EncodingVersion, buffer: Uint8Array);

/**
* Constructs an empty input stream that uses the given encoding version and the given communicator.
*
* @param communicator The communicator that provides the logger, and the value factory manager.
* @param encoding The encoding version.
*/
constructor(communicator: Communicator, encoding: EncodingVersion);

/**
* Constructs an input stream that uses the given encoding version, the given communicator, and the given buffer.
*
Expand Down
248 changes: 71 additions & 177 deletions js/src/Ice/InputStream.js
Original file line number Diff line number Diff line change
Expand Up @@ -442,9 +442,8 @@ class EncapsDecoder10 extends EncapsDecoder {
}

class EncapsDecoder11 extends EncapsDecoder {
constructor(stream, encaps, classGraphDepth, f, r) {
constructor(stream, encaps, classGraphDepth, f) {
super(stream, encaps, classGraphDepth, f);
this._compactIdResolver = r;
this._current = null;
this._valueIdIndex = 1;
}
Expand Down Expand Up @@ -744,24 +743,7 @@ class EncapsDecoder11 extends EncapsDecoder {
//
// Translate a compact (numeric) type ID into a string type ID.
//
this._current.typeId = "";
if (this._compactIdResolver !== null) {
try {
this._current.typeId = this._compactIdResolver.call(null, this._current.compactId);
} catch (ex) {
if (!(ex instanceof LocalException)) {
throw new MarshalException(
"exception in CompactIdResolver for ID " + this._current.compactId,
{ cause: ex },
);
}
throw ex;
}
}

if (this._current.typeId.length === 0) {
this._current.typeId = this._stream.resolveCompactId(this._current.compactId);
}
this._current.typeId = this._stream.resolveCompactId(this._current.compactId);
}

if (this._current.typeId.length > 0) {
Expand Down Expand Up @@ -928,98 +910,75 @@ class PatchEntry {

export class InputStream {
constructor(arg1, arg2, arg3) {
const args = {
instance: null,
encoding: null,
bytes: null,
buffer: null,
};
this._checkArgs([arg1, arg2, arg3], args);
this._initialize(args);
}

_checkArgs(arr, args) {
//
// The constructor can accept a variety of argument combinations:
//
// ()
// (communicator)
// (instance)
// (encoding)
// (array)
// (buffer)
// (communicator, encoding)
// (instance, encoding)
// (communicator, array)
// (instance, array)
// (communicator, buffer)
// (instance, buffer)
// (communicator, encoding, array)
// (instance, encoding, array)
// (communicator, encoding, buffer)
// (instance, encoding, buffer)
// (encoding, array)
// (encoding, buffer)
//
arr.forEach(arg => {
if (arg !== null && arg !== undefined) {
if (arg.constructor === Communicator) {
args.instance = arg.instance;
} else if (arg.constructor === Instance) {
args.instance = arg;
} else if (arg.constructor === EncodingVersion) {
args.encoding = arg;
} else if (arg.constructor === Buffer) {
args.buffer = arg;
} else if (arg.constructor === ArrayBuffer) {
args.bytes = arg;
} else if (arg.constructor === Uint8Array) {
args.bytes = arg.buffer;
} else {
throw new InitializationException("unknown argument to InputStream constructor");
// The first argument must be a Communicator or an Instance.
if (arg1 === null || arg1 === undefined) {
throw new InitializationException("missing argument(s) for InputStream constructor");
}

if (arg1.constructor === Instance) {
// (instance, encoding) or (instance, encoding, buffer)

this._instance = arg1;
if (arg2 === null || arg2 === undefined || arg2.constructor !== EncodingVersion) {
throw new InitializationException(
"expected the encoding version as the second argument to the InputStream constructor",
);
}
this._encoding = arg2;

if (arg3 === undefined || arg3 === null) {
this._buf = new Buffer();
} else if (arg3.constructor === Buffer) {
this._buf = arg3;
} else {
throw new InitializationException("unknown third argument to InputStream constructor");
}
} else if (arg1.constructor === Communicator) {
// (communicator, encoding, buffer) or (communicator, buffer), with two flavors for buffer
this._instance = arg1.instance;

[arg2, arg3].forEach(arg => {
if (arg !== null && arg !== undefined) {
if (arg.constructor === EncodingVersion) {
if (this._encoding !== undefined) {
throw new InitializationException(
"expected buffer as the third argument to InputStream constructor",
);
}
this._encoding = arg;
} else if (arg.constructor === ArrayBuffer) {
if (this._buf !== undefined) {
throw new InitializationException("duplicate buffer argument to InputStream constructor");
}
this._buf = new Buffer(arg.bytes);
} else if (arg.constructor === Uint8Array) {
if (this._buf !== undefined) {
throw new InitializationException("duplicate buffer argument to InputStream constructor");
}
this._buf = new Buffer(arg.buffer);
} else {
throw new InitializationException("unknown argument to InputStream constructor");
}
}
});

if (this._buf === undefined) {
throw new InitializationException("missing buffer argument to InputStream constructor");
}
});
if (args.buffer !== null && args.bytes !== null) {
throw new InitializationException("invalid argument to InputStream constructor");
this._encoding ??= this._instance.defaultsAndOverrides().defaultEncoding;
} else {
throw new InitializationException("unknown first argument to InputStream constructor");
}
}

_initialize(args) {
this._instance = args.instance;
this._encoding = args.encoding;
this._encapsStack = null;
this._encapsCache = null;
this._closure = null;
this._startSeq = -1;
this._sizePos = -1;
this._compactIdResolver = null;

if (this._instance !== null) {
if (this._encoding === null) {
this._encoding = this._instance.defaultsAndOverrides().defaultEncoding;
}
this._traceSlicing = this._instance.traceLevels().slicing > 0;
this._valueFactoryManager = this._instance.initializationData().valueFactoryManager;
this._logger = this._instance.initializationData().logger;
this._classGraphDepthMax = this._instance.classGraphDepthMax();
} else {
if (this._encoding === null) {
this._encoding = Protocol.currentEncoding;
}
this._traceSlicing = false;
this._valueFactoryManager = null;
this._logger = null;
this._classGraphDepthMax = 0x7fffffff;
}

if (args.bytes !== null) {
this._buf = new Buffer(args.bytes);
} else if (args.buffer !== null) {
this._buf = args.buffer;
} else {
this._buf = new Buffer();
}
this._valueFactoryManager = this._instance.initializationData().valueFactoryManager;
this._logger = this._instance.initializationData().logger;
this._classGraphDepthMax = this._instance.classGraphDepthMax();
}

clear() {
Expand All @@ -1037,29 +996,23 @@ export class InputStream {
swap(other) {
Debug.assert(this._instance === other._instance);

// These are cached values derived from instance.
Debug.assert(this._classGraphDepthMax === other._classGraphDepthMax);
Debug.assert(this._valueFactoryManager === other._valueFactoryManager);
Debug.assert(this._logger === other._logger);

[other._buf, this._buf] = [this._buf, other._buf];
[other._encoding, this._encoding] = [this._encoding, other._encoding];
[other._traceSlicing, this._traceSlicing] = [this._traceSlicing, other._traceSlicing];
[other._closure, this._closure] = [this._closure, other.closure];
[other._classGraphDepthMax, this._classGraphDepthMax] = [this._classGraphDepthMax, other._classGraphDepthMax];

//
[other._startSeq, this._startSeq] = [this._startSeq, other._startSeq];
[other._minSeqSize, this._minSeqSize] = [this._minSeqSize, other._minSeqSize];
[other._sizePos, this._sizePos] = [this._sizePos, other._sizePos];

// Swap is never called for InputStreams that have encapsulations being read/write. However,
// encapsulations might still be set in case marshaling or unmarshaling failed. We just
// reset the encapsulations if there are still some set.
//
this.resetEncapsulation();
other.resetEncapsulation();

[other._startSeq, this._startSeq] = [this._startSeq, other._startSeq];
[other._minSeqSize, this._minSeqSize] = [this._minSeqSize, other._minSeqSize];
[other._sizePos, this._sizePos] = [this._sizePos, other._sizePos];
[other._valueFactoryManager, this._valueFactoryManager] = [
this._valueFactoryManager,
other._valueFactoryManager,
];
[other._logger, this._logger] = [this._logger, other._logger];
[other._compactIdResolver, this._compactIdResolver] = [this._compactIdResolver, other._compactIdResolver];
}

resetEncapsulation() {
Expand Down Expand Up @@ -1677,14 +1630,13 @@ export class InputStream {
this._encapsStack,
this._classGraphDepthMax,
this._valueFactoryManager,
this._compactIdResolver,
);
}
}
}

traceSkipSlice(typeId, sliceType) {
if (this._traceSlicing && this._logger !== null) {
if (this._instance.traceLevels().slicing > 0 && this._logger !== null) {
traceSlicing(
sliceType === SliceType.ExceptionSlice ? "exception" : "object",
typeId,
Expand All @@ -1694,56 +1646,6 @@ export class InputStream {
}
}

//
// Sets the value factory manager to use when marshaling value instances. If the stream
// was initialized with a communicator, the communicator's value factory manager will
// be used by default.
//
get valueFactoryManager() {
return this._valueFactoryManager;
}

set valueFactoryManager(value) {
this._valueFactoryManager = value !== undefined ? value : null;
}

//
// Sets the logger to use when logging trace messages. If the stream
// was initialized with a communicator, the communicator's logger will
// be used by default.
//
get logger() {
return this._logger;
}

set logger(value) {
this._logger = value !== undefined ? value : null;
}

//
// Sets the compact ID resolver to use when unmarshaling value and exception
// instances. If the stream was initialized with a communicator, the communicator's
// resolver will be used by default.
//
get compactIdResolver() {
return this._compactIdResolver;
}

set compactIdResolver(value) {
this._compactIdResolver = value !== undefined ? value : null;
}

//
// Determines whether the stream logs messages about slicing instances of Slice values.
//
get traceSlicing() {
return this._traceSlicing;
}

set traceSlicing(value) {
this._traceSlicing = value;
}

get pos() {
return this._buf.position;
}
Expand All @@ -1760,14 +1662,6 @@ export class InputStream {
return this._instance;
}

get closure() {
return this._type;
}

set closure(value) {
this._type = value;
}

get buffer() {
return this._buf;
}
Expand Down

0 comments on commit 5cb7dfc

Please sign in to comment.