final class TBinaryProtocol()

in lib/d/src/thrift/protocol/binary.d [30:333]


final class TBinaryProtocol(Transport = TTransport) if (
  isTTransport!Transport
) : TProtocol {

  /**
   * Constructs a new instance.
   *
   * Params:
   *   trans = The transport to use.
   *   containerSizeLimit = If positive, the container size is limited to the
   *     given number of items.
   *   stringSizeLimit = If positive, the string length is limited to the
   *     given number of bytes.
   *   strictRead = If false, old peers which do not include the protocol
   *     version are tolerated.
   *   strictWrite = Whether to include the protocol version in the header.
   */
  this(Transport trans, int containerSizeLimit = 0, int stringSizeLimit = 0,
    bool strictRead = false, bool strictWrite = true
  ) {
    trans_ = trans;
    this.containerSizeLimit = containerSizeLimit;
    this.stringSizeLimit = stringSizeLimit;
    this.strictRead = strictRead;
    this.strictWrite = strictWrite;
  }

  Transport transport() @property {
    return trans_;
  }

  void reset() {}

  /**
   * If false, old peers which do not include the protocol version in the
   * message header are tolerated.
   *
   * Defaults to false.
   */
  bool strictRead;

  /**
   * Whether to include the protocol version in the message header (older
   * versions didn't).
   *
   * Defaults to true.
   */
  bool strictWrite;

  /**
   * If positive, limits the number of items of deserialized containers to the
   * given amount.
   *
   * This is useful to avoid allocating excessive amounts of memory when broken
   * data is received. If the limit is exceeded, a SIZE_LIMIT-type
   * TProtocolException is thrown.
   *
   * Defaults to zero (no limit).
   */
  int containerSizeLimit;

  /**
   * If positive, limits the length of deserialized strings/binary data to the
   * given number of bytes.
   *
   * This is useful to avoid allocating excessive amounts of memory when broken
   * data is received. If the limit is exceeded, a SIZE_LIMIT-type
   * TProtocolException is thrown.
   *
   * Defaults to zero (no limit).
   */
  int stringSizeLimit;

  /*
   * Writing methods.
   */

  void writeBool(bool b) {
    writeByte(b ? 1 : 0);
  }

  void writeByte(byte b) {
    trans_.write((cast(ubyte*)&b)[0 .. 1]);
  }

  void writeI16(short i16) {
    short net = hostToNet(i16);
    trans_.write((cast(ubyte*)&net)[0 .. 2]);
  }

  void writeI32(int i32) {
    int net = hostToNet(i32);
    trans_.write((cast(ubyte*)&net)[0 .. 4]);
  }

  void writeI64(long i64) {
    long net = hostToNet(i64);
    trans_.write((cast(ubyte*)&net)[0 .. 8]);
  }

  void writeDouble(double dub) {
    static assert(double.sizeof == ulong.sizeof);
    auto bits = hostToNet(*cast(ulong*)(&dub));
    trans_.write((cast(ubyte*)&bits)[0 .. 8]);
  }

  void writeString(string str) {
    writeBinary(cast(ubyte[])str);
  }

  void writeBinary(ubyte[] buf) {
    assert(buf.length <= int.max);
    writeI32(cast(int)buf.length);
    trans_.write(buf);
  }

  void writeMessageBegin(TMessage message) {
    if (strictWrite) {
      int versn = VERSION_1 | message.type;
      writeI32(versn);
      writeString(message.name);
      writeI32(message.seqid);
    } else {
      writeString(message.name);
      writeByte(message.type);
      writeI32(message.seqid);
    }
  }
  void writeMessageEnd() {}

  void writeStructBegin(TStruct tstruct) {}
  void writeStructEnd() {}

  void writeFieldBegin(TField field) {
    writeByte(field.type);
    writeI16(field.id);
  }
  void writeFieldEnd() {}

  void writeFieldStop() {
    writeByte(TType.STOP);
  }

  void writeListBegin(TList list) {
    assert(list.size <= int.max);
    writeByte(list.elemType);
    writeI32(cast(int)list.size);
  }
  void writeListEnd() {}

  void writeMapBegin(TMap map) {
    assert(map.size <= int.max);
    writeByte(map.keyType);
    writeByte(map.valueType);
    writeI32(cast(int)map.size);
  }
  void writeMapEnd() {}

  void writeSetBegin(TSet set) {
    assert(set.size <= int.max);
    writeByte(set.elemType);
    writeI32(cast(int)set.size);
  }
  void writeSetEnd() {}


  /*
   * Reading methods.
   */

  bool readBool() {
    return readByte() != 0;
  }

  byte readByte() {
    ubyte[1] b = void;
    trans_.readAll(b);
    return cast(byte)b[0];
  }

  short readI16() {
    IntBuf!short b = void;
    trans_.readAll(b.bytes);
    return netToHost(b.value);
  }

  int readI32() {
    IntBuf!int b = void;
    trans_.readAll(b.bytes);
    return netToHost(b.value);
  }

  long readI64() {
    IntBuf!long b = void;
    trans_.readAll(b.bytes);
    return netToHost(b.value);
  }

  double readDouble() {
    IntBuf!long b = void;
    trans_.readAll(b.bytes);
    b.value = netToHost(b.value);
    return *cast(double*)(&b.value);
  }

  string readString() {
    return cast(string)readBinary();
  }

  ubyte[] readBinary() {
    return readBinaryBody(readSize(stringSizeLimit));
  }

  TMessage readMessageBegin() {
    TMessage msg = void;

    int size = readI32();
    if (size < 0) {
      int versn = size & VERSION_MASK;
      if (versn != VERSION_1) {
        throw new TProtocolException("Bad protocol version.",
          TProtocolException.Type.BAD_VERSION);
      }

      msg.type = cast(TMessageType)(size & MESSAGE_TYPE_MASK);
      msg.name = readString();
      msg.seqid = readI32();
    } else {
      if (strictRead) {
        throw new TProtocolException(
          "Protocol version missing, old client?",
          TProtocolException.Type.BAD_VERSION);
      } else {
        if (size < 0) {
          throw new TProtocolException(TProtocolException.Type.NEGATIVE_SIZE);
        }
        msg.name = cast(string)readBinaryBody(size);
        msg.type = cast(TMessageType)(readByte());
        msg.seqid = readI32();
      }
    }

    return msg;
  }
  void readMessageEnd() {}

  TStruct readStructBegin() {
    return TStruct();
  }
  void readStructEnd() {}

  TField readFieldBegin() {
    TField f = void;
    f.name = null;
    f.type = cast(TType)readByte();
    if (f.type == TType.STOP) return f;
    f.id = readI16();
    return f;
  }
  void readFieldEnd() {}

  TList readListBegin() {
    return TList(cast(TType)readByte(), readSize(containerSizeLimit));
  }
  void readListEnd() {}

  TMap readMapBegin() {
    return TMap(cast(TType)readByte(), cast(TType)readByte(),
      readSize(containerSizeLimit));
  }
  void readMapEnd() {}

  TSet readSetBegin() {
    return TSet(cast(TType)readByte(), readSize(containerSizeLimit));
  }
  void readSetEnd() {}

private:
  ubyte[] readBinaryBody(int size) {
    if (size == 0) {
      return null;
    }

    auto buf = uninitializedArray!(ubyte[])(size);
    trans_.readAll(buf);
    return buf;
  }

  int readSize(int limit) {
    auto size = readI32();
    if (size < 0) {
      throw new TProtocolException(TProtocolException.Type.NEGATIVE_SIZE);
    } else if (limit > 0 && size > limit) {
      throw new TProtocolException(TProtocolException.Type.SIZE_LIMIT);
    }
    return size;
  }

  enum MESSAGE_TYPE_MASK = 0x000000ff;
  enum VERSION_MASK = 0xffff0000;
  enum VERSION_1 = 0x80010000;

  Transport trans_;
}