Protocol Buffers - Google's data interchange format (grpc依赖) https://developers.google.com/protocol-buffers/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

892 lines
30 KiB

//
// upb - a minimalist implementation of protocol buffers.
//
// Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
// Author: Josh Haberman <jhaberman@gmail.com>
#include <string>
#include <typeinfo>
#include "upb/bytestream.hpp"
#include "upb/def.hpp"
#include "upb/handlers.hpp"
#include "upb/msg.hpp"
#include "upb/proto2_bridge.hpp"
namespace {
static void* GetFieldPointer(void *message, const upb::FieldDef* f) {
return static_cast<char*>(message) + f->offset();
}
} // namespace
#ifdef UPB_GOOGLE3
// TODO(haberman): friend upb so that this isn't required.
#define protected public
#include "net/proto2/public/repeated_field.h"
#undef private
#define private public
#include "net/proto/proto2_reflection.h"
#undef private
#include "net/proto2/proto/descriptor.pb.h"
#include "net/proto2/public/descriptor.h"
#include "net/proto2/public/generated_message_reflection.h"
#include "net/proto2/public/lazy_field.h"
#include "net/proto2/public/message.h"
#include "net/proto2/public/string_piece_field_support.h"
#include "net/proto/internal_layout.h"
#include "strings/cord.h"
using ::proto2::Descriptor;
using ::proto2::EnumDescriptor;
using ::proto2::EnumValueDescriptor;
using ::proto2::FieldDescriptor;
using ::proto2::FieldOptions;
using ::proto2::FileDescriptor;
using ::proto2::internal::GeneratedMessageReflection;
using ::proto2::internal::RepeatedPtrFieldBase;
using ::proto2::internal::StringPieceField;
using ::proto2::Message;
using ::proto2::MessageFactory;
using ::proto2::Reflection;
using ::proto2::RepeatedField;
using ::proto2::RepeatedPtrField;
namespace upb {
static const Message* GetPrototypeForField(const Message& m,
const FieldDescriptor* f);
namespace proto2_bridge_google3 { class FieldAccessor; }
using ::upb::proto2_bridge_google3::FieldAccessor;
namespace proto2_bridge_google3 {
static void AssignToCord(const ByteRegion* r, Cord* cord) {
// TODO(haberman): ref source data if source is a cord.
cord->Clear();
uint64_t ofs = r->start_ofs();
while (ofs < r->end_ofs()) {
size_t len;
const char *buf = r->GetPtr(ofs, &len);
cord->Append(StringPiece(buf, len));
ofs += len;
}
}
#else
// TODO(haberman): friend upb so that this isn't required.
#define protected public
#include "google/protobuf/repeated_field.h"
#undef protected
#define private public
#include "google/protobuf/generated_message_reflection.h"
#undef private
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/message.h"
using ::google::protobuf::Descriptor;
using ::google::protobuf::EnumDescriptor;
using ::google::protobuf::EnumValueDescriptor;
using ::google::protobuf::FieldDescriptor;
using ::google::protobuf::FieldOptions;
using ::google::protobuf::FileDescriptor;
using ::google::protobuf::internal::GeneratedMessageReflection;
using ::google::protobuf::internal::RepeatedPtrFieldBase;
using ::google::protobuf::Message;
using ::google::protobuf::MessageFactory;
using ::google::protobuf::Reflection;
using ::google::protobuf::RepeatedField;
using ::google::protobuf::RepeatedPtrField;
namespace upb {
static const Message* GetPrototypeForField(const Message& m,
const FieldDescriptor* f);
namespace proto2_bridge_opensource { class FieldAccessor; }
using ::upb::proto2_bridge_opensource::FieldAccessor;
namespace proto2_bridge_opensource {
#endif // ifdef UPB_GOOGLE3
// Have to define this manually since older versions of proto2 didn't define
// an enum value for STRING.
#define UPB_CTYPE_STRING 0
// The code in this class depends on the internal representation of the proto2
// generated classes, which is an internal implementation detail of proto2 and
// is not a public interface. As a result, this class's implementation may
// need to be changed if/when proto2 changes its internal representation. It
// is intended that this class is the only code that depends on these internal,
// non-public interfaces.
//
// This class only works with messages that use GeneratedMessageReflection.
// Other reflection classes will need other accessor implementations.
class FieldAccessor {
public:
// Returns true if we were able to set an accessor and any other properties
// of the FieldDef that are necessary to read/write this field to a
// proto2::Message.
static bool TrySet(const FieldDescriptor* proto2_f,
const upb::MessageDef* md,
upb::FieldDef* upb_f) {
const Message* prototype = static_cast<const Message*>(md->prototype);
const Reflection* base_r = prototype->GetReflection();
const GeneratedMessageReflection* r =
dynamic_cast<const GeneratedMessageReflection*>(base_r);
// Old versions of the open-source protobuf release erroneously default to
// Cord even though that has never been supported in the open-source
// release.
int32_t ctype = proto2_f->options().has_ctype() ?
proto2_f->options().ctype() : UPB_CTYPE_STRING;
if (!r) return false;
// Extensions not supported yet.
if (proto2_f->is_extension()) return false;
upb_f->set_accessor(GetForFieldDescriptor(proto2_f, ctype));
upb_f->set_hasbit(GetHasbit(proto2_f, r));
upb_f->set_offset(GetOffset(proto2_f, r));
if (upb_f->IsSubmessage()) {
upb_f->set_subtype_name(proto2_f->message_type()->full_name());
upb_f->prototype = GetPrototypeForField(*prototype, proto2_f);
}
if (upb_f->IsString() && !upb_f->IsSequence() &&
ctype == UPB_CTYPE_STRING) {
upb_f->prototype = &r->GetStringReference(*prototype, proto2_f, NULL);
}
return true;
}
static MessageFactory* GetMessageFactory(const Message& m) {
const GeneratedMessageReflection* r =
dynamic_cast<const GeneratedMessageReflection*>(m.GetReflection());
return r ? r->message_factory_ : NULL;
}
private:
static int64_t GetHasbit(const FieldDescriptor* f,
const GeneratedMessageReflection* r) {
if (f->is_repeated()) {
// proto2 does not store hasbits for repeated fields.
return -1;
} else {
return (r->has_bits_offset_ * 8) + f->index();
}
}
static uint16_t GetOffset(const FieldDescriptor* f,
const GeneratedMessageReflection* r) {
return r->offsets_[f->index()];
}
static AccessorVTable *GetForFieldDescriptor(const FieldDescriptor* f,
int32_t ctype) {
switch (f->cpp_type()) {
case FieldDescriptor::CPPTYPE_ENUM:
// Should handlers validate enum membership to match proto2?
case FieldDescriptor::CPPTYPE_INT32: return Get<int32_t>();
case FieldDescriptor::CPPTYPE_INT64: return Get<int64_t>();
case FieldDescriptor::CPPTYPE_UINT32: return Get<uint32_t>();
case FieldDescriptor::CPPTYPE_UINT64: return Get<uint64_t>();
case FieldDescriptor::CPPTYPE_DOUBLE: return Get<double>();
case FieldDescriptor::CPPTYPE_FLOAT: return Get<float>();
case FieldDescriptor::CPPTYPE_BOOL: return Get<bool>();
case FieldDescriptor::CPPTYPE_STRING:
switch (ctype) {
#ifdef UPB_GOOGLE3
case FieldOptions::STRING:
return GetForString<string>();
case FieldOptions::CORD:
return GetForCord();
case FieldOptions::STRING_PIECE:
return GetForStringPiece();
#else
case UPB_CTYPE_STRING:
return GetForString<std::string>();
#endif
default: return NULL;
}
case FieldDescriptor::CPPTYPE_MESSAGE:
#ifdef UPB_GOOGLE3
if (f->options().lazy()) {
return NULL; // Not yet implemented.
} else {
return GetForMessage();
}
#else
return GetForMessage();
#endif
default: return NULL;
}
}
// PushOffset handler (used for StartSequence and others) ///////////////////
static SubFlow PushOffset(void *m, Value fval) {
const FieldDef *f = GetValue<const FieldDef*>(fval);
return UPB_CONTINUE_WITH(GetFieldPointer(m, f));
}
// Primitive Value (numeric, enum, bool) /////////////////////////////////////
template <typename T> static AccessorVTable *Get() {
static upb_accessor_vtbl vtbl = {
NULL, // StartSubMessage handler
GetValueHandler<T>(),
&PushOffset, // StartSequence handler
NULL, // StartRepeatedSubMessage handler
&Append<T>,
NULL, NULL, NULL, NULL, NULL, NULL};
return &vtbl;
}
template <typename T>
static Flow Append(void *_r, Value fval, Value val) {
(void)fval;
RepeatedField<T>* r = static_cast<RepeatedField<T>*>(_r);
r->Add(GetValue<T>(val));
return UPB_CONTINUE;
}
// String ////////////////////////////////////////////////////////////////////
template <typename T> static AccessorVTable *GetForString() {
static upb_accessor_vtbl vtbl = {
NULL, // StartSubMessage handler
&SetString<T>,
&PushOffset, // StartSequence handler
NULL, // StartRepeatedSubMessage handler
&AppendString<T>,
NULL, NULL, NULL, NULL, NULL, NULL};
return &vtbl;
}
// This needs to be templated because google3 string is not std::string.
template <typename T> static Flow SetString(void *m, Value fval, Value val) {
const FieldDef* f = GetValue<const FieldDef*>(fval);
T **str = static_cast<T**>(GetFieldPointer(m, f));
// If it points to the default instance, we must create a new instance.
if (*str == f->prototype) *str = new T();
GetValue<ByteRegion*>(val)->AssignToString(*str);
return UPB_CONTINUE;
}
template <typename T>
static Flow AppendString(void *_r, Value fval, Value val) {
(void)fval;
RepeatedPtrField<T>* r = static_cast<RepeatedPtrField<T>*>(_r);
GetValue<ByteRegion*>(val)->AssignToString(r->Add());
return UPB_CONTINUE;
}
// SubMessage ////////////////////////////////////////////////////////////////
static AccessorVTable *GetForMessage() {
static upb_accessor_vtbl vtbl = {
&StartSubMessage,
NULL, // Value handler
&PushOffset, // StartSequence handler
&StartRepeatedSubMessage,
NULL, // Repeated value handler
NULL, NULL, NULL, NULL, NULL, NULL};
return &vtbl;
}
static SubFlow StartSubMessage(void *m, Value fval) {
const FieldDef* f = GetValue<const FieldDef*>(fval);
void **subm = static_cast<void**>(GetFieldPointer(m, f));
if (*subm == NULL || *subm == f->prototype) {
const Message* prototype = static_cast<const Message*>(f->prototype);
*subm = prototype->New();
}
return UPB_CONTINUE_WITH(*subm);
}
class RepeatedMessageTypeHandler {
public:
typedef void Type;
// AddAllocated() calls this, but only if other objects are sitting
// around waiting for reuse, which we will not do.
static void Delete(Type* t) {
(void)t;
assert(false);
}
};
// Closure is a RepeatedPtrField<SubMessageType>*, but we access it through
// its base class RepeatedPtrFieldBase*.
static SubFlow StartRepeatedSubMessage(void* _r, Value fval) {
const FieldDef* f = GetValue<const FieldDef*>(fval);
RepeatedPtrFieldBase *r = static_cast<RepeatedPtrFieldBase*>(_r);
void *submsg = r->AddFromCleared<RepeatedMessageTypeHandler>();
if (!submsg) {
const Message* prototype = static_cast<const Message*>(f->prototype);
submsg = prototype->New();
r->AddAllocated<RepeatedMessageTypeHandler>(submsg);
}
return UPB_CONTINUE_WITH(submsg);
}
// TODO(haberman): handle Extensions, Unknown Fields.
#ifdef UPB_GOOGLE3
// Handlers for types/features only included in internal proto2 release:
// Cord, StringPiece, LazyField, and MessageSet.
// TODO(haberman): LazyField, MessageSet.
// Cord //////////////////////////////////////////////////////////////////////
static AccessorVTable *GetForCord() {
static upb_accessor_vtbl vtbl = {
NULL, // StartSubMessage handler
&SetCord,
&PushOffset, // StartSequence handler
NULL, // StartRepeatedSubMessage handler
&AppendCord,
NULL, NULL, NULL, NULL, NULL, NULL};
return &vtbl;
}
static Flow SetCord(void *m, Value fval, Value val) {
const FieldDef* f = GetValue<const FieldDef*>(fval);
Cord* field = static_cast<Cord*>(GetFieldPointer(m, f));
AssignToCord(GetValue<ByteRegion*>(val), field);
return UPB_CONTINUE;
}
static Flow AppendCord(void *_r, Value fval, Value val) {
RepeatedField<Cord>* r = static_cast<RepeatedField<Cord>*>(_r);
AssignToCord(GetValue<ByteRegion*>(val), r->Add());
return UPB_CONTINUE;
}
// StringPiece ///////////////////////////////////////////////////////////////
static AccessorVTable *GetForStringPiece() {
static upb_accessor_vtbl vtbl = {
NULL, // StartSubMessage handler
&SetStringPiece,
&PushOffset, // StartSequence handler
NULL, // StartRepeatedSubMessage handler
&AppendStringPiece,
NULL, NULL, NULL, NULL, NULL, NULL};
return &vtbl;
}
static void AssignToStringPieceField(const ByteRegion* r,
proto2::internal::StringPieceField* f) {
// TODO(haberman): alias if possible and enabled on the input stream.
// TODO(haberman): add a method to StringPieceField that lets us avoid
// this copy/malloc/free.
char *data = new char[r->Length()];
r->Copy(r->start_ofs(), r->Length(), data);
f->CopyFrom(StringPiece(data, r->Length()));
delete[] data;
}
static Flow SetStringPiece(void *m, Value fval, Value val) {
const FieldDef* f = GetValue<const FieldDef*>(fval);
StringPieceField* field =
static_cast<StringPieceField*>(GetFieldPointer(m, f));
AssignToStringPieceField(GetValue<ByteRegion*>(val), field);
return UPB_CONTINUE;
}
static Flow AppendStringPiece(void* _r, Value fval, Value val) {
RepeatedPtrField<StringPieceField>* r =
static_cast<RepeatedPtrField<StringPieceField>*>(_r);
AssignToStringPieceField(GetValue<ByteRegion*>(val), r->Add());
return UPB_CONTINUE;
}
#endif // UPB_GOOGLE3
};
#ifdef UPB_GOOGLE3
// Proto1 accessor -- only needed inside Google.
class Proto1FieldAccessor {
public:
// Returns true if we were able to set an accessor and any other properties
// of the FieldDef that are necessary to read/write this field to a
// proto2::Message.
static bool TrySet(const FieldDescriptor* proto2_f,
const upb::MessageDef* md,
upb::FieldDef* upb_f) {
const Message* m = static_cast<const Message*>(md->prototype);
const proto2::Reflection* base_r = m->GetReflection();
const _pi::Proto2Reflection* r =
dynamic_cast<const _pi::Proto2Reflection*>(base_r);
if (!r) return false;
// Extensions not supported yet.
if (proto2_f->is_extension()) return false;
const _pi::Field* f = r->GetFieldLayout(proto2_f);
if (f->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK) {
// Override the BYTES type that proto2 descriptors have for weak fields.
upb_f->set_type(UPB_TYPE(MESSAGE));
}
if (upb_f->IsSubmessage()) {
const Message* prototype = upb::GetPrototypeForField(*m, proto2_f);
upb_f->set_subtype_name(prototype->GetDescriptor()->full_name());
upb_f->prototype = prototype;
}
upb_f->set_accessor(GetForCrep(f->crep));
upb_f->set_hasbit(GetHasbit(proto2_f, r));
upb_f->set_offset(GetOffset(proto2_f, r));
return true;
}
private:
static int16_t GetHasbit(const FieldDescriptor* f,
const _pi::Proto2Reflection* r) {
if (f->is_repeated()) {
// proto1 does not store hasbits for repeated fields.
return -1;
} else {
return (r->layout_->has_bit_offset * 8) + r->GetFieldLayout(f)->has_index;
}
}
static uint16_t GetOffset(const FieldDescriptor* f,
const _pi::Proto2Reflection* r) {
return r->GetFieldLayout(f)->offset;
}
static AccessorVTable *GetForCrep(int crep) {
#define PRIMITIVE(name, type_name) \
case _pi::CREP_REQUIRED_ ## name: \
case _pi::CREP_OPTIONAL_ ## name: \
case _pi::CREP_REPEATED_ ## name: return Get<type_name>();
switch (crep) {
PRIMITIVE(DOUBLE, double);
PRIMITIVE(FLOAT, float);
PRIMITIVE(INT64, int64_t);
PRIMITIVE(UINT64, uint64_t);
PRIMITIVE(INT32, int32_t);
PRIMITIVE(FIXED64, uint64_t);
PRIMITIVE(FIXED32, uint32_t);
PRIMITIVE(BOOL, bool);
case _pi::CREP_REQUIRED_STRING:
case _pi::CREP_OPTIONAL_STRING:
case _pi::CREP_REPEATED_STRING: return GetForString();
case _pi::CREP_OPTIONAL_OUTOFLINE_STRING: return GetForOutOfLineString();
case _pi::CREP_REQUIRED_CORD:
case _pi::CREP_OPTIONAL_CORD:
case _pi::CREP_REPEATED_CORD: return GetForCord();
case _pi::CREP_REQUIRED_GROUP:
case _pi::CREP_REQUIRED_FOREIGN:
case _pi::CREP_REQUIRED_FOREIGN_PROTO2: return GetForRequiredMessage();
case _pi::CREP_OPTIONAL_GROUP:
case _pi::CREP_REPEATED_GROUP:
case _pi::CREP_OPTIONAL_FOREIGN:
case _pi::CREP_REPEATED_FOREIGN:
case _pi::CREP_OPTIONAL_FOREIGN_PROTO2:
case _pi::CREP_REPEATED_FOREIGN_PROTO2: return GetForMessage();
case _pi::CREP_OPTIONAL_FOREIGN_WEAK: return GetForWeakMessage();
default: assert(false); return NULL;
}
#undef PRIMITIVE
}
// PushOffset handler (used for StartSequence and others) ///////////////////
// We can find a RepeatedField* or a RepeatedPtrField* at f->offset().
static SubFlow PushOffset(void *m, Value fval) {
const FieldDef *f = GetValue<const FieldDef*>(fval);
return UPB_CONTINUE_WITH(GetFieldPointer(m, f));
}
// Primitive Value (numeric, enum, bool) /////////////////////////////////////
template <typename T> static AccessorVTable *Get() {
static upb_accessor_vtbl vtbl = {
NULL, // StartSubMessage handler
GetValueHandler<T>(),
&PushOffset, // StartSequence handler
NULL, // StartRepeatedSubMessage handler
&Append<T>,
NULL, NULL, NULL, NULL, NULL, NULL};
return &vtbl;
}
template <typename T>
static Flow Append(void *_r, Value fval, Value val) {
(void)fval;
// Proto1's ProtoArray class derives from RepeatedField.
RepeatedField<T>* r = static_cast<RepeatedField<T>*>(_r);
r->Add(GetValue<T>(val));
return UPB_CONTINUE;
}
// String ////////////////////////////////////////////////////////////////////
static AccessorVTable *GetForString() {
static upb_accessor_vtbl vtbl = {
NULL, // StartSubMessage handler
&SetString,
&PushOffset, // StartSequence handler
NULL, // StartRepeatedSubMessage handler
&AppendString,
NULL, NULL, NULL, NULL, NULL, NULL};
return &vtbl;
}
static Flow SetString(void *m, Value fval, Value val) {
const FieldDef* f = GetValue<const FieldDef*>(fval);
string *str = static_cast<string*>(GetFieldPointer(m, f));
GetValue<ByteRegion*>(val)->AssignToString(str);
return UPB_CONTINUE;
}
static Flow AppendString(void *_r, Value fval, Value val) {
(void)fval;
RepeatedPtrField<string>* r = static_cast<RepeatedPtrField<string>*>(_r);
GetValue<ByteRegion*>(val)->AssignToString(r->Add());
return UPB_CONTINUE;
}
// Out-of-line string ////////////////////////////////////////////////////////
static AccessorVTable *GetForOutOfLineString() {
static upb_accessor_vtbl vtbl = {
NULL, &SetOutOfLineString,
// This type is only used for non-repeated string fields.
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
return &vtbl;
}
static Flow SetOutOfLineString(void *m, Value fval, Value val) {
const FieldDef* f = GetValue<const FieldDef*>(fval);
string **str = static_cast<string**>(GetFieldPointer(m, f));
if (*str == &::ProtocolMessage::___empty_internal_proto_string_)
*str = new string();
GetValue<ByteRegion*>(val)->AssignToString(*str);
return UPB_CONTINUE;
}
// Cord //////////////////////////////////////////////////////////////////////
static AccessorVTable *GetForCord() {
static upb_accessor_vtbl vtbl = {
NULL, // StartSubMessage handler
&SetCord,
&PushOffset, // StartSequence handler
NULL, // StartRepeatedSubMessage handler
&AppendCord,
NULL, NULL, NULL, NULL, NULL, NULL};
return &vtbl;
}
static Flow SetCord(void *m, Value fval, Value val) {
const FieldDef* f = GetValue<const FieldDef*>(fval);
Cord* field = static_cast<Cord*>(GetFieldPointer(m, f));
AssignToCord(GetValue<ByteRegion*>(val), field);
return UPB_CONTINUE;
}
static Flow AppendCord(void *_r, Value fval, Value val) {
RepeatedField<Cord>* r = static_cast<RepeatedField<Cord>*>(_r);
AssignToCord(GetValue<ByteRegion*>(val), r->Add());
return UPB_CONTINUE;
}
// SubMessage ////////////////////////////////////////////////////////////////
static AccessorVTable *GetForRequiredMessage() {
static upb_accessor_vtbl vtbl = {
&PushOffset, // StartSubMessage handler
NULL, // Value handler
&PushOffset, // StartSequence handler
&StartRepeatedSubMessage,
NULL, // Repeated value handler
NULL, NULL, NULL, NULL, NULL, NULL};
return &vtbl;
}
static AccessorVTable *GetForWeakMessage() {
static upb_accessor_vtbl vtbl = {
&StartWeakSubMessage, // StartSubMessage handler
NULL, // Value handler
&PushOffset, // StartSequence handler
&StartRepeatedSubMessage,
NULL, // Repeated value handler
NULL, NULL, NULL, NULL, NULL, NULL};
return &vtbl;
}
static AccessorVTable *GetForMessage() {
static upb_accessor_vtbl vtbl = {
&StartSubMessage,
NULL, // Value handler
&PushOffset, // StartSequence handler
&StartRepeatedSubMessage,
NULL, // Repeated value handler
NULL, NULL, NULL, NULL, NULL, NULL};
return &vtbl;
}
static SubFlow StartSubMessage(void *m, Value fval) {
const FieldDef* f = GetValue<const FieldDef*>(fval);
Message **subm = static_cast<Message**>(GetFieldPointer(m, f));
if (*subm == f->prototype) *subm = (*subm)->New();
return UPB_CONTINUE_WITH(*subm);
}
static SubFlow StartWeakSubMessage(void *m, Value fval) {
const FieldDef* f = GetValue<const FieldDef*>(fval);
Message **subm = static_cast<Message**>(GetFieldPointer(m, f));
if (*subm == NULL) {
const Message* prototype = static_cast<const Message*>(f->prototype);
*subm = prototype->New();
}
return UPB_CONTINUE_WITH(*subm);
}
class RepeatedMessageTypeHandler {
public:
typedef void Type;
// AddAllocated() calls this, but only if other objects are sitting
// around waiting for reuse, which we will not do.
static void Delete(Type* t) {
(void)t;
assert(false);
}
};
// Closure is a RepeatedPtrField<SubMessageType>*, but we access it through
// its base class RepeatedPtrFieldBase*.
static SubFlow StartRepeatedSubMessage(void* _r, Value fval) {
const FieldDef* f = GetValue<const FieldDef*>(fval);
RepeatedPtrFieldBase *r = static_cast<RepeatedPtrFieldBase*>(_r);
void *submsg = r->AddFromCleared<RepeatedMessageTypeHandler>();
if (!submsg) {
const Message* prototype = static_cast<const Message*>(f->prototype);
submsg = prototype->New();
r->AddAllocated<RepeatedMessageTypeHandler>(submsg);
}
return UPB_CONTINUE_WITH(submsg);
}
};
#endif
} // namespace proto2_bridge_{google3,opensource}
static const Message* GetPrototypeForMessage(const Message& m) {
const Message* ret = NULL;
MessageFactory* factory = FieldAccessor::GetMessageFactory(m);
if (factory) {
// proto2 generated message or DynamicMessage.
ret = factory->GetPrototype(m.GetDescriptor());
assert(ret);
} else {
// Proto1 message; since proto1 has no dynamic message, it must be
// from the generated factory.
ret = MessageFactory::generated_factory()->GetPrototype(m.GetDescriptor());
assert(ret); // If NULL, then wasn't a proto1 message, can't handle it.
}
assert(ret->GetReflection() == m.GetReflection());
return ret;
}
static const Message* GetPrototypeForField(const Message& m,
const FieldDescriptor* f) {
#ifdef UPB_GOOGLE3
if (f->type() == FieldDescriptor::TYPE_BYTES) {
// Proto1 weak field: the proto2 descriptor says their type is BYTES.
const _pi::Proto2Reflection* r =
dynamic_cast<const _pi::Proto2Reflection*>(m.GetReflection());
assert(r);
const _pi::Field* field = r->GetFieldLayout(f);
assert(field->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK);
return GetPrototypeForMessage(
*static_cast<const Message*>(field->weak_layout()->default_instance));
} else if (dynamic_cast<const _pi::Proto2Reflection*>(m.GetReflection())) {
// Proto1 message; since proto1 has no dynamic message, it must be from
// the generated factory.
const Message* ret =
MessageFactory::generated_factory()->GetPrototype(f->message_type());
assert(ret);
return ret;
}
#endif
assert(f->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE);
// We assume that all submessages (and extensions) will be constructed using
// the same MessageFactory as this message. This doesn't cover the case of
// CodedInputStream::SetExtensionRegistry().
MessageFactory* factory = FieldAccessor::GetMessageFactory(m);
assert(factory); // If neither proto1 nor proto2 we can't handle it.
const Message* ret = factory->GetPrototype(f->message_type());
assert(ret);
return ret;
}
namespace proto2_bridge {
upb::FieldDef* AddFieldDef(const FieldDescriptor* f, upb::MessageDef* md) {
upb::FieldDef* upb_f = upb::FieldDef::New(&upb_f);
upb_f->set_number(f->number());
upb_f->set_name(f->name());
upb_f->set_label(static_cast<upb::Label>(f->label()));
upb_f->set_type(static_cast<upb::FieldType>(f->type()));
if (!FieldAccessor::TrySet(f, md, upb_f)
#ifdef UPB_GOOGLE3
&& !proto2_bridge_google3::Proto1FieldAccessor::TrySet(f, md, upb_f)
#endif
) {
// Unsupported reflection class.
assert(false);
}
if (upb_f->type() == UPB_TYPE(ENUM)) {
// We set the enum default symbolically.
upb_f->set_default(f->default_value_enum()->name());
upb_f->set_subtype_name(f->enum_type()->full_name());
} else {
// Set field default for primitive types. Need to switch on the upb type
// rather than the proto2 type, because upb_f->type() may have been changed
// from BYTES to MESSAGE for a weak field.
switch (upb_types[upb_f->type()].inmemory_type) {
case UPB_CTYPE_INT32:
upb_f->set_default(MakeValue(f->default_value_int32()));
break;
case UPB_CTYPE_INT64:
upb_f->set_default(
MakeValue(static_cast<int64_t>(f->default_value_int64())));
break;
case UPB_CTYPE_UINT32:
upb_f->set_default(MakeValue(f->default_value_uint32()));
break;
case UPB_CTYPE_UINT64:
upb_f->set_default(
MakeValue(static_cast<uint64_t>(f->default_value_uint64())));
break;
case UPB_CTYPE_DOUBLE:
upb_f->set_default(MakeValue(f->default_value_double()));
break;
case UPB_CTYPE_FLOAT:
upb_f->set_default(MakeValue(f->default_value_float()));
break;
case UPB_CTYPE_BOOL:
upb_f->set_default(MakeValue(f->default_value_bool()));
break;
case UPB_CTYPE_BYTEREGION:
upb_f->set_default(f->default_value_string());
break;
}
}
return md->AddField(upb_f, &upb_f) ? upb_f : NULL;
}
upb::MessageDef *NewEmptyMessageDef(const Message& m, void *owner) {
upb::MessageDef *md = upb::MessageDef::New(owner);
md->set_full_name(m.GetDescriptor()->full_name());
md->prototype = GetPrototypeForMessage(m);
return md;
}
upb::EnumDef* NewEnumDef(const EnumDescriptor* desc, void *owner) {
upb::EnumDef* e = upb::EnumDef::New(owner);
e->set_full_name(desc->full_name());
for (int i = 0; i < desc->value_count(); i++) {
const EnumValueDescriptor* val = desc->value(i);
bool success = e->AddValue(val->name(), val->number());
assert(success);
(void)success;
}
return e;
}
void AddAllFields(upb::MessageDef* md) {
const Descriptor* d =
static_cast<const Message*>(md->prototype)->GetDescriptor();
for (int i = 0; i < d->field_count(); i++) {
#ifdef UPB_GOOGLE3
// Skip lazy fields for now since we can't properly handle them.
if (d->field(i)->options().lazy()) continue;
#endif
// Extensions not supported yet.
if (d->field(i)->is_extension()) continue;
AddFieldDef(d->field(i), md);
}
}
upb::MessageDef *NewFullMessageDef(const Message& m, void *owner) {
upb::MessageDef* md = NewEmptyMessageDef(m, owner);
AddAllFields(md);
// TODO(haberman): add unknown field handler and extensions.
return md;
}
typedef std::map<std::string, upb::Def*> SymbolMap;
static upb::MessageDef* NewFinalMessageDefHelper(const Message& m, void *owner,
SymbolMap* symbols) {
upb::MessageDef* md = NewFullMessageDef(m, owner);
// Must do this before processing submessages to prevent infinite recursion.
(*symbols)[std::string(md->full_name())] = md->AsDef();
for (upb::MessageDef::Iterator i(md); !i.Done(); i.Next()) {
upb::FieldDef* f = i.field();
if (!f->HasSubDef()) continue;
SymbolMap::iterator iter = symbols->find(f->subtype_name());
upb::Def* subdef;
if (iter != symbols->end()) {
subdef = iter->second;
} else {
const FieldDescriptor* proto2_f =
m.GetDescriptor()->FindFieldByNumber(f->number());
if (f->type() == UPB_TYPE(ENUM)) {
subdef = NewEnumDef(proto2_f->enum_type(), owner)->AsDef();
(*symbols)[std::string(subdef->full_name())] = subdef;
} else {
assert(f->IsSubmessage());
const Message* prototype = GetPrototypeForField(m, proto2_f);
subdef = NewFinalMessageDefHelper(*prototype, owner, symbols)->AsDef();
}
}
f->set_subdef(subdef);
}
return md;
}
const upb::MessageDef* NewFinalMessageDef(const Message& m, void *owner) {
SymbolMap symbols;
upb::MessageDef* ret = NewFinalMessageDefHelper(m, owner, &symbols);
// Finalize defs.
std::vector<upb::Def*> defs;
SymbolMap::iterator iter;
for (iter = symbols.begin(); iter != symbols.end(); ++iter) {
defs.push_back(iter->second);
}
Status status;
bool success = Def::Finalize(defs, &status);
assert(success);
(void)success;
// Unref all defs except the top-level one that we are returning.
for (int i = 0; i < static_cast<int>(defs.size()); i++) {
if (defs[i] != ret->AsDef()) defs[i]->Unref(owner);
}
return ret;
}
} // namespace proto2_bridge
} // namespace upb