static _decodeProto(proto, encoded) {
		if (ByteBuffer.isByteBuffer(encoded)) {
			encoded = encoded.toBuffer();
		}

		let decoded = proto.decode(encoded);
		let objNoDefaults = proto.toObject(decoded, {longs: String});
		let objWithDefaults = proto.toObject(decoded, {defaults: true, longs: String});
		return replaceDefaults(objNoDefaults, objWithDefaults);

		function replaceDefaults(noDefaults, withDefaults) {
			if (Array.isArray(withDefaults)) {
				return withDefaults.map((val, idx) => replaceDefaults(noDefaults[idx], val));
			}

			for (let i in withDefaults) {
				if (!Object.hasOwnProperty.call(withDefaults, i)) {
					continue;
				}

				if (withDefaults[i] && typeof withDefaults[i] === 'object' && !Buffer.isBuffer(withDefaults[i])) {
					// Covers both object and array cases, both of which will work
					// Won't replace empty arrays, but that's desired behavior
					withDefaults[i] = replaceDefaults(noDefaults[i], withDefaults[i]);
				} else if (typeof noDefaults[i] === 'undefined' && isReplaceableDefaultValue(withDefaults[i])) {
					withDefaults[i] = null;
				}
			}

			return withDefaults;
		}

		function isReplaceableDefaultValue(val) {
			if (Buffer.isBuffer(val) && val.length == 0) {
				// empty buffer is replaceable
				return true;
			}

			if (Array.isArray(val)) {
				// empty array is not replaceable (empty repeated fields)
				return false;
			}

			if (val === '0') {
				// Zero as a string is replaceable (64-bit integer)
				return true;
			}

			// Anything falsy is true
			return !val;
		}
	}
Decode a protobuf.
@param {object} proto - The protobuf class
@param {Buffer|ByteBuffer} encoded - The data to decode
@returns {object}
@protected