/** * @param \Protobuf\Compiler\Entity $entity * @param \google\protobuf\FieldDescriptorProto $field * * @return string[] */ public function generateFieldReadStatement(Entity $entity, FieldDescriptorProto $field) { $body = []; $reference = null; $type = $field->getType(); $name = $field->getName(); $rule = $field->getLabel(); $tag = $field->getNumber(); $options = $field->getOptions(); $isPack = $options ? $options->getPacked() : false; $variable = $this->targetVar ?: '$this->' . $name; $breakSttm = $this->getBreakStatement($variable); if ($field->hasTypeName()) { $typeName = $field->getTypeName(); $typeEntity = $this->getEntity($typeName); $reference = $typeEntity->getNamespacedName(); } if (!$isPack) { $body[] = sprintf('\\Protobuf\\WireFormat::assertWireType($wire, %s);', $type->value()); $body[] = null; } if ($rule === Label::LABEL_REPEATED() && $isPack) { $readSttm = $type === Type::TYPE_ENUM() ? $reference . '::valueOf(' . $this->generateReadScalarStatement($type->value()) . ')' : $this->generateReadScalarStatement($type->value()); $body[] = '$innerSize = $reader->readVarint($stream);'; $body[] = '$innerLimit = $stream->tell() + $innerSize;'; $body[] = null; $body[] = 'if (' . $variable . ' === null) {'; $body[] = ' ' . $variable . ' = new ' . $this->getCollectionClassName($field) . '();'; $body[] = '}'; $body[] = null; $body[] = 'while ($stream->tell() < $innerLimit) {'; $body[] = ' ' . $variable . '->add(' . $readSttm . ');'; $body[] = '}'; $body[] = null; $body[] = $breakSttm; return $body; } if ($type === Type::TYPE_MESSAGE() && $rule === Label::LABEL_REPEATED()) { $body[] = '$innerSize = $reader->readVarint($stream);'; $body[] = '$innerMessage = new ' . $reference . '();'; $body[] = null; $body[] = 'if (' . $variable . ' === null) {'; $body[] = ' ' . $variable . ' = new \\Protobuf\\MessageCollection();'; $body[] = '}'; $body[] = null; $body[] = $variable . '->add($innerMessage);'; $body[] = null; $body[] = '$context->setLength($innerSize);'; $body[] = '$innerMessage->readFrom($context);'; $body[] = '$context->setLength($length);'; $body[] = null; $body[] = $breakSttm; return $body; } if ($type === Type::TYPE_ENUM() && $rule === LABEL::LABEL_REPEATED()) { $body[] = 'if (' . $variable . ' === null) {'; $body[] = ' ' . $variable . ' = new ' . $this->getCollectionClassName($field) . '();'; $body[] = '}'; $body[] = null; $body[] = $variable . '->add(' . $reference . '::valueOf(' . $this->generateReadScalarStatement($type->value()) . '));'; $body[] = null; $body[] = $breakSttm; return $body; } if ($type === Type::TYPE_MESSAGE()) { $body[] = '$innerSize = $reader->readVarint($stream);'; $body[] = '$innerMessage = new ' . $reference . '();'; $body[] = null; $body[] = $variable . ' = $innerMessage;'; $body[] = null; $body[] = '$context->setLength($innerSize);'; $body[] = '$innerMessage->readFrom($context);'; $body[] = '$context->setLength($length);'; $body[] = null; $body[] = $breakSttm; return $body; } if ($type === Type::TYPE_ENUM()) { $body[] = $variable . ' = ' . $reference . '::valueOf(' . $this->generateReadScalarStatement($type->value()) . ');'; $body[] = null; $body[] = $breakSttm; return $body; } if ($rule !== LABEL::LABEL_REPEATED()) { $body[] = $variable . ' = ' . $this->generateReadScalarStatement($type->value()) . ';'; $body[] = null; $body[] = $breakSttm; return $body; } $body[] = 'if (' . $variable . ' === null) {'; $body[] = ' ' . $variable . ' = new ' . $this->getCollectionClassName($field) . '();'; $body[] = '}'; $body[] = null; $body[] = $variable . '->add(' . $this->generateReadScalarStatement($type->value()) . ');'; $body[] = null; $body[] = $breakSttm; return $body; }
protected function compileField(proto\FieldDescriptorProto $field, $ns, $indent) { // Fetch constants by reflecton $refl = new \ReflectionClass('\\DrSlump\\Protobuf'); $constants = $refl->getConstants(); // Separate rules and types $rules = $types = array(); foreach ($constants as $k => $v) { if (false === strpos($k, '_')) { continue; } list($prefix, $name) = explode('_', $k, 2); if ('RULE' === $prefix) { $rules[$name] = $v; } else { if ('TYPE' === $prefix) { $types[$name] = $v; } } } // Get the key for the rule and type $rule = array_search($field->getLabel(), $rules); $type = array_search($field->getType(), $types); $s[] = "// {$rule} {$type} " . $field->getName() . " = " . $field->getNumber(); $s[] = '$f = new \\DrSlump\\Protobuf\\Field();'; $s[] = '$f->number = ' . $field->getNumber() . ';'; $s[] = '$f->name = "' . $field->getName() . '";'; $s[] = '$f->type = \\DrSlump\\Protobuf::TYPE_' . $type . ';'; $s[] = '$f->rule = \\DrSlump\\Protobuf::RULE_' . $rule . ';'; if ($field->hasTypeName()) { $ref = $field->getTypeName(); if (substr($ref, 0, 1) !== '.') { throw new \RuntimeException("Only fully qualified names are supported but found '{$ref}' at {$ns}"); } $s[] = '$f->reference = \'\\' . $this->normalizeNS($ref) . "';"; } if ($field->hasDefaultValue()) { switch ($field->getType()) { case Protobuf::TYPE_BOOL: $bool = filter_var($field->getDefaultValue(), FILTER_VALIDATE_BOOLEAN); $s[] = '$f->default = ' . ($bool ? 'true' : 'false') . ';'; break; case Protobuf::TYPE_STRING: $s[] = '$f->default = "' . addcslashes($field->getDefaultValue(), '"\\') . '";'; break; case Protobuf::TYPE_ENUM: $value = '\\' . $this->normalizeNS($field->getTypeName()) . '::' . $field->getDefaultValue(); $s[] = '$f->default = ' . $value . ';'; break; default: // Numbers $s[] = '$f->default = ' . $field->getDefaultValue() . ';'; } } $s[] = '// @@protoc_insertion_point(scope_field)'; $s[] = '// @@protoc_insertion_point(field_' . $ns . ':' . $field->getName() . ')'; return $indent . implode(PHP_EOL . $indent, $s); }
public function generateField(proto\FieldDescriptorProto $field) { $reference = 'null'; if ($field->hasTypeName()) { $reference = $field->getTypeName(); if (substr($reference, 0, 1) !== '.') { throw new \RuntimeException('Only fully qualified names are supported: ' . $reference); } $reference = "'" . $this->normalizeNS($reference) . "'"; } $default = 'null'; if ($field->hasDefaultValue()) { switch ($field->getType()) { case Protobuf::TYPE_BOOL: $default = $field->getDefaultValue() ? 'true' : 'false'; break; case Protobuf::TYPE_STRING: $default = '"' . addcslashes($field->getDefaultValue(), '"\\') . '"'; break; case Protobuf::TYPE_ENUM: $default = $this->normalizeNS($field->getTypeName()) . '.' . $field->getDefaultValue(); break; default: // Numbers $default = $field->getDefaultValue(); } } $data = array("'" . $field->getName() . "'", $field->getLabel(), $field->getType(), $reference, $default, '{}'); return '[' . implode(', ', $data) . ']'; }