protected function _describe(Protobuf\Descriptor $descriptor) { $name = $descriptor->getName(); if (isset($this->_resources[$name])) { return $this->_resources[$name]; } // Create the message descriptor resource $res = \protobuf_desc_message($name); // Add the resource immediately in the dictionary to support cyclic references $this->_resources[$name] = $res; $lazy = $this->getOption('lazy'); // Iterate over all the fields to setup the message foreach ($descriptor->getFields() as $field) { $type = $field->getType(); // Nested messages need to be populated first if ($type === Protobuf\Protobuf::TYPE_MESSAGE) { // When in lazy decoding mode we handle nested messages as binary fields if ($lazy) { $type = Protobuf\Protobuf::TYPE_BYTES; } else { // Try to obtain the message descriptor resource for this field $descr = Protobuf\Protobuf::getRegistry()->getDescriptor($field->getReference()); if (!$descr) { throw new \RuntimeException('Unable to find a descriptor for message "' . $field->getReference() . '"'); } $nested = $this->_describe($descr); } } //printf("N: %d R: %d T: %d Name: %s P: %d\n", $field->getNumber(), $field->getRule(), $type, $field->getName(), $field->isPacked() ? PROTOBUF_FLAG_PACKED : 0); // Append the field definition to the message \protobuf_desc_field($res, $field->getNumber(), $field->getRule(), $type, $field->getName(), $field->isPacked() ? PROTOBUF_FLAG_PACKED : 0, $type === Protobuf\Protobuf::TYPE_MESSAGE ? $nested : NULL); } return $res; }
public static function descriptor() { $descriptor = new Descriptor(__CLASS__, 'payments.PaymentDetails'); // OPTIONAL STRING network = 1 $f = new Field(); $f->number = 1; $f->name = "network"; $f->type = Protobuf::TYPE_STRING; $f->rule = Protobuf::RULE_OPTIONAL; $f->default = "main"; $descriptor->addField($f); // REPEATED MESSAGE outputs = 2 $f = new Field(); $f->number = 2; $f->name = "outputs"; $f->type = Protobuf::TYPE_MESSAGE; $f->rule = Protobuf::RULE_REPEATED; $f->reference = '\\BitWasp\\Bitcoin\\Payments\\Protobufs\\Output'; $descriptor->addField($f); // REQUIRED UINT64 time = 3 $f = new Field(); $f->number = 3; $f->name = "time"; $f->type = Protobuf::TYPE_UINT64; $f->rule = Protobuf::RULE_REQUIRED; $descriptor->addField($f); // OPTIONAL UINT64 expires = 4 $f = new Field(); $f->number = 4; $f->name = "expires"; $f->type = Protobuf::TYPE_UINT64; $f->rule = Protobuf::RULE_OPTIONAL; $descriptor->addField($f); // OPTIONAL STRING memo = 5 $f = new Field(); $f->number = 5; $f->name = "memo"; $f->type = Protobuf::TYPE_STRING; $f->rule = Protobuf::RULE_OPTIONAL; $descriptor->addField($f); // OPTIONAL STRING payment_url = 6 $f = new Field(); $f->number = 6; $f->name = "payment_url"; $f->type = Protobuf::TYPE_STRING; $f->rule = Protobuf::RULE_OPTIONAL; $descriptor->addField($f); // OPTIONAL BYTES merchant_data = 7 $f = new Field(); $f->number = 7; $f->name = "merchant_data"; $f->type = Protobuf::TYPE_BYTES; $f->rule = Protobuf::RULE_OPTIONAL; $descriptor->addField($f); foreach (self::$__extensions as $cb) { $descriptor->addField($cb(), true); } return $descriptor; }
public static function descriptor() { $descriptor = new Descriptor(__CLASS__, 'payments.Output'); // OPTIONAL UINT64 amount = 1 $f = new Field(); $f->number = 1; $f->name = 'amount'; $f->type = Protobuf::TYPE_UINT64; $f->rule = Protobuf::RULE_OPTIONAL; $f->default = 0; $descriptor->addField($f); // REQUIRED BYTES script = 2 $f = new Field(); $f->number = 2; $f->name = 'script'; $f->type = Protobuf::TYPE_BYTES; $f->rule = Protobuf::RULE_REQUIRED; $descriptor->addField($f); foreach (self::$__extensions as $cb) { $descriptor->addField($cb(), true); } return $descriptor; }
/** * Clears/Resets a field by tag number * * @throws \Exception If trying to modify an unknown field * @param int $tag * @return \DrSlump\Protobuf\Message - Fluent interface */ public function _clear($tag) { $f = $this->_descriptor->getField($tag); if (!$f) { throw new \Exception('Unknown fields not supported'); } $name = $f->getName(); if (!$f->isExtension()) { $this->{$name} = $f->isRepeated() ? array() : NULL; } else { $this->_extensions[$name] = $f->isRepeated() ? array() : NULL; } return $this; }
public static function descriptor() { $descriptor = new Descriptor(__CLASS__, 'payments.PaymentRequest'); // OPTIONAL UINT32 payment_details_version = 1 $f = new Field(); $f->number = 1; $f->name = "payment_details_version"; $f->type = Protobuf::TYPE_UINT32; $f->rule = Protobuf::RULE_OPTIONAL; $f->default = 1; $descriptor->addField($f); // OPTIONAL STRING pki_type = 2 $f = new Field(); $f->number = 2; $f->name = "pki_type"; $f->type = Protobuf::TYPE_STRING; $f->rule = Protobuf::RULE_OPTIONAL; $f->default = "none"; $descriptor->addField($f); // OPTIONAL BYTES pki_data = 3 $f = new Field(); $f->number = 3; $f->name = "pki_data"; $f->type = Protobuf::TYPE_BYTES; $f->rule = Protobuf::RULE_OPTIONAL; $descriptor->addField($f); // REQUIRED BYTES serialized_payment_details = 4 $f = new Field(); $f->number = 4; $f->name = "serialized_payment_details"; $f->type = Protobuf::TYPE_BYTES; $f->rule = Protobuf::RULE_REQUIRED; $descriptor->addField($f); // OPTIONAL BYTES signature = 5 $f = new Field(); $f->number = 5; $f->name = "signature"; $f->type = Protobuf::TYPE_BYTES; $f->rule = Protobuf::RULE_OPTIONAL; $descriptor->addField($f); foreach (self::$__extensions as $cb) { $descriptor->addField($cb(), true); } return $descriptor; }
public function offsetUnset($offset) { if (is_numeric($offset)) { $field = $this->_descriptor->getField($offset); if (!$field) { trigger_error("Protobuf message " . $this->_descriptor->getName() . " doesn't have any field with a tag number of {$offset}", E_USER_NOTICE); return; } if ($field->isExtension()) { $data =& $this->_extensions; } else { $data =& $this->_values; } if (isset($data[$field->name])) { unset($data[$field->name]); } } else { $this->clearExtension($offset); } }
public static function descriptor() { $class = get_called_class(); // Instantiate a new descriptor $descriptor = new Descriptor($class); $rflClass = new \ReflectionClass($class); $props = $rflClass->getProperties(); foreach ($props as $prop) { $doc = $prop->getDocComment(); if (empty($doc)) { continue; } // Format: @protobuf(tag=X, type=bool, required=true) // Extract annotation from the comment if (!preg_match('/@protobuf\\s?\\(([^\\)]+)\\)/', $doc, $m)) { continue; } // Parse params $params = explode(',', $m[1]); $params = array_filter(array_map('trim', $params)); $options = array(); foreach ($params as $param) { $parts = explode('=', $param); $parts = array_filter(array_map('trim', $parts)); $options[$parts[0]] = count($parts) < 2 ? true : $parts[1]; } // Check if we have the minimum required options if (empty($options['tag'])) { throw new \InvalidArgumentException('The tag option is required for property ' . $prop->getName()); } if (empty($options['type'])) { throw new \InvalidArgumentException('The type option is required for property ' . $prop->getName()); } // Normalize boolean values foreach (array('required', 'optional', 'repeated', 'packed') as $opt) { if (isset($options[$opt])) { $options[$opt] = filter_var($options[$opt], FILTER_VALIDATE_BOOLEAN); } } // Build a field descriptor $f = new Protobuf\Field(); $f->number = (int) $options['tag']; $f->name = $prop->getName(); // Convert type name to its numeric constant switch (strtolower($options['type'])) { case 'double': $f->type = Protobuf\Protobuf::TYPE_DOUBLE; break; case 'float': $f->type = Protobuf\Protobuf::TYPE_FLOAT; break; case 'int64': $f->type = Protobuf\Protobuf::TYPE_INT64; break; case 'uint64': $f->type = Protobuf\Protobuf::TYPE_UINT64; break; case 'int32': $f->type = Protobuf\Protobuf::TYPE_INT32; break; case 'fixed64': $f->type = Protobuf\Protobuf::TYPE_FIXED64; break; case 'fixed32': $f->type = Protobuf\Protobuf::TYPE_FIXED32; break; case 'bool': $f->type = Protobuf\Protobuf::TYPE_BOOL; break; case 'string': $f->type = Protobuf\Protobuf::TYPE_STRING; break; case 'message': $f->type = Protobuf\Protobuf::TYPE_MESSAGE; break; case 'bytes': $f->type = Protobuf\Protobuf::TYPE_BYTES; break; case 'uint32': $f->type = Protobuf\Protobuf::TYPE_UINT32; break; case 'enum': $f->type = Protobuf\Protobuf::TYPE_ENUM; break; case 'sfixed32': $f->type = Protobuf\Protobuf::TYPE_SFIXED32; break; case 'sfixed64': $f->type = Protobuf\Protobuf::TYPE_SFIXED64; break; case 'sint32': $f->type = Protobuf\Protobuf::TYPE_SINT32; break; case 'sint64': $f->type = Protobuf\Protobuf::TYPE_SINT64; break; default: throw new \InvalidArgumentException('Type ' . $options['type'] . ' is not recognized as valid for property ' . $prop->getName()); } // Define the rule type $f->rule = Protobuf\Protobuf::RULE_OPTIONAL; if (!empty($options['required'])) { $f->rule = Protobuf\Protobuf::RULE_REQUIRED; } if (!empty($options['repeated'])) { $f->rule = Protobuf\Protobuf::RULE_REPEATED; } // Check if it's flagged as packed if (isset($options['packed'])) { $f->packed = $options['packed']; } // Get the reference if (isset($options['reference'])) { $f->reference = $options['reference']; } else { if ($f->type === Protobuf\Protobuf::TYPE_MESSAGE || $f->type === Protobuf\Protobuf::TYPE_ENUM) { throw new \InvalidArgumentException('Property ' . $prop->getName() . ' requires the "reference" option'); } } if (isset($options['default'])) { $f->default = $options['default']; } // Add the field to the message descriptor $descriptor->addField($f); } return $descriptor; }