private static function readStructHelper()

in thrift/lib/hack/src/ThriftSerializationHelper.php [165:355]


  private static function readStructHelper(
    TProtocol $protocol,
    $field_type,
    &$object,
    $tspec,
  ): int {
    $xfer = 0;
    switch ($field_type) {
      case TType::BOOL:
        $xfer += $protocol->readBool(&$object);
        break;
      case TType::BYTE:
        $xfer += $protocol->readByte(&$object);
        break;
      case TType::I16:
        $xfer += $protocol->readI16(&$object);
        break;
      case TType::I32:
        // Enums:
        // In Hack, enums are encoded as I32s.
        // This looks into the tspec to distinguish the two of them.
        // Optimization opportunity: Add a TType of enum and encode that to
        // the tspec to avoid this if statement.
        if (isset($tspec['enum'])) {
          $val = null;
          $xfer += $protocol->readI32(&$val);
          $enum_class = $tspec['enum'];
          $object = $enum_class::coerce($val);
        } else {
          $xfer += $protocol->readI32(&$object);
        }
        break;
      case TType::I64:
        $xfer += $protocol->readI64(&$object);
        break;
      case TType::DOUBLE:
        $xfer += $protocol->readDouble(&$object);
        break;
      case TType::FLOAT:
        $xfer += $protocol->readFloat(&$object);
        break;
      case TType::STRING:
        $xfer += $protocol->readString(&$object);
        break;
      case TType::LST:
        $size = 0;
        $element_type = 0;
        $xfer += $protocol->readListBegin(&$element_type, &$size);

        // Use the correct collection.
        $list = null;
        if ($tspec['format'] === 'harray') {
          $list = vec[];
        } else if ($tspec['format'] === 'collection') {
          $list = Vector {};
        } else { // format === 'array'
          $list = varray[];
        }

        for ($i = 0; $size === null || $i < $size; ++$i) {
          if ($size === null && !$protocol->readListHasNext()) {
            break;
          }

          $list_element = null;
          $xfer += self::readStructHelper(
            $protocol,
            $tspec['etype'],
            &$list_element,
            $tspec['elem']
          );

          // If the element type is enum and the enum
          // does not exist, it will return a null.
          if ($list_element === null) {
            continue;
          }

          /* HH_IGNORE_ERROR[4006] type can be Vector, vec, or array */
          $list[] = $list_element;
        }
        $object = $list;
        $xfer += $protocol->readListEnd();
        break;
      case TType::SET:
        $size = 0;
        $element_type = 0;
        $xfer += $protocol->readSetBegin(&$element_type, &$size);

        // Use the correct collection.
        if ($tspec['format'] === 'harray') {
          $set = keyset[];
        } else if ($tspec['format'] === 'collection') {
          $set = Set {};
        } else { // format === 'array'
          $set = array();
        }

        for ($i = 0; $size === null || $i < $size; ++$i) {
          if ($size === null && !$protocol->readSetHasNext()) {
            break;
          }

          $set_element = null;
          $xfer += self::readStructHelper(
            $protocol,
            $tspec['etype'],
            &$set_element,
            $tspec['elem']
          );

          // If the element type is enum and the enum
          // does not exist, it will return a null.
          if ($set_element === null) {
            continue;
          }

          // When using a set array(), we can't append in the normal way.
          // Therefore, we need to distinguish between the two types
          // before we add the element to the set.
          if ($tspec['format'] === 'array') {
            invariant(is_array($set), 'for hack');
            $set[$set_element] = true;
          } else {
            /* HH_IGNORE_ERROR[4006] type will be Set or keyset */
            $set[] = $set_element;
          }
        }
        $object = $set;
        $xfer += $protocol->readSetEnd();
        break;
      case TType::MAP:
        $size = 0;
        $key_type = 0;
        $value_type = 0;
        $xfer += $protocol->readMapBegin(
          inout $key_type,
          inout $value_type,
          inout $size,
        );

        // Use the correct collection.
        $map = null;
        if ($tspec['format'] === 'harray') {
          $map = dict[];
        } else if ($tspec['format'] === 'collection') {
          $map = Map {};
        } else { // format === 'array'
          $map = array();
        }

        for ($i = 0; $size === null || $i < $size; ++$i) {
          if ($size === null && !$protocol->readMapHasNext()) {
            break;
          }

          $key = null;
          $val = null;
          $xfer += self::readStructHelper(
            $protocol,
            $tspec['ktype'],
            &$key,
            $tspec['key']
          );
          $xfer += self::readStructHelper(
            $protocol,
            $tspec['vtype'],
            &$val,
            $tspec['val']
          );

          // If the element type is enum and the enum
          // does not exist, it will return a null.
          if ($key === null || $val === null) {
            continue;
          }

          $map[$key] = $val;
        }
        $object = $map;
        $xfer += $protocol->readMapEnd();
        break;
      case TType::STRUCT:
        $object = new $tspec['class']();
        $xfer += $object->read($protocol);
        break;
      default:
        $xfer += $protocol->skip($field_type);
    }
    return $xfer;
  }