From 16dccd6820ae70c167dc683a316d9eb05d11204a Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Mon, 14 Mar 2022 14:06:36 -0700 Subject: [PATCH 01/54] Updated Ruby to the latest upb. (#9589) (#9630) * Updated Ruby to the latest upb. * Updated to newer upb. --- ruby/ext/google/protobuf_c/convert.c | 8 +- ruby/ext/google/protobuf_c/message.c | 38 +- ruby/ext/google/protobuf_c/protobuf.c | 4 +- ruby/ext/google/protobuf_c/ruby-upb.c | 715 +++++++++------- ruby/ext/google/protobuf_c/ruby-upb.h | 1100 ++++++++++++++++--------- 5 files changed, 1131 insertions(+), 734 deletions(-) diff --git a/ruby/ext/google/protobuf_c/convert.c b/ruby/ext/google/protobuf_c/convert.c index 2b3a6501b06e..bdc71599fbe9 100644 --- a/ruby/ext/google/protobuf_c/convert.c +++ b/ruby/ext/google/protobuf_c/convert.c @@ -340,19 +340,19 @@ uint64_t Msgval_GetHash(upb_MessageValue val, TypeInfo type_info, uint64_t seed) { switch (type_info.type) { case kUpb_CType_Bool: - return Wyhash(&val, 1, seed, kWyhashSalt); + return _upb_Hash(&val, 1, seed); case kUpb_CType_Float: case kUpb_CType_Int32: case kUpb_CType_UInt32: case kUpb_CType_Enum: - return Wyhash(&val, 4, seed, kWyhashSalt); + return _upb_Hash(&val, 4, seed); case kUpb_CType_Double: case kUpb_CType_Int64: case kUpb_CType_UInt64: - return Wyhash(&val, 8, seed, kWyhashSalt); + return _upb_Hash(&val, 8, seed); case kUpb_CType_String: case kUpb_CType_Bytes: - return Wyhash(val.str_val.data, val.str_val.size, seed, kWyhashSalt); + return _upb_Hash(val.str_val.data, val.str_val.size, seed); case kUpb_CType_Message: return Message_Hash(val.msg_val, type_info.def.msgdef, seed); default: diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c index 5d1e72e2ec01..6b8bbaa3c5e5 100644 --- a/ruby/ext/google/protobuf_c/message.c +++ b/ruby/ext/google/protobuf_c/message.c @@ -161,10 +161,8 @@ void Message_PrintMessage(StringBuilder* b, const upb_Message* msg, if (upb_FieldDef_IsMap(field)) { const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field); - const upb_FieldDef* key_f = - upb_MessageDef_FindFieldByNumberWithSize(entry_m, 1); - const upb_FieldDef* val_f = - upb_MessageDef_FindFieldByNumberWithSize(entry_m, 2); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); TypeInfo val_info = TypeInfo_get(val_f); Map_Inspect(b, msgval.map_val, upb_FieldDef_CType(key_f), val_info); } else if (upb_FieldDef_IsRepeated(field)) { @@ -365,7 +363,7 @@ static VALUE Message_field_accessor(VALUE _self, const upb_FieldDef* f, upb_MessageValue wrapper = upb_Message_Get(self->msg, f); const upb_MessageDef* wrapper_m = upb_FieldDef_MessageSubDef(f); const upb_FieldDef* value_f = - upb_MessageDef_FindFieldByNumberWithSize(wrapper_m, 1); + upb_MessageDef_FindFieldByNumber(wrapper_m, 1); upb_MessageValue value = upb_Message_Get(wrapper.msg_val, value_f); return Convert_UpbToRuby(value, TypeInfo_get(value_f), self->arena); } else { @@ -377,8 +375,8 @@ static VALUE Message_field_accessor(VALUE _self, const upb_FieldDef* f, if (argv[1] == Qnil) { upb_Message_ClearField(msg, f); } else { - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumberWithSize( - upb_FieldDef_MessageSubDef(f), 1); + const upb_FieldDef* val_f = + upb_MessageDef_FindFieldByNumber(upb_FieldDef_MessageSubDef(f), 1); upb_MessageValue msgval = Convert_RubyToUpb( argv[1], upb_FieldDef_Name(f), TypeInfo_get(val_f), arena); upb_Message* wrapper = upb_Message_Mutable(msg, f, arena).msg; @@ -527,10 +525,8 @@ static int Map_initialize_kwarg(VALUE key, VALUE val, VALUE _self) { static void Map_InitFromValue(upb_Map* map, const upb_FieldDef* f, VALUE val, upb_Arena* arena) { const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(f); - const upb_FieldDef* key_f = - upb_MessageDef_FindFieldByNumberWithSize(entry_m, 1); - const upb_FieldDef* val_f = - upb_MessageDef_FindFieldByNumberWithSize(entry_m, 2); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); if (TYPE(val) != T_HASH) { rb_raise(rb_eArgError, "Expected Hash object as initializer value for map field '%s' " @@ -748,7 +744,7 @@ uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m, &size); if (data) { - uint64_t ret = Wyhash(data, size, seed, kWyhashSalt); + uint64_t ret = _upb_Hash(data, size, seed); upb_Arena_Free(arena); return ret; } else { @@ -847,10 +843,8 @@ static VALUE Message_CreateHash(const upb_Message* msg, if (upb_FieldDef_IsMap(field)) { const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field); - const upb_FieldDef* key_f = - upb_MessageDef_FindFieldByNumberWithSize(entry_m, 1); - const upb_FieldDef* val_f = - upb_MessageDef_FindFieldByNumberWithSize(entry_m, 2); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); upb_CType key_type = upb_FieldDef_CType(key_f); msg_value = Map_CreateHash(msgval.map_val, key_type, TypeInfo_get(val_f)); } else if (upb_FieldDef_IsRepeated(field)) { @@ -1357,10 +1351,8 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m, upb_Message* msg = upb_Message_New(m, arena); upb_MessageValue sec, nsec; struct timespec time; - const upb_FieldDef* sec_f = - upb_MessageDef_FindFieldByNumberWithSize(m, 1); - const upb_FieldDef* nsec_f = - upb_MessageDef_FindFieldByNumberWithSize(m, 2); + const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nsec_f = upb_MessageDef_FindFieldByNumber(m, 2); if (!rb_obj_is_kind_of(value, rb_cTime)) goto badtype; @@ -1375,10 +1367,8 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m, // Numeric -> Google::Protobuf::Duration upb_Message* msg = upb_Message_New(m, arena); upb_MessageValue sec, nsec; - const upb_FieldDef* sec_f = - upb_MessageDef_FindFieldByNumberWithSize(m, 1); - const upb_FieldDef* nsec_f = - upb_MessageDef_FindFieldByNumberWithSize(m, 2); + const upb_FieldDef* sec_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nsec_f = upb_MessageDef_FindFieldByNumber(m, 2); if (!rb_obj_is_kind_of(value, rb_cNumeric)) goto badtype; diff --git a/ruby/ext/google/protobuf_c/protobuf.c b/ruby/ext/google/protobuf_c/protobuf.c index 2135cca462c9..3c765c564d23 100644 --- a/ruby/ext/google/protobuf_c/protobuf.c +++ b/ruby/ext/google/protobuf_c/protobuf.c @@ -42,12 +42,12 @@ VALUE cTypeError; const upb_FieldDef *map_field_key(const upb_FieldDef *field) { const upb_MessageDef *entry = upb_FieldDef_MessageSubDef(field); - return upb_MessageDef_FindFieldByNumberWithSize(entry, 1); + return upb_MessageDef_FindFieldByNumber(entry, 1); } const upb_FieldDef *map_field_value(const upb_FieldDef *field) { const upb_MessageDef *entry = upb_FieldDef_MessageSubDef(field); - return upb_MessageDef_FindFieldByNumberWithSize(entry, 2); + return upb_MessageDef_FindFieldByNumber(entry, 2); } // ----------------------------------------------------------------------------- diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c index 15f222464354..d50bd99f9c42 100755 --- a/ruby/ext/google/protobuf_c/ruby-upb.c +++ b/ruby/ext/google/protobuf_c/ruby-upb.c @@ -254,6 +254,14 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); ((void)(addr), (void)(size)) #endif +/* Disable proto2 arena behavior (TEMPORARY) **********************************/ + +#ifdef UPB_DISABLE_PROTO2_ENUM_CHECKING +#define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 1 +#else +#define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 0 +#endif + /** upb/decode.c ************************************************************/ #include @@ -610,6 +618,18 @@ static char* encode_varint32(uint32_t val, char* ptr) { return ptr; } +static void upb_Decode_AddUnknownVarints(upb_Decoder* d, upb_Message* msg, + uint32_t val1, uint32_t val2) { + char buf[20]; + char* end = buf; + end = encode_varint32(val1, end); + end = encode_varint32(val2, end); + + if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) { + decode_err(d, kUpb_DecodeStatus_OutOfMemory); + } +} + UPB_NOINLINE static bool decode_checkenum_slow(upb_Decoder* d, const char* ptr, upb_Message* msg, const upb_MiniTable_Enum* e, @@ -623,17 +643,9 @@ static bool decode_checkenum_slow(upb_Decoder* d, const char* ptr, // Unrecognized enum goes into unknown fields. // For packed fields the tag could be arbitrarily far in the past, so we - // just re-encode the tag here. - char buf[20]; - char* end = buf; + // just re-encode the tag and value here. uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Varint; - end = encode_varint32(tag, end); - end = encode_varint32(v, end); - - if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) { - decode_err(d, kUpb_DecodeStatus_OutOfMemory); - } - + upb_Decode_AddUnknownVarints(d, msg, tag, v); return false; } @@ -852,8 +864,20 @@ static const char* decode_tomap(upb_Decoder* d, const char* ptr, upb_value_ptr(_upb_Message_New(entry->subs[0].submsg, &d->arena)); } + const char* start = ptr; ptr = decode_tosubmsg(d, ptr, &ent.k, subs, field, val->size); - _upb_Map_Set(map, &ent.k, map->key_size, &ent.v, map->val_size, &d->arena); + // check if ent had any unknown fields + size_t size; + upb_Message_GetUnknown(&ent.k, &size); + if (size != 0) { + uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Delimited; + upb_Decode_AddUnknownVarints(d, msg, tag, (uint32_t)(ptr - start)); + if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { + decode_err(d, kUpb_DecodeStatus_OutOfMemory); + } + } else { + _upb_Map_Set(map, &ent.k, map->key_size, &ent.v, map->val_size, &d->arena); + } return ptr; } @@ -967,7 +991,7 @@ static const char* decode_msgset(upb_Decoder* d, const char* ptr, .fields = NULL, .size = 0, .field_count = 0, - .ext = upb_ExtMode_IsMessageSet_ITEM, + .ext = kUpb_ExtMode_IsMessageSet_ITEM, .dense_below = 0, .table_mask = -1}; return decode_group(d, ptr, msg, &item_layout, 1); @@ -1005,19 +1029,19 @@ static const upb_MiniTable_Field* decode_findfield(upb_Decoder* d, if (d->extreg) { switch (l->ext) { - case upb_ExtMode_Extendable: { + case kUpb_ExtMode_Extendable: { const upb_MiniTable_Extension* ext = _upb_extreg_get(d->extreg, l, field_number); if (ext) return &ext->field; break; } - case upb_ExtMode_IsMessageSet: + case kUpb_ExtMode_IsMessageSet: if (field_number == _UPB_MSGSET_ITEM) { static upb_MiniTable_Field item = {0, 0, 0, 0, TYPE_MSGSET_ITEM, 0}; return &item; } break; - case upb_ExtMode_IsMessageSet_ITEM: + case kUpb_ExtMode_IsMessageSet_ITEM: switch (field_number) { case _UPB_MSGSET_TYPEID: { static upb_MiniTable_Field type_id = { @@ -1110,7 +1134,7 @@ static const char* decode_known(upb_Decoder* d, const char* ptr, const upb_MiniTable_Sub* subs = layout->subs; uint8_t mode = field->mode; - if (UPB_UNLIKELY(mode & upb_LabelFlags_IsExtension)) { + if (UPB_UNLIKELY(mode & kUpb_LabelFlags_IsExtension)) { const upb_MiniTable_Extension* ext_layout = (const upb_MiniTable_Extension*)field; upb_Message_Extension* ext = @@ -1291,7 +1315,7 @@ upb_DecodeStatus upb_Decode(const char* buf, size_t size, void* msg, if (size <= 16) { memset(&state.patch, 0, 32); - memcpy(&state.patch, buf, size); + if (size) memcpy(&state.patch, buf, size); buf = state.patch; state.end = buf + size; state.limit = 0; @@ -1593,7 +1617,7 @@ static void encode_array(upb_encstate* e, const upb_Message* msg, const upb_MiniTable_Sub* subs, const upb_MiniTable_Field* f) { const upb_Array* arr = *UPB_PTR_AT(msg, f->offset, upb_Array*); - bool packed = f->mode & upb_LabelFlags_IsPacked; + bool packed = f->mode & kUpb_LabelFlags_IsPacked; size_t pre_len = e->limit - e->ptr; if (arr == NULL || arr->len == 0) { @@ -1747,23 +1771,29 @@ static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, if (f->presence == 0) { /* Proto3 presence or map/array. */ const void* mem = UPB_PTR_AT(msg, f->offset, void); - switch (f->mode >> upb_FieldRep_Shift) { - case upb_FieldRep_1Byte: { + switch (f->mode >> kUpb_FieldRep_Shift) { + case kUpb_FieldRep_1Byte: { char ch; memcpy(&ch, mem, 1); return ch != 0; } - case upb_FieldRep_4Byte: { +#if UINTPTR_MAX == 0xffffffff + case kUpb_FieldRep_Pointer: +#endif + case kUpb_FieldRep_4Byte: { uint32_t u32; memcpy(&u32, mem, 4); return u32 != 0; } - case upb_FieldRep_8Byte: { +#if UINTPTR_MAX != 0xffffffff + case kUpb_FieldRep_Pointer: +#endif + case kUpb_FieldRep_8Byte: { uint64_t u64; memcpy(&u64, mem, 8); return u64 != 0; } - case upb_FieldRep_StringView: { + case kUpb_FieldRep_StringView: { const upb_StringView* str = (const upb_StringView*)mem; return str->size != 0; } @@ -1837,16 +1867,16 @@ static void encode_message(upb_encstate* e, const upb_Message* msg, } } - if (m->ext != upb_ExtMode_NonExtendable) { + if (m->ext != kUpb_ExtMode_NonExtendable) { /* Encode all extensions together. Unlike C++, we do not attempt to keep * these in field number order relative to normal fields or even to each * other. */ size_t ext_count; const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &ext_count); - const upb_Message_Extension* end = ext + ext_count; if (ext_count) { + const upb_Message_Extension* end = ext + ext_count; for (; ext != end; ext++) { - if (UPB_UNLIKELY(m->ext == upb_ExtMode_IsMessageSet)) { + if (UPB_UNLIKELY(m->ext == kUpb_ExtMode_IsMessageSet)) { encode_msgset_item(e, ext); } else { encode_field(e, &ext->data, &ext->ext->sub, &ext->ext->field); @@ -1855,12 +1885,14 @@ static void encode_message(upb_encstate* e, const upb_Message* msg, } } - const upb_MiniTable_Field* f = &m->fields[m->field_count]; - const upb_MiniTable_Field* first = &m->fields[0]; - while (f != first) { - f--; - if (encode_shouldencode(e, msg, m->subs, f)) { - encode_field(e, msg, m->subs, f); + if (m->field_count) { + const upb_MiniTable_Field* f = &m->fields[m->field_count]; + const upb_MiniTable_Field* first = &m->fields[0]; + while (f != first) { + f--; + if (encode_shouldencode(e, msg, m->subs, f)) { + encode_field(e, msg, m->subs, f); + } } } @@ -1927,7 +1959,7 @@ static bool realloc_internal(upb_Message* msg, size_t need, upb_Arena* arena) { upb_Message_Internal* in = upb_Message_Getinternal(msg); if (!in->internal) { /* No internal data, allocate from scratch. */ - size_t size = UPB_MAX(128, _upb_Log2Ceilingsize(need + overhead)); + size_t size = UPB_MAX(128, _upb_Log2CeilingSize(need + overhead)); upb_Message_InternalData* internal = upb_Arena_Malloc(arena, size); if (!internal) return false; internal->size = size; @@ -1936,7 +1968,7 @@ static bool realloc_internal(upb_Message* msg, size_t need, upb_Arena* arena) { in->internal = internal; } else if (in->internal->ext_begin - in->internal->unknown_end < need) { /* Internal data is too small, reallocate. */ - size_t new_size = _upb_Log2Ceilingsize(in->internal->size + need); + size_t new_size = _upb_Log2CeilingSize(in->internal->size + need); size_t ext_bytes = in->internal->size - in->internal->ext_begin; size_t new_ext_begin = new_size - ext_bytes; upb_Message_InternalData* internal = @@ -2182,7 +2214,7 @@ bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, /* Grow s->entries if necessary. */ if (sorted->end > s->cap) { - s->cap = _upb_Log2Ceilingsize(sorted->end); + s->cap = _upb_Log2CeilingSize(sorted->end); s->entries = realloc(s->entries, s->cap * sizeof(*s->entries)); if (!s->entries) return false; } @@ -2624,7 +2656,7 @@ static uint64_t WyhashMix(uint64_t v0, uint64_t v1) { return low ^ high; } -uint64_t Wyhash(const void* data, size_t len, uint64_t seed, +static uint64_t Wyhash(const void* data, size_t len, uint64_t seed, const uint64_t salt[]) { const uint8_t* ptr = (const uint8_t*)data; uint64_t starting_length = (uint64_t)len; @@ -2708,14 +2740,18 @@ const uint64_t kWyhashSalt[5] = { 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL, }; -static uint32_t table_hash(const char* p, size_t n) { - return Wyhash(p, n, 0, kWyhashSalt); +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed) { + return Wyhash(p, n, seed, kWyhashSalt); +} + +static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) { + return _upb_Hash(p, n, 0); } static uint32_t strhash(upb_tabkey key) { uint32_t len; char* str = upb_tabstr(key, &len); - return table_hash(str, len); + return _upb_Hash_NoSeed(str, len); } static bool streql(upb_tabkey k1, lookupkey_t k2) { @@ -2771,20 +2807,20 @@ bool upb_strtable_insert(upb_strtable* t, const char* k, size_t len, tabkey = strcopy(key, a); if (tabkey == 0) return false; - hash = table_hash(key.str.str, key.str.len); + hash = _upb_Hash_NoSeed(key.str.str, key.str.len); insert(&t->t, key, tabkey, v, hash, &strhash, &streql); return true; } bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, upb_value* v) { - uint32_t hash = table_hash(key, len); + uint32_t hash = _upb_Hash_NoSeed(key, len); return lookup(&t->t, strkey2(key, len), v, hash, &streql); } bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, upb_value* val) { - uint32_t hash = table_hash(key, len); + uint32_t hash = _upb_Hash_NoSeed(key, len); upb_tabkey tabkey; return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql); } @@ -3511,7 +3547,6 @@ static void upb_FixLocale(char* p) { } } - void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size) { assert(size >= kUpb_RoundTripBufferSize); snprintf(buf, size, "%.*g", DBL_DIG, val); @@ -4575,13 +4610,13 @@ static const upb_MiniTable_Sub google_protobuf_FileDescriptorSet_submsgs[1] = { }; static const upb_MiniTable_Field google_protobuf_FileDescriptorSet__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_FileDescriptorSet_msginit = { &google_protobuf_FileDescriptorSet_submsgs[0], &google_protobuf_FileDescriptorSet__fields[0], - UPB_SIZE(8, 8), 1, upb_ExtMode_NonExtendable, 1, 255, 0, + UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_FileDescriptorProto_submsgs[6] = { @@ -4594,24 +4629,24 @@ static const upb_MiniTable_Sub google_protobuf_FileDescriptorProto_submsgs[6] = }; static const upb_MiniTable_Field google_protobuf_FileDescriptorProto__fields[12] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {3, UPB_SIZE(36, 72), 0, 0, 12, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {4, UPB_SIZE(40, 80), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {5, UPB_SIZE(44, 88), 0, 1, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {6, UPB_SIZE(48, 96), 0, 4, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {7, UPB_SIZE(52, 104), 0, 2, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {8, UPB_SIZE(28, 56), 3, 3, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {9, UPB_SIZE(32, 64), 4, 5, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {10, UPB_SIZE(56, 112), 0, 0, 5, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {11, UPB_SIZE(60, 120), 0, 0, 5, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {12, UPB_SIZE(20, 40), 5, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, + {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(36, 72), 0, 0, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(40, 80), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(44, 88), 0, 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(48, 96), 0, 4, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(52, 104), 0, 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(28, 56), 3, 3, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(32, 64), 4, 5, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(56, 112), 0, 0, 5, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(60, 120), 0, 0, 5, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {12, UPB_SIZE(20, 40), 5, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_FileDescriptorProto_msginit = { &google_protobuf_FileDescriptorProto_submsgs[0], &google_protobuf_FileDescriptorProto__fields[0], - UPB_SIZE(64, 128), 12, upb_ExtMode_NonExtendable, 12, 255, 0, + UPB_SIZE(64, 128), 12, kUpb_ExtMode_NonExtendable, 12, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_DescriptorProto_submsgs[7] = { @@ -4625,22 +4660,22 @@ static const upb_MiniTable_Sub google_protobuf_DescriptorProto_submsgs[7] = { }; static const upb_MiniTable_Field google_protobuf_DescriptorProto__fields[10] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(16, 32), 0, 4, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {3, UPB_SIZE(20, 40), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {4, UPB_SIZE(24, 48), 0, 3, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {5, UPB_SIZE(28, 56), 0, 1, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {6, UPB_SIZE(32, 64), 0, 4, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {7, UPB_SIZE(12, 24), 2, 5, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {8, UPB_SIZE(36, 72), 0, 6, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {9, UPB_SIZE(40, 80), 0, 2, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {10, UPB_SIZE(44, 88), 0, 0, 12, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(16, 32), 0, 4, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(20, 40), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(24, 48), 0, 3, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(28, 56), 0, 1, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(32, 64), 0, 4, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(12, 24), 2, 5, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(36, 72), 0, 6, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(40, 80), 0, 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(44, 88), 0, 0, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_DescriptorProto_msginit = { &google_protobuf_DescriptorProto_submsgs[0], &google_protobuf_DescriptorProto__fields[0], - UPB_SIZE(48, 96), 10, upb_ExtMode_NonExtendable, 10, 255, 0, + UPB_SIZE(48, 96), 10, kUpb_ExtMode_NonExtendable, 10, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { @@ -4648,26 +4683,26 @@ static const upb_MiniTable_Sub google_protobuf_DescriptorProto_ExtensionRange_su }; static const upb_MiniTable_Field google_protobuf_DescriptorProto_ExtensionRange__fields[3] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 16), 3, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(12, 16), 3, 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msginit = { &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0], &google_protobuf_DescriptorProto_ExtensionRange__fields[0], - UPB_SIZE(16, 24), 3, upb_ExtMode_NonExtendable, 3, 255, 0, + UPB_SIZE(16, 24), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, }; static const upb_MiniTable_Field google_protobuf_DescriptorProto_ReservedRange__fields[2] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, + {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msginit = { NULL, &google_protobuf_DescriptorProto_ReservedRange__fields[0], - UPB_SIZE(16, 16), 2, upb_ExtMode_NonExtendable, 2, 255, 0, + UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_ExtensionRangeOptions_submsgs[1] = { @@ -4675,13 +4710,13 @@ static const upb_MiniTable_Sub google_protobuf_ExtensionRangeOptions_submsgs[1] }; static const upb_MiniTable_Field google_protobuf_ExtensionRangeOptions__fields[1] = { - {999, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {999, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_ExtensionRangeOptions_msginit = { &google_protobuf_ExtensionRangeOptions_submsgs[0], &google_protobuf_ExtensionRangeOptions__fields[0], - UPB_SIZE(8, 8), 1, upb_ExtMode_Extendable, 0, 255, 0, + UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_FieldDescriptorProto_submsgs[3] = { @@ -4691,23 +4726,23 @@ static const upb_MiniTable_Sub google_protobuf_FieldDescriptorProto_submsgs[3] = }; static const upb_MiniTable_Field google_protobuf_FieldDescriptorProto__fields[11] = { - {1, UPB_SIZE(24, 24), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(32, 40), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 12), 3, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {4, UPB_SIZE(4, 4), 4, 1, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {5, UPB_SIZE(8, 8), 5, 2, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {6, UPB_SIZE(40, 56), 6, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {7, UPB_SIZE(48, 72), 7, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {8, UPB_SIZE(64, 104), 8, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {9, UPB_SIZE(16, 16), 9, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {10, UPB_SIZE(56, 88), 10, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {17, UPB_SIZE(20, 20), 11, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, + {1, UPB_SIZE(24, 24), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(32, 40), 2, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(12, 12), 3, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(4, 4), 4, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(8, 8), 5, 2, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(40, 56), 6, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(48, 72), 7, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(64, 104), 8, 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(16, 16), 9, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(56, 88), 10, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {17, UPB_SIZE(20, 20), 11, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_FieldDescriptorProto_msginit = { &google_protobuf_FieldDescriptorProto_submsgs[0], &google_protobuf_FieldDescriptorProto__fields[0], - UPB_SIZE(72, 112), 11, upb_ExtMode_NonExtendable, 10, 255, 0, + UPB_SIZE(72, 112), 11, kUpb_ExtMode_NonExtendable, 10, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_OneofDescriptorProto_submsgs[1] = { @@ -4715,14 +4750,14 @@ static const upb_MiniTable_Sub google_protobuf_OneofDescriptorProto_submsgs[1] = }; static const upb_MiniTable_Field google_protobuf_OneofDescriptorProto__fields[2] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 24), 2, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), 2, 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_OneofDescriptorProto_msginit = { &google_protobuf_OneofDescriptorProto_submsgs[0], &google_protobuf_OneofDescriptorProto__fields[0], - UPB_SIZE(16, 32), 2, upb_ExtMode_NonExtendable, 2, 255, 0, + UPB_SIZE(16, 32), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_EnumDescriptorProto_submsgs[3] = { @@ -4732,28 +4767,28 @@ static const upb_MiniTable_Sub google_protobuf_EnumDescriptorProto_submsgs[3] = }; static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto__fields[5] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(16, 32), 0, 2, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 24), 2, 1, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {4, UPB_SIZE(20, 40), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {5, UPB_SIZE(24, 48), 0, 0, 12, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(16, 32), 0, 2, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(12, 24), 2, 1, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(20, 40), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(24, 48), 0, 0, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_EnumDescriptorProto_msginit = { &google_protobuf_EnumDescriptorProto_submsgs[0], &google_protobuf_EnumDescriptorProto__fields[0], - UPB_SIZE(32, 64), 5, upb_ExtMode_NonExtendable, 5, 255, 0, + UPB_SIZE(32, 64), 5, kUpb_ExtMode_NonExtendable, 5, 255, 0, }; static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, + {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit = { NULL, &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0], - UPB_SIZE(16, 16), 2, upb_ExtMode_NonExtendable, 2, 255, 0, + UPB_SIZE(16, 16), 2, kUpb_ExtMode_NonExtendable, 2, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_EnumValueDescriptorProto_submsgs[1] = { @@ -4761,15 +4796,15 @@ static const upb_MiniTable_Sub google_protobuf_EnumValueDescriptorProto_submsgs[ }; static const upb_MiniTable_Field google_protobuf_EnumValueDescriptorProto__fields[3] = { - {1, UPB_SIZE(8, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(4, 4), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {3, UPB_SIZE(16, 24), 3, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {1, UPB_SIZE(8, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(4, 4), 2, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(16, 24), 3, 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msginit = { &google_protobuf_EnumValueDescriptorProto_submsgs[0], &google_protobuf_EnumValueDescriptorProto__fields[0], - UPB_SIZE(24, 32), 3, upb_ExtMode_NonExtendable, 3, 255, 0, + UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_ServiceDescriptorProto_submsgs[2] = { @@ -4778,15 +4813,15 @@ static const upb_MiniTable_Sub google_protobuf_ServiceDescriptorProto_submsgs[2] }; static const upb_MiniTable_Field google_protobuf_ServiceDescriptorProto__fields[3] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(16, 32), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {3, UPB_SIZE(12, 24), 2, 1, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(16, 32), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(12, 24), 2, 1, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_ServiceDescriptorProto_msginit = { &google_protobuf_ServiceDescriptorProto_submsgs[0], &google_protobuf_ServiceDescriptorProto__fields[0], - UPB_SIZE(24, 48), 3, upb_ExtMode_NonExtendable, 3, 255, 0, + UPB_SIZE(24, 48), 3, kUpb_ExtMode_NonExtendable, 3, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_MethodDescriptorProto_submsgs[1] = { @@ -4794,18 +4829,18 @@ static const upb_MiniTable_Sub google_protobuf_MethodDescriptorProto_submsgs[1] }; static const upb_MiniTable_Field google_protobuf_MethodDescriptorProto__fields[6] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {3, UPB_SIZE(20, 40), 3, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {4, UPB_SIZE(28, 56), 4, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {5, UPB_SIZE(1, 1), 5, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {6, UPB_SIZE(2, 2), 6, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, + {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(20, 40), 3, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(28, 56), 4, 0, 11, kUpb_FieldMode_Scalar | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(1, 1), 5, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(2, 2), 6, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_MethodDescriptorProto_msginit = { &google_protobuf_MethodDescriptorProto_submsgs[0], &google_protobuf_MethodDescriptorProto__fields[0], - UPB_SIZE(32, 64), 6, upb_ExtMode_NonExtendable, 6, 255, 0, + UPB_SIZE(32, 64), 6, kUpb_ExtMode_NonExtendable, 6, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_FileOptions_submsgs[2] = { @@ -4814,33 +4849,33 @@ static const upb_MiniTable_Sub google_protobuf_FileOptions_submsgs[2] = { }; static const upb_MiniTable_Field google_protobuf_FileOptions__fields[21] = { - {1, UPB_SIZE(20, 24), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {8, UPB_SIZE(28, 40), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {9, UPB_SIZE(4, 4), 3, 1, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {10, UPB_SIZE(8, 8), 4, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {11, UPB_SIZE(36, 56), 5, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {16, UPB_SIZE(9, 9), 6, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {17, UPB_SIZE(10, 10), 7, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {18, UPB_SIZE(11, 11), 8, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {20, UPB_SIZE(12, 12), 9, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {23, UPB_SIZE(13, 13), 10, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {27, UPB_SIZE(14, 14), 11, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {31, UPB_SIZE(15, 15), 12, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {36, UPB_SIZE(44, 72), 13, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {37, UPB_SIZE(52, 88), 14, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {39, UPB_SIZE(60, 104), 15, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {40, UPB_SIZE(68, 120), 16, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {41, UPB_SIZE(76, 136), 17, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {42, UPB_SIZE(16, 16), 18, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {44, UPB_SIZE(84, 152), 19, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {45, UPB_SIZE(92, 168), 20, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {999, UPB_SIZE(100, 184), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {1, UPB_SIZE(20, 24), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(28, 40), 2, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {9, UPB_SIZE(4, 4), 3, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(8, 8), 4, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {11, UPB_SIZE(36, 56), 5, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {16, UPB_SIZE(9, 9), 6, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {17, UPB_SIZE(10, 10), 7, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {18, UPB_SIZE(11, 11), 8, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {20, UPB_SIZE(12, 12), 9, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {23, UPB_SIZE(13, 13), 10, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {27, UPB_SIZE(14, 14), 11, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {31, UPB_SIZE(15, 15), 12, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {36, UPB_SIZE(44, 72), 13, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {37, UPB_SIZE(52, 88), 14, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {39, UPB_SIZE(60, 104), 15, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {40, UPB_SIZE(68, 120), 16, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {41, UPB_SIZE(76, 136), 17, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {42, UPB_SIZE(16, 16), 18, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {44, UPB_SIZE(84, 152), 19, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {45, UPB_SIZE(92, 168), 20, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(100, 184), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_FileOptions_msginit = { &google_protobuf_FileOptions_submsgs[0], &google_protobuf_FileOptions__fields[0], - UPB_SIZE(104, 192), 21, upb_ExtMode_Extendable, 1, 255, 0, + UPB_SIZE(104, 192), 21, kUpb_ExtMode_Extendable, 1, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_MessageOptions_submsgs[1] = { @@ -4848,17 +4883,17 @@ static const upb_MiniTable_Sub google_protobuf_MessageOptions_submsgs[1] = { }; static const upb_MiniTable_Field google_protobuf_MessageOptions__fields[5] = { - {1, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {2, UPB_SIZE(2, 2), 2, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {3, UPB_SIZE(3, 3), 3, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {7, UPB_SIZE(4, 4), 4, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(8, 8), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {1, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(2, 2), 2, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(3, 3), 3, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(4, 4), 4, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(8, 8), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_MessageOptions_msginit = { &google_protobuf_MessageOptions_submsgs[0], &google_protobuf_MessageOptions__fields[0], - UPB_SIZE(16, 16), 5, upb_ExtMode_Extendable, 3, 255, 0, + UPB_SIZE(16, 16), 5, kUpb_ExtMode_Extendable, 3, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_FieldOptions_submsgs[3] = { @@ -4867,20 +4902,21 @@ static const upb_MiniTable_Sub google_protobuf_FieldOptions_submsgs[3] = { {.subenum = &google_protobuf_FieldOptions_JSType_enuminit}, }; -static const upb_MiniTable_Field google_protobuf_FieldOptions__fields[7] = { - {1, UPB_SIZE(4, 4), 1, 1, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 12), 2, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {3, UPB_SIZE(13, 13), 3, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {5, UPB_SIZE(14, 14), 4, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {6, UPB_SIZE(8, 8), 5, 2, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {10, UPB_SIZE(15, 15), 6, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(16, 16), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, +static const upb_MiniTable_Field google_protobuf_FieldOptions__fields[8] = { + {1, UPB_SIZE(4, 4), 1, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 12), 2, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(13, 13), 3, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(14, 14), 4, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(8, 8), 5, 2, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {10, UPB_SIZE(15, 15), 6, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {15, UPB_SIZE(16, 16), 7, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(20, 24), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_FieldOptions_msginit = { &google_protobuf_FieldOptions_submsgs[0], &google_protobuf_FieldOptions__fields[0], - UPB_SIZE(24, 24), 7, upb_ExtMode_Extendable, 3, 255, 0, + UPB_SIZE(24, 32), 8, kUpb_ExtMode_Extendable, 3, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_OneofOptions_submsgs[1] = { @@ -4888,13 +4924,13 @@ static const upb_MiniTable_Sub google_protobuf_OneofOptions_submsgs[1] = { }; static const upb_MiniTable_Field google_protobuf_OneofOptions__fields[1] = { - {999, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {999, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_OneofOptions_msginit = { &google_protobuf_OneofOptions_submsgs[0], &google_protobuf_OneofOptions__fields[0], - UPB_SIZE(8, 8), 1, upb_ExtMode_Extendable, 0, 255, 0, + UPB_SIZE(8, 8), 1, kUpb_ExtMode_Extendable, 0, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_EnumOptions_submsgs[1] = { @@ -4902,15 +4938,15 @@ static const upb_MiniTable_Sub google_protobuf_EnumOptions_submsgs[1] = { }; static const upb_MiniTable_Field google_protobuf_EnumOptions__fields[3] = { - {2, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {3, UPB_SIZE(2, 2), 2, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {2, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(2, 2), 2, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_EnumOptions_msginit = { &google_protobuf_EnumOptions_submsgs[0], &google_protobuf_EnumOptions__fields[0], - UPB_SIZE(8, 16), 3, upb_ExtMode_Extendable, 0, 255, 0, + UPB_SIZE(8, 16), 3, kUpb_ExtMode_Extendable, 0, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_EnumValueOptions_submsgs[1] = { @@ -4918,14 +4954,14 @@ static const upb_MiniTable_Sub google_protobuf_EnumValueOptions_submsgs[1] = { }; static const upb_MiniTable_Field google_protobuf_EnumValueOptions__fields[2] = { - {1, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {1, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_EnumValueOptions_msginit = { &google_protobuf_EnumValueOptions_submsgs[0], &google_protobuf_EnumValueOptions__fields[0], - UPB_SIZE(8, 16), 2, upb_ExtMode_Extendable, 1, 255, 0, + UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 1, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_ServiceOptions_submsgs[1] = { @@ -4933,14 +4969,14 @@ static const upb_MiniTable_Sub google_protobuf_ServiceOptions_submsgs[1] = { }; static const upb_MiniTable_Field google_protobuf_ServiceOptions__fields[2] = { - {33, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {33, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_ServiceOptions_msginit = { &google_protobuf_ServiceOptions_submsgs[0], &google_protobuf_ServiceOptions__fields[0], - UPB_SIZE(8, 16), 2, upb_ExtMode_Extendable, 0, 255, 0, + UPB_SIZE(8, 16), 2, kUpb_ExtMode_Extendable, 0, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_MethodOptions_submsgs[2] = { @@ -4949,15 +4985,15 @@ static const upb_MiniTable_Sub google_protobuf_MethodOptions_submsgs[2] = { }; static const upb_MiniTable_Field google_protobuf_MethodOptions__fields[3] = { - {33, UPB_SIZE(8, 8), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, - {34, UPB_SIZE(4, 4), 2, 1, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {999, UPB_SIZE(12, 16), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {33, UPB_SIZE(8, 8), 1, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, + {34, UPB_SIZE(4, 4), 2, 1, 14, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {999, UPB_SIZE(12, 16), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_MethodOptions_msginit = { &google_protobuf_MethodOptions_submsgs[0], &google_protobuf_MethodOptions__fields[0], - UPB_SIZE(16, 24), 3, upb_ExtMode_Extendable, 0, 255, 0, + UPB_SIZE(16, 24), 3, kUpb_ExtMode_Extendable, 0, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_UninterpretedOption_submsgs[1] = { @@ -4965,30 +5001,30 @@ static const upb_MiniTable_Sub google_protobuf_UninterpretedOption_submsgs[1] = }; static const upb_MiniTable_Field google_protobuf_UninterpretedOption__fields[7] = { - {2, UPB_SIZE(56, 80), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {3, UPB_SIZE(32, 32), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {4, UPB_SIZE(8, 8), 2, 0, 4, kUpb_FieldMode_Scalar | (upb_FieldRep_8Byte << upb_FieldRep_Shift)}, - {5, UPB_SIZE(16, 16), 3, 0, 3, kUpb_FieldMode_Scalar | (upb_FieldRep_8Byte << upb_FieldRep_Shift)}, - {6, UPB_SIZE(24, 24), 4, 0, 1, kUpb_FieldMode_Scalar | (upb_FieldRep_8Byte << upb_FieldRep_Shift)}, - {7, UPB_SIZE(40, 48), 5, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {8, UPB_SIZE(48, 64), 6, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, + {2, UPB_SIZE(56, 80), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(32, 32), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(8, 8), 2, 0, 4, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {5, UPB_SIZE(16, 16), 3, 0, 3, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(24, 24), 4, 0, 1, kUpb_FieldMode_Scalar | (kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, + {7, UPB_SIZE(40, 48), 5, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {8, UPB_SIZE(48, 64), 6, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_UninterpretedOption_msginit = { &google_protobuf_UninterpretedOption_submsgs[0], &google_protobuf_UninterpretedOption__fields[0], - UPB_SIZE(64, 96), 7, upb_ExtMode_NonExtendable, 0, 255, 0, + UPB_SIZE(64, 96), 7, kUpb_ExtMode_NonExtendable, 0, 255, 0, }; static const upb_MiniTable_Field google_protobuf_UninterpretedOption_NamePart__fields[2] = { - {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {2, UPB_SIZE(1, 1), 2, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)}, + {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(1, 1), 2, 0, 8, kUpb_FieldMode_Scalar | (kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msginit = { NULL, &google_protobuf_UninterpretedOption_NamePart__fields[0], - UPB_SIZE(16, 32), 2, upb_ExtMode_NonExtendable, 2, 255, 2, + UPB_SIZE(16, 32), 2, kUpb_ExtMode_NonExtendable, 2, 255, 2, }; static const upb_MiniTable_Sub google_protobuf_SourceCodeInfo_submsgs[1] = { @@ -4996,27 +5032,27 @@ static const upb_MiniTable_Sub google_protobuf_SourceCodeInfo_submsgs[1] = { }; static const upb_MiniTable_Field google_protobuf_SourceCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_SourceCodeInfo_msginit = { &google_protobuf_SourceCodeInfo_submsgs[0], &google_protobuf_SourceCodeInfo__fields[0], - UPB_SIZE(8, 8), 1, upb_ExtMode_NonExtendable, 1, 255, 0, + UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, }; static const upb_MiniTable_Field google_protobuf_SourceCodeInfo_Location__fields[5] = { - {1, UPB_SIZE(20, 40), 0, 0, 5, kUpb_FieldMode_Array | upb_LabelFlags_IsPacked | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {2, UPB_SIZE(24, 48), 0, 0, 5, kUpb_FieldMode_Array | upb_LabelFlags_IsPacked | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {3, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {4, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {6, UPB_SIZE(28, 56), 0, 0, 12, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {1, UPB_SIZE(20, 40), 0, 0, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(24, 48), 0, 0, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {6, UPB_SIZE(28, 56), 0, 0, 12, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msginit = { NULL, &google_protobuf_SourceCodeInfo_Location__fields[0], - UPB_SIZE(32, 64), 5, upb_ExtMode_NonExtendable, 4, 255, 0, + UPB_SIZE(32, 64), 5, kUpb_ExtMode_NonExtendable, 4, 255, 0, }; static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_submsgs[1] = { @@ -5024,26 +5060,26 @@ static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_submsgs[1] = { }; static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, + {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_GeneratedCodeInfo_msginit = { &google_protobuf_GeneratedCodeInfo_submsgs[0], &google_protobuf_GeneratedCodeInfo__fields[0], - UPB_SIZE(8, 8), 1, upb_ExtMode_NonExtendable, 1, 255, 0, + UPB_SIZE(8, 8), 1, kUpb_ExtMode_NonExtendable, 1, 255, 0, }; static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = { - {1, UPB_SIZE(20, 32), 0, 0, 5, kUpb_FieldMode_Array | upb_LabelFlags_IsPacked | (upb_FieldRep_Pointer << upb_FieldRep_Shift)}, - {2, UPB_SIZE(12, 16), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)}, - {3, UPB_SIZE(4, 4), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, - {4, UPB_SIZE(8, 8), 3, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)}, + {1, UPB_SIZE(20, 32), 0, 0, 5, kUpb_FieldMode_Array | kUpb_LabelFlags_IsPacked | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift)}, + {2, UPB_SIZE(12, 16), 1, 0, 12, kUpb_FieldMode_Scalar | (kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, + {3, UPB_SIZE(4, 4), 2, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, + {4, UPB_SIZE(8, 8), 3, 0, 5, kUpb_FieldMode_Scalar | (kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, }; const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msginit = { NULL, &google_protobuf_GeneratedCodeInfo_Annotation__fields[0], - UPB_SIZE(24, 48), 4, upb_ExtMode_NonExtendable, 4, 255, 0, + UPB_SIZE(24, 48), 4, kUpb_ExtMode_NonExtendable, 4, 255, 0, }; static const upb_MiniTable *messages_layout[27] = { @@ -5190,6 +5226,9 @@ struct upb_FieldDef { bool has_json_name_; upb_FieldType type_; upb_Label label_; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; struct upb_ExtensionRange { @@ -5227,6 +5266,9 @@ struct upb_MessageDef { int nested_ext_count; bool in_message_set; upb_WellKnown well_known_type; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; struct upb_EnumDef { @@ -5240,6 +5282,9 @@ struct upb_EnumDef { const upb_EnumValueDef* values; int value_count; int32_t defaultval; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; struct upb_EnumValueDef { @@ -5258,6 +5303,9 @@ struct upb_OneofDef { const upb_FieldDef** fields; upb_strtable ntof; upb_inttable itof; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; struct upb_FileDef { @@ -5292,6 +5340,7 @@ struct upb_MethodDef { const char* full_name; const upb_MessageDef* input_type; const upb_MessageDef* output_type; + int index; bool client_streaming; bool server_streaming; }; @@ -5350,6 +5399,20 @@ static const void* unpack_def(upb_value v, upb_deftype_t type) { } static upb_value pack_def(const void* ptr, upb_deftype_t type) { + // Our 3-bit pointer tagging requires all pointers to be multiples of 8. + // The arena will always yield 8-byte-aligned addresses, however we put + // the defs into arrays. For each element in the array to be 8-byte-aligned, + // the sizes of each def type must also be a multiple of 8. + // + // If any of these asserts fail, we need to add or remove padding on 32-bit + // machines (64-bit machines will have 8-byte alignment already due to + // pointers, which all of these structs have). + UPB_ASSERT((sizeof(upb_FieldDef) & UPB_DEFTYPE_MASK) == 0); + UPB_ASSERT((sizeof(upb_MessageDef) & UPB_DEFTYPE_MASK) == 0); + UPB_ASSERT((sizeof(upb_EnumDef) & UPB_DEFTYPE_MASK) == 0); + UPB_ASSERT((sizeof(upb_EnumValueDef) & UPB_DEFTYPE_MASK) == 0); + UPB_ASSERT((sizeof(upb_ServiceDef) & UPB_DEFTYPE_MASK) == 0); + UPB_ASSERT((sizeof(upb_OneofDef) & UPB_DEFTYPE_MASK) == 0); uintptr_t num = (uintptr_t)ptr; UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0); num |= type; @@ -5795,8 +5858,8 @@ upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m) { return m->file->syntax; } -const upb_FieldDef* upb_MessageDef_FindFieldByNumberWithSize( - const upb_MessageDef* m, uint32_t i) { +const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, + uint32_t i) { upb_value val; return upb_inttable_lookup(&m->itof, i, &val) ? upb_value_getconstptr(val) : NULL; @@ -6084,6 +6147,8 @@ const char* upb_MethodDef_FullName(const upb_MethodDef* m) { return m->full_name; } +int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } + const char* upb_MethodDef_Name(const upb_MethodDef* m) { return shortdefname(m->full_name); } @@ -6469,8 +6534,8 @@ static void assign_layout_indices(const upb_MessageDef* m, upb_MiniTable* l, int n = upb_MessageDef_numfields(m); int dense_below = 0; for (i = 0; i < n; i++) { - upb_FieldDef* f = (upb_FieldDef*)upb_MessageDef_FindFieldByNumberWithSize( - m, fields[i].number); + upb_FieldDef* f = + (upb_FieldDef*)upb_MessageDef_FindFieldByNumber(m, fields[i].number); UPB_ASSERT(f); f->layout_index = i; if (i < UINT8_MAX && fields[i].number == i + 1 && @@ -6488,17 +6553,17 @@ static uint8_t map_descriptortype(const upb_FieldDef* f) { if (type == kUpb_FieldType_String && f->file->syntax == kUpb_Syntax_Proto2) { return kUpb_FieldType_Bytes; } else if (type == kUpb_FieldType_Enum && - f->sub.enumdef->file->syntax == kUpb_Syntax_Proto3) { + (f->sub.enumdef->file->syntax == kUpb_Syntax_Proto3 || + UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 || + // TODO(https://github.com/protocolbuffers/upb/issues/541): + // fix map enum values to check for unknown enum values and put + // them in the unknown field set. + upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)))) { return kUpb_FieldType_Int32; } return type; } -static bool IsProto2Enum(const upb_FieldDef* f) { - return upb_FieldDef_CType(f) == kUpb_CType_Enum && - f->sub.enumdef->file->syntax == kUpb_Syntax_Proto2; -} - static void fill_fieldlayout(upb_MiniTable_Field* field, const upb_FieldDef* f) { field->number = upb_FieldDef_Number(f); @@ -6506,43 +6571,43 @@ static void fill_fieldlayout(upb_MiniTable_Field* field, if (upb_FieldDef_IsMap(f)) { field->mode = - kUpb_FieldMode_Map | (upb_FieldRep_Pointer << upb_FieldRep_Shift); + kUpb_FieldMode_Map | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift); } else if (upb_FieldDef_IsRepeated(f)) { field->mode = - kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift); + kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift); } else { /* Maps descriptor type -> elem_size_lg2. */ static const uint8_t sizes[] = { - -1, /* invalid descriptor type */ - upb_FieldRep_8Byte, /* DOUBLE */ - upb_FieldRep_4Byte, /* FLOAT */ - upb_FieldRep_8Byte, /* INT64 */ - upb_FieldRep_8Byte, /* UINT64 */ - upb_FieldRep_4Byte, /* INT32 */ - upb_FieldRep_8Byte, /* FIXED64 */ - upb_FieldRep_4Byte, /* FIXED32 */ - upb_FieldRep_1Byte, /* BOOL */ - upb_FieldRep_StringView, /* STRING */ - upb_FieldRep_Pointer, /* GROUP */ - upb_FieldRep_Pointer, /* MESSAGE */ - upb_FieldRep_StringView, /* BYTES */ - upb_FieldRep_4Byte, /* UINT32 */ - upb_FieldRep_4Byte, /* ENUM */ - upb_FieldRep_4Byte, /* SFIXED32 */ - upb_FieldRep_8Byte, /* SFIXED64 */ - upb_FieldRep_4Byte, /* SINT32 */ - upb_FieldRep_8Byte, /* SINT64 */ + -1, /* invalid descriptor type */ + kUpb_FieldRep_8Byte, /* DOUBLE */ + kUpb_FieldRep_4Byte, /* FLOAT */ + kUpb_FieldRep_8Byte, /* INT64 */ + kUpb_FieldRep_8Byte, /* UINT64 */ + kUpb_FieldRep_4Byte, /* INT32 */ + kUpb_FieldRep_8Byte, /* FIXED64 */ + kUpb_FieldRep_4Byte, /* FIXED32 */ + kUpb_FieldRep_1Byte, /* BOOL */ + kUpb_FieldRep_StringView, /* STRING */ + kUpb_FieldRep_Pointer, /* GROUP */ + kUpb_FieldRep_Pointer, /* MESSAGE */ + kUpb_FieldRep_StringView, /* BYTES */ + kUpb_FieldRep_4Byte, /* UINT32 */ + kUpb_FieldRep_4Byte, /* ENUM */ + kUpb_FieldRep_4Byte, /* SFIXED32 */ + kUpb_FieldRep_8Byte, /* SFIXED64 */ + kUpb_FieldRep_4Byte, /* SINT32 */ + kUpb_FieldRep_8Byte, /* SINT64 */ }; field->mode = kUpb_FieldMode_Scalar | - (sizes[field->descriptortype] << upb_FieldRep_Shift); + (sizes[field->descriptortype] << kUpb_FieldRep_Shift); } if (upb_FieldDef_IsPacked(f)) { - field->mode |= upb_LabelFlags_IsPacked; + field->mode |= kUpb_LabelFlags_IsPacked; } if (upb_FieldDef_IsExtension(f)) { - field->mode |= upb_LabelFlags_IsExtension; + field->mode |= kUpb_LabelFlags_IsExtension; } } @@ -6562,7 +6627,9 @@ static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { const upb_FieldDef* f = &m->fields[i]; if (upb_FieldDef_IsSubMessage(f)) { sublayout_count++; - } else if (IsProto2Enum(f)) { + } + if (upb_FieldDef_CType(f) == kUpb_CType_Enum && + f->sub.enumdef->file->syntax == kUpb_Syntax_Proto2) { sublayout_count++; } } @@ -6578,12 +6645,12 @@ static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { if (upb_MessageDef_ExtensionRangeCount(m) > 0) { if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { - l->ext = upb_ExtMode_IsMessageSet; + l->ext = kUpb_ExtMode_IsMessageSet; } else { - l->ext = upb_ExtMode_Extendable; + l->ext = kUpb_ExtMode_Extendable; } } else { - l->ext = upb_ExtMode_NonExtendable; + l->ext = kUpb_ExtMode_NonExtendable; } /* TODO(haberman): initialize fast tables so that reflection-based parsing @@ -6594,8 +6661,8 @@ static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { if (upb_MessageDef_IsMapEntry(m)) { /* TODO(haberman): refactor this method so this special case is more * elegant. */ - const upb_FieldDef* key = upb_MessageDef_FindFieldByNumberWithSize(m, 1); - const upb_FieldDef* val = upb_MessageDef_FindFieldByNumberWithSize(m, 2); + const upb_FieldDef* key = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* val = upb_MessageDef_FindFieldByNumber(m, 2); fields[0].number = 1; fields[1].number = 2; fields[0].mode = kUpb_FieldMode_Scalar; @@ -6610,8 +6677,6 @@ static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { if (upb_FieldDef_CType(val) == kUpb_CType_Message) { subs[0].submsg = upb_FieldDef_MessageSubDef(val)->layout; - } else if (IsProto2Enum(val)) { - subs[0].subenum = upb_FieldDef_EnumSubDef(val)->layout; } upb_FieldDef* fielddefs = (upb_FieldDef*)&m->fields[0]; @@ -6660,11 +6725,11 @@ static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { fill_fieldlayout(field, f); - if (upb_FieldDef_IsSubMessage(f)) { + if (field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group) { field->submsg_index = sublayout_count++; subs[field->submsg_index].submsg = upb_FieldDef_MessageSubDef(f)->layout; - } else if (upb_FieldDef_CType(f) == kUpb_CType_Enum && - f->file->syntax == kUpb_Syntax_Proto2) { + } else if (field->descriptortype == kUpb_FieldType_Enum) { field->submsg_index = sublayout_count++; subs[field->submsg_index].subenum = upb_FieldDef_EnumSubDef(f)->layout; UPB_ASSERT(subs[field->submsg_index].subenum); @@ -6683,7 +6748,7 @@ static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { } /* Account for space used by hasbits. */ - l->size = div_round_up(hasbit + 1, 8); + l->size = hasbit ? div_round_up(hasbit + 1, 8) : 0; /* Allocate non-oneof fields. */ for (int i = 0; i < m->field_count; i++) { @@ -6710,6 +6775,10 @@ static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { if (upb_OneofDef_IsSynthetic(o)) continue; + if (o->field_count == 0) { + symtab_errf(ctx, "Oneof must have at least one field (%s)", o->full_name); + } + /* Calculate field size: the max of all field sizes. */ for (int j = 0; j < o->field_count; j++) { const upb_FieldDef* f = o->fields[j]; @@ -6732,7 +6801,10 @@ static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { l->size = UPB_ALIGN_UP(l->size, 8); /* Sort fields by number. */ - qsort(fields, upb_MessageDef_numfields(m), sizeof(*fields), field_number_cmp); + if (fields) { + qsort(fields, upb_MessageDef_numfields(m), sizeof(*fields), + field_number_cmp); + } assign_layout_indices(m, l, fields); } @@ -6893,8 +6965,8 @@ static const void* symtab_resolveany(symtab_addctx* ctx, } } else { /* Remove components from base until we find an entry or run out. */ - size_t baselen = strlen(base); - char* tmp = malloc(sym.size + strlen(base) + 1); + size_t baselen = base ? strlen(base) : 0; + char* tmp = malloc(sym.size + baselen + 1); while (1) { char* p = tmp; if (baselen) { @@ -6930,10 +7002,10 @@ static const void* symtab_resolve(symtab_addctx* ctx, const char* from_name_dbg, const void* ret = symtab_resolveany(ctx, from_name_dbg, base, sym, &found_type); if (ret && found_type != type) { - symtab_errf( - ctx, - "type mismatch when resolving %s: couldn't find name %s with type=%d", - from_name_dbg, sym.data, (int)type); + symtab_errf(ctx, + "type mismatch when resolving %s: couldn't find " + "name " UPB_STRINGVIEW_FORMAT " with type=%d", + from_name_dbg, UPB_STRINGVIEW_ARGS(sym), (int)type); } return ret; } @@ -6953,6 +7025,11 @@ static void create_oneofdef( SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); + upb_value existing_v; + if (upb_strtable_lookup2(&m->ntof, name.data, name.size, &existing_v)) { + symtab_errf(ctx, "duplicate oneof name (%s)", o->full_name); + } + v = pack_def(o, UPB_DEFTYPE_ONEOF); CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, v, ctx->arena)); @@ -7262,7 +7339,7 @@ static void create_fielddef( f->file = ctx->file; /* Must happen prior to symtab_add(). */ if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { - symtab_errf(ctx, "field has no name (%s)", upb_MessageDef_FullName(m)); + symtab_errf(ctx, "field has no name"); } name = google_protobuf_FieldDescriptorProto_name(field_proto); @@ -7479,6 +7556,7 @@ static void create_service( m->service = s; m->full_name = makefullname(ctx, s->full_name, name); + m->index = i; m->client_streaming = google_protobuf_MethodDescriptorProto_client_streaming(method_proto); m->server_streaming = @@ -7506,6 +7584,12 @@ static int count_bits_debug(uint64_t x) { return n; } +static int compare_int32(const void* a_ptr, const void* b_ptr) { + int32_t a = *(int32_t*)a_ptr; + int32_t b = *(int32_t*)b_ptr; + return a < b ? -1 : (a == b ? 0 : 1); +} + upb_MiniTable_Enum* create_enumlayout(symtab_addctx* ctx, const upb_EnumDef* e) { int n = 0; @@ -7514,7 +7598,7 @@ upb_MiniTable_Enum* create_enumlayout(symtab_addctx* ctx, for (int i = 0; i < e->value_count; i++) { uint32_t val = (uint32_t)e->values[i].number; if (val < 64) { - mask |= 1 << val; + mask |= 1ULL << val; } else { n++; } @@ -7536,6 +7620,17 @@ upb_MiniTable_Enum* create_enumlayout(symtab_addctx* ctx, UPB_ASSERT(p == values + n); } + // Enums can have duplicate values; we must sort+uniq them. + if (values) qsort(values, n, sizeof(*values), &compare_int32); + + int dst = 0; + for (int i = 0; i < n; dst++) { + int32_t val = values[i]; + while (i < n && values[i] == val) i++; // Skip duplicates. + values[dst] = val; + } + n = dst; + UPB_ASSERT(upb_inttable_count(&e->iton) == n + count_bits_debug(mask)); upb_MiniTable_Enum* layout = symtab_alloc(ctx, sizeof(*layout)); @@ -7619,7 +7714,7 @@ static void create_enumdef( if (ctx->layout) { UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); e->layout = ctx->layout->enums[ctx->enum_count++]; - UPB_ASSERT(n == + UPB_ASSERT(upb_inttable_count(&e->iton) == e->layout->value_count + count_bits_debug(e->layout->mask)); } else { e->layout = create_enumlayout(ctx, e); @@ -7890,15 +7985,10 @@ static void resolve_msgdef(symtab_addctx* ctx, upb_MessageDef* m) { resolve_fielddef(ctx, m->full_name, (upb_FieldDef*)&m->fields[i]); } - for (int i = 0; i < m->nested_ext_count; i++) { - resolve_fielddef(ctx, m->full_name, (upb_FieldDef*)&m->nested_exts[i]); - } - - if (!ctx->layout) make_layout(ctx, m); - m->in_message_set = false; - if (m->nested_ext_count == 1) { - const upb_FieldDef* ext = &m->nested_exts[0]; + for (int i = 0; i < m->nested_ext_count; i++) { + upb_FieldDef* ext = (upb_FieldDef*)&m->nested_exts[i]; + resolve_fielddef(ctx, m->full_name, ext); if (ext->type_ == kUpb_FieldType_Message && ext->label_ == kUpb_Label_Optional && ext->sub.msgdef == m && google_protobuf_MessageOptions_message_set_wire_format( @@ -7907,6 +7997,8 @@ static void resolve_msgdef(symtab_addctx* ctx, upb_MessageDef* m) { } } + if (!ctx->layout) make_layout(ctx, m); + for (int i = 0; i < m->nested_msg_count; i++) { resolve_msgdef(ctx, (upb_MessageDef*)&m->nested_msgs[i]); } @@ -8038,7 +8130,7 @@ static void build_filedef( int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; for (i = 0; i < n; i++) { if (weak_deps[i] >= file->dep_count) { - symtab_errf(ctx, "public_dep %d is out of range", (int)public_deps[i]); + symtab_errf(ctx, "weak_dep %d is out of range", (int)weak_deps[i]); } mutable_weak_deps[i] = weak_deps[i]; } @@ -8194,7 +8286,8 @@ const upb_FileDef* upb_DefPool_AddFile( /* Include here since we want most of this file to be stdio-free. */ #include -bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) { +bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, + bool rebuild_minitable) { /* Since this function should never fail (it would indicate a bug in upb) we * print errors to stderr instead of returning error status to the user. */ _upb_DefPool_Init** deps = init->deps; @@ -8211,7 +8304,7 @@ bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) { arena = upb_Arena_New(); for (; *deps; deps++) { - if (!_upb_DefPool_LoadDefInit(s, *deps)) goto err; + if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; } file = google_protobuf_FileDescriptorProto_parse_ex( @@ -8228,7 +8321,8 @@ bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) { goto err; } - if (!_upb_DefPool_AddFile(s, file, init->layout, &status)) { + const upb_MiniTable_File* mt = rebuild_minitable ? NULL : init->layout; + if (!_upb_DefPool_AddFile(s, file, mt, &status)) { goto err; } @@ -8458,10 +8552,10 @@ upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, if (!a) return (upb_MutableMessageValue){.array = NULL}; if (upb_FieldDef_IsMap(f)) { const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); - const upb_FieldDef* key = upb_MessageDef_FindFieldByNumberWithSize( - entry, kUpb_MapEntry_KeyFieldNumber); - const upb_FieldDef* value = upb_MessageDef_FindFieldByNumberWithSize( - entry, kUpb_MapEntry_ValueFieldNumber); + const upb_FieldDef* key = + upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_KeyFieldNumber); + const upb_FieldDef* value = + upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_ValueFieldNumber); ret.map = upb_Map_New(a, upb_FieldDef_CType(key), upb_FieldDef_CType(value)); } else if (upb_FieldDef_IsRepeated(f)) { @@ -8591,8 +8685,7 @@ bool _upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); if (!subm) continue; if (upb_FieldDef_IsMap(f)) { - const upb_FieldDef* val_f = - upb_MessageDef_FindFieldByNumberWithSize(subm, 2); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(subm, 2); const upb_MessageDef* val_m = upb_FieldDef_MessageSubDef(val_f); upb_Map* map = (upb_Map*)val.map_val; size_t iter = kUpb_Map_Begin; @@ -9624,10 +9717,8 @@ static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { upb_Map* map = upb_Message_Mutable(msg, f, d->arena).map; const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); - const upb_FieldDef* key_f = - upb_MessageDef_FindFieldByNumberWithSize(entry, 1); - const upb_FieldDef* val_f = - upb_MessageDef_FindFieldByNumberWithSize(entry, 2); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); jsondec_objstart(d); while (jsondec_objnext(d)) { @@ -9869,10 +9960,9 @@ static void jsondec_timestamp(jsondec* d, upb_Message* msg, jsondec_err(d, "Timestamp out of range"); } - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumberWithSize(m, 1), seconds, - d->arena); - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumberWithSize(m, 2), nanos, + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, d->arena); + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); return; malformed: @@ -9904,15 +9994,14 @@ static void jsondec_duration(jsondec* d, upb_Message* msg, nanos.int32_val = -nanos.int32_val; } - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumberWithSize(m, 1), seconds, - d->arena); - upb_Message_Set(msg, upb_MessageDef_FindFieldByNumberWithSize(m, 2), nanos, + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, d->arena); + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); } static void jsondec_listvalue(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { - const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumberWithSize(m, 1); + const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(values_f); upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; @@ -9929,10 +10018,9 @@ static void jsondec_listvalue(jsondec* d, upb_Message* msg, static void jsondec_struct(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { - const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumberWithSize(m, 1); + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); - const upb_FieldDef* value_f = - upb_MessageDef_FindFieldByNumberWithSize(entry_m, 2); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(value_f); upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; @@ -9958,42 +10046,42 @@ static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, switch (jsondec_peek(d)) { case JD_NUMBER: /* double number_value = 2; */ - f = upb_MessageDef_FindFieldByNumberWithSize(m, 2); + f = upb_MessageDef_FindFieldByNumber(m, 2); val.double_val = jsondec_number(d); break; case JD_STRING: /* string string_value = 3; */ - f = upb_MessageDef_FindFieldByNumberWithSize(m, 3); + f = upb_MessageDef_FindFieldByNumber(m, 3); val.str_val = jsondec_string(d); break; case JD_FALSE: /* bool bool_value = 4; */ - f = upb_MessageDef_FindFieldByNumberWithSize(m, 4); + f = upb_MessageDef_FindFieldByNumber(m, 4); val.bool_val = false; jsondec_false(d); break; case JD_TRUE: /* bool bool_value = 4; */ - f = upb_MessageDef_FindFieldByNumberWithSize(m, 4); + f = upb_MessageDef_FindFieldByNumber(m, 4); val.bool_val = true; jsondec_true(d); break; case JD_NULL: /* NullValue null_value = 1; */ - f = upb_MessageDef_FindFieldByNumberWithSize(m, 1); + f = upb_MessageDef_FindFieldByNumber(m, 1); val.int32_val = 0; jsondec_null(d); break; /* Note: these cases return, because upb_Message_Mutable() is enough. */ case JD_OBJECT: /* Struct struct_value = 5; */ - f = upb_MessageDef_FindFieldByNumberWithSize(m, 5); + f = upb_MessageDef_FindFieldByNumber(m, 5); submsg = upb_Message_Mutable(msg, f, d->arena).msg; jsondec_struct(d, submsg, upb_FieldDef_MessageSubDef(f)); return; case JD_ARRAY: /* ListValue list_value = 6; */ - f = upb_MessageDef_FindFieldByNumberWithSize(m, 6); + f = upb_MessageDef_FindFieldByNumber(m, 6); submsg = upb_Message_Mutable(msg, f, d->arena).msg; jsondec_listvalue(d, submsg, upb_FieldDef_MessageSubDef(f)); return; @@ -10040,7 +10128,7 @@ static upb_StringView jsondec_mask(jsondec* d, const char* buf, static void jsondec_fieldmask(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { /* repeated string paths = 1; */ - const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumberWithSize(m, 1); + const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); upb_Array* arr = upb_Message_Mutable(msg, paths_f, d->arena).array; upb_StringView str = jsondec_string(d); const char* ptr = str.data; @@ -10080,8 +10168,7 @@ static void jsondec_anyfield(jsondec* d, upb_Message* msg, static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { - const upb_FieldDef* type_url_f = - upb_MessageDef_FindFieldByNumberWithSize(m, 1); + const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); const upb_MessageDef* type_m; upb_StringView type_url = jsondec_string(d); const char* end = type_url.data + type_url.size; @@ -10112,7 +10199,7 @@ static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg, static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { /* string type_url = 1; * bytes value = 2; */ - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumberWithSize(m, 2); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); upb_Message* any_msg; const upb_MessageDef* any_m = NULL; const char* pre_type_data = NULL; @@ -10174,7 +10261,7 @@ static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { static void jsondec_wrapper(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumberWithSize(m, 1); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 1); upb_MessageValue val = jsondec_value(d, value_f); upb_Message_Set(msg, value_f, val, d->arena); } @@ -10356,9 +10443,8 @@ static void jsonenc_nanos(jsonenc* e, int32_t nanos) { static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg, const upb_MessageDef* m) { - const upb_FieldDef* seconds_f = - upb_MessageDef_FindFieldByNumberWithSize(m, 1); - const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumberWithSize(m, 2); + const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; int L, N, I, J, K, hour, min, sec; @@ -10377,7 +10463,8 @@ static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg, * Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for * Processing Calendar Dates," Communications of the Association of * Computing Machines, vol. 11 (1968), p. 657. */ - L = (int)(seconds / 86400) + 68569 + 2440588; + seconds += 62135596800; // Ensure seconds is positive. + L = (int)(seconds / 86400) - 719162 + 68569 + 2440588; N = 4 * L / 146097; L = L - (146097 * N + 3) / 4; I = 4000 * (L + 1) / 1461001; @@ -10399,9 +10486,8 @@ static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg, static void jsonenc_duration(jsonenc* e, const upb_Message* msg, const upb_MessageDef* m) { - const upb_FieldDef* seconds_f = - upb_MessageDef_FindFieldByNumberWithSize(m, 1); - const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumberWithSize(m, 2); + const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; @@ -10550,7 +10636,7 @@ static void upb_JsonEncode_Float(jsonenc* e, float val) { static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg, const upb_MessageDef* m) { - const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumberWithSize(m, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(m, 1); upb_MessageValue val = upb_Message_Get(msg, val_f); jsonenc_scalar(e, val, val_f); } @@ -10594,9 +10680,8 @@ static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e, static void jsonenc_any(jsonenc* e, const upb_Message* msg, const upb_MessageDef* m) { - const upb_FieldDef* type_url_f = - upb_MessageDef_FindFieldByNumberWithSize(m, 1); - const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumberWithSize(m, 2); + const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); upb_StringView type_url = upb_Message_Get(msg, type_url_f).str_val; upb_StringView value = upb_Message_Get(msg, value_f).str_val; const upb_MessageDef* any_m = jsonenc_getanymsg(e, type_url); @@ -10655,7 +10740,7 @@ static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg, const upb_MessageDef* m) { - const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumberWithSize(m, 1); + const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); const upb_Array* paths = upb_Message_Get(msg, paths_f).array_val; bool first = true; size_t i, n = 0; @@ -10674,11 +10759,10 @@ static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg, static void jsonenc_struct(jsonenc* e, const upb_Message* msg, const upb_MessageDef* m) { - const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumberWithSize(m, 1); + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); const upb_Map* fields = upb_Message_Get(msg, fields_f).map_val; const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); - const upb_FieldDef* value_f = - upb_MessageDef_FindFieldByNumberWithSize(entry_m, 2); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); size_t iter = kUpb_Map_Begin; bool first = true; @@ -10701,7 +10785,7 @@ static void jsonenc_struct(jsonenc* e, const upb_Message* msg, static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg, const upb_MessageDef* m) { - const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumberWithSize(m, 1); + const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f); const upb_Array* values = upb_Message_Get(msg, values_f).array_val; size_t i; @@ -10883,10 +10967,8 @@ static void jsonenc_array(jsonenc* e, const upb_Array* arr, static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) { const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); - const upb_FieldDef* key_f = - upb_MessageDef_FindFieldByNumberWithSize(entry, 1); - const upb_FieldDef* val_f = - upb_MessageDef_FindFieldByNumberWithSize(entry, 2); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); size_t iter = kUpb_Map_Begin; bool first = true; @@ -11030,3 +11112,4 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #undef UPB_POISON_MEMORY_REGION #undef UPB_UNPOISON_MEMORY_REGION #undef UPB_ASAN +#undef UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 diff --git a/ruby/ext/google/protobuf_c/ruby-upb.h b/ruby/ext/google/protobuf_c/ruby-upb.h index 369861c50854..e57eb0edad00 100755 --- a/ruby/ext/google/protobuf_c/ruby-upb.h +++ b/ruby/ext/google/protobuf_c/ruby-upb.h @@ -1,3 +1,5 @@ +// Ruby is still using proto3 enum semantics for proto2 +#define UPB_DISABLE_PROTO2_ENUM_CHECKING /* Amalgamated source file */ /* * Copyright (c) 2009-2021, Google LLC @@ -253,6 +255,14 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); ((void)(addr), (void)(size)) #endif +/* Disable proto2 arena behavior (TEMPORARY) **********************************/ + +#ifdef UPB_DISABLE_PROTO2_ENUM_CHECKING +#define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 1 +#else +#define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 0 +#endif + /** upb/decode.h ************************************************************/ /* * upb_decode: parsing into a upb_Message using a upb_MiniTable. @@ -475,8 +485,32 @@ UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) { return ret; } +// Shrinks the last alloc from arena. +// REQUIRES: (ptr, oldsize) was the last malloc/realloc from this arena. +// We could also add a upb_Arena_TryShrinkLast() which is simply a no-op if +// this was not the last alloc. +UPB_INLINE void upb_Arena_ShrinkLast(upb_Arena* a, void* ptr, size_t oldsize, + size_t size) { + _upb_ArenaHead* h = (_upb_ArenaHead*)a; + oldsize = UPB_ALIGN_MALLOC(oldsize); + size = UPB_ALIGN_MALLOC(size); + UPB_ASSERT((char*)ptr + oldsize == h->ptr); // Must be the last alloc. + UPB_ASSERT(size <= oldsize); + h->ptr = (char*)ptr + size; +} + UPB_INLINE void* upb_Arena_Realloc(upb_Arena* a, void* ptr, size_t oldsize, size_t size) { + _upb_ArenaHead* h = (_upb_ArenaHead*)a; + oldsize = UPB_ALIGN_MALLOC(oldsize); + size = UPB_ALIGN_MALLOC(size); + if (size <= oldsize) { + if ((char*)ptr + oldsize == h->ptr) { + upb_Arena_ShrinkLast(a, ptr, oldsize, size); + } + return ptr; + } + void* ret = upb_Arena_Malloc(a, size); if (ret && oldsize > 0) { @@ -584,7 +618,7 @@ UPB_INLINE int _upb_Log2Ceiling(int x) { #endif } -UPB_INLINE int _upb_Log2Ceilingsize(int x) { return 1 << _upb_Log2Ceiling(x); } +UPB_INLINE int _upb_Log2CeilingSize(int x) { return 1 << _upb_Log2Ceiling(x); } #ifdef __cplusplus @@ -786,10 +820,6 @@ upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg, extern "C" { #endif -uint64_t Wyhash(const void* data, size_t len, uint64_t seed, - const uint64_t salt[]); -extern const uint64_t kWyhashSalt[5]; - /* upb_value ******************************************************************/ typedef struct { @@ -1105,6 +1135,8 @@ void upb_inttable_iter_setdone(upb_inttable_iter* i); bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, const upb_inttable_iter* i2); +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed); + #ifdef __cplusplus } /* extern "C" */ #endif @@ -1118,6 +1150,18 @@ bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, extern "C" { #endif +/** upb_*Int* conversion routines ********************************************/ + +UPB_INLINE int32_t _upb_Int32_FromI(int v) { return (int32_t)v; } + +UPB_INLINE int64_t _upb_Int64_FromLL(long long v) { return (int64_t)v; } + +UPB_INLINE uint32_t _upb_UInt32_FromU(unsigned v) { return (uint32_t)v; } + +UPB_INLINE uint64_t _upb_UInt64_FromULL(unsigned long long v) { + return (uint64_t)v; +} + /** upb_MiniTable *************************************************************/ /* upb_MiniTable represents the memory layout of a given upb_MessageDef. The @@ -1131,7 +1175,7 @@ typedef struct { uint16_t submsg_index; // undefined if descriptortype != MESSAGE/GROUP/ENUM uint8_t descriptortype; uint8_t mode; /* upb_FieldMode | upb_LabelFlags | - (upb_FieldRep << upb_FieldRep_Shift) */ + (upb_FieldRep << kUpb_FieldRep_Shift) */ } upb_MiniTable_Field; typedef enum { @@ -1143,28 +1187,22 @@ typedef enum { } upb_FieldMode; /* Extra flags on the mode field. */ -enum upb_LabelFlags { - upb_LabelFlags_IsPacked = 4, - upb_LabelFlags_IsExtension = 8, -}; - -/* Representation in the message. Derivable from descriptortype and mode, but - * fast access helps the serializer. */ -enum upb_FieldRep { - upb_FieldRep_1Byte = 0, - upb_FieldRep_4Byte = 1, - upb_FieldRep_8Byte = 2, - upb_FieldRep_StringView = 3, +typedef enum { + kUpb_LabelFlags_IsPacked = 4, + kUpb_LabelFlags_IsExtension = 8, +} upb_LabelFlags; -#if UINTPTR_MAX == 0xffffffff - upb_FieldRep_Pointer = upb_FieldRep_4Byte, -#else - upb_FieldRep_Pointer = upb_FieldRep_8Byte, -#endif +// Note: we sort by this number when calculating layout order. +typedef enum { + kUpb_FieldRep_1Byte = 0, + kUpb_FieldRep_4Byte = 1, + kUpb_FieldRep_StringView = 2, + kUpb_FieldRep_Pointer = 3, + kUpb_FieldRep_8Byte = 4, - upb_FieldRep_Shift = - 6, /* Bit offset of the rep in upb_MiniTable_Field.mode */ -}; + kUpb_FieldRep_Shift = 5, // Bit offset of the rep in upb_MiniTable_Field.mode + kUpb_FieldRep_Max = kUpb_FieldRep_8Byte, +} upb_FieldRep; UPB_INLINE upb_FieldMode upb_FieldMode_Get(const upb_MiniTable_Field* field) { return (upb_FieldMode)(field->mode & 3); @@ -1216,11 +1254,15 @@ typedef union { } upb_MiniTable_Sub; typedef enum { - upb_ExtMode_NonExtendable = 0, // Non-extendable message. - upb_ExtMode_Extendable = 1, // Normal extendable message. - upb_ExtMode_IsMessageSet = 2, // MessageSet message. - upb_ExtMode_IsMessageSet_ITEM = + kUpb_ExtMode_NonExtendable = 0, // Non-extendable message. + kUpb_ExtMode_Extendable = 1, // Normal extendable message. + kUpb_ExtMode_IsMessageSet = 2, // MessageSet message. + kUpb_ExtMode_IsMessageSet_ITEM = 3, // MessageSet item (temporary only, see decode.c) + + // During table building we steal a bit to indicate that the message is a map + // entry. *Only* used during table building! + kUpb_ExtMode_IsMapEntry = 4, } upb_ExtMode; /* MessageSet wire format is: @@ -1281,8 +1323,7 @@ UPB_INLINE uint64_t upb_MiniTable_requiredmask(const upb_MiniTable* l) { return ((1ULL << n) - 1) << 1; } -/** upb_ExtensionRegistry - * ****************************************************************/ +/** upb_ExtensionRegistry *****************************************************/ /* Adds the given extension info for message type |l| and field number |num| * into the registry. Returns false if this message type and field number were @@ -1297,8 +1338,7 @@ const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r, const upb_MiniTable* l, uint32_t num); -/** upb_Message - * *******************************************************************/ +/** upb_Message ***************************************************************/ /* Internal members of a upb_Message that track unknown fields and/or * extensions. We can change this without breaking binary compatibility. We put @@ -1371,8 +1411,7 @@ void _upb_Message_DiscardUnknown_shallow(upb_Message* msg); bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, upb_Arena* arena); -/** upb_Message_Extension - * ***************************************************************/ +/** upb_Message_Extension *****************************************************/ /* The internal representation of an extension is self-describing: it contains * enough information that we can serialize it to binary format without needing @@ -1829,8 +1868,7 @@ UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, } } -/** _upb_mapsorter - * *************************************************************/ +/** _upb_mapsorter ************************************************************/ /* _upb_mapsorter sorts maps and provides ordered iteration over the entries. * Since maps can be recursive (map values can be messages which contain other @@ -1920,9 +1958,7 @@ struct upb_Arena { // the beginning. // // The given buffer size must be at least kUpb_RoundTripBufferSize. -enum { - kUpb_RoundTripBufferSize = 32 -}; +enum { kUpb_RoundTripBufferSize = 32 }; void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size); void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size); @@ -2455,19 +2491,22 @@ UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize_ex(const google_pro upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_FileDescriptorSet_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_FileDescriptorSet_has_file(const google_protobuf_FileDescriptorSet *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_FileDescriptorProto* const* google_protobuf_FileDescriptorSet_file(const google_protobuf_FileDescriptorSet *msg, size_t *len) { return (const google_protobuf_FileDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } +UPB_INLINE bool google_protobuf_FileDescriptorSet_has_file(const google_protobuf_FileDescriptorSet* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_FileDescriptorProto* const* google_protobuf_FileDescriptorSet_file(const google_protobuf_FileDescriptorSet* msg, size_t* len) { + return (const google_protobuf_FileDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); +} -UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_mutable_file(google_protobuf_FileDescriptorSet *msg, size_t *len) { +UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_mutable_file(google_protobuf_FileDescriptorSet* msg, size_t* len) { return (google_protobuf_FileDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_resize_file(google_protobuf_FileDescriptorSet *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_resize_file(google_protobuf_FileDescriptorSet* msg, size_t len, upb_Arena* arena) { return (google_protobuf_FileDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorSet_add_file(google_protobuf_FileDescriptorSet *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorSet_add_file(google_protobuf_FileDescriptorSet* msg, upb_Arena* arena) { struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)_upb_Message_New(&google_protobuf_FileDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -2503,34 +2542,66 @@ UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize_ex(const google_p upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_FileDescriptorProto_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_name(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_name(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_name(const google_protobuf_FileDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_package(const google_protobuf_FileDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); } -UPB_INLINE upb_StringView const* google_protobuf_FileDescriptorProto_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_message_type(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); } -UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_FileDescriptorProto_message_type(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_enum_type(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(44, 88)); } -UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_FileDescriptorProto_enum_type(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_service(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(48, 96)); } -UPB_INLINE const google_protobuf_ServiceDescriptorProto* const* google_protobuf_FileDescriptorProto_service(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_ServiceDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(48, 96), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_extension(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(52, 104)); } -UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_FileDescriptorProto_extension(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(52, 104), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_options(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE upb_StringView const* google_protobuf_FileDescriptorProto_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_message_type(const google_protobuf_FileDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); +} +UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_FileDescriptorProto_message_type(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_enum_type(const google_protobuf_FileDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(44, 88)); +} +UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_FileDescriptorProto_enum_type(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_service(const google_protobuf_FileDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(48, 96)); +} +UPB_INLINE const google_protobuf_ServiceDescriptorProto* const* google_protobuf_FileDescriptorProto_service(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (const google_protobuf_ServiceDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(48, 96), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_extension(const google_protobuf_FileDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(52, 104)); +} +UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_FileDescriptorProto_extension(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(52, 104), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_options(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 3); +} UPB_INLINE const google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_options(const google_protobuf_FileDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_FileOptions*); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_source_code_info(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_source_code_info(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 4); +} UPB_INLINE const google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_source_code_info(const google_protobuf_FileDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const google_protobuf_SourceCodeInfo*); } -UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_public_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(56, 112), len); } -UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_weak_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(60, 120), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_syntax(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_public_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(56, 112), len); +} +UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_weak_dependency(const google_protobuf_FileDescriptorProto* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(60, 120), len); +} +UPB_INLINE bool google_protobuf_FileDescriptorProto_has_syntax(const google_protobuf_FileDescriptorProto* msg) { + return _upb_hasbit(msg, 5); +} UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_syntax(const google_protobuf_FileDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView); } @@ -2543,65 +2614,60 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_set_package(google_protobuf_ _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value; } -UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_mutable_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) { +UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_mutable_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len); } -UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(3, 4), arena); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_add_dependency(google_protobuf_FileDescriptorProto *msg, upb_StringView val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(3, 4), &val, - arena); +UPB_INLINE bool google_protobuf_FileDescriptorProto_add_dependency(google_protobuf_FileDescriptorProto* msg, upb_StringView val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(3, 4), &val, arena); } -UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_mutable_message_type(google_protobuf_FileDescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_mutable_message_type(google_protobuf_FileDescriptorProto* msg, size_t* len) { return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len); } -UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_resize_message_type(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_resize_message_type(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_FileDescriptorProto_add_message_type(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_FileDescriptorProto_add_message_type(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_mutable_enum_type(google_protobuf_FileDescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_mutable_enum_type(google_protobuf_FileDescriptorProto* msg, size_t* len) { return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len); } -UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_resize_enum_type(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_resize_enum_type(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(44, 88), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_FileDescriptorProto_add_enum_type(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_FileDescriptorProto_add_enum_type(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(44, 88), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(44, 88), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_mutable_service(google_protobuf_FileDescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_mutable_service(google_protobuf_FileDescriptorProto* msg, size_t* len) { return (google_protobuf_ServiceDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(48, 96), len); } -UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_resize_service(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_resize_service(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_ServiceDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(48, 96), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_ServiceDescriptorProto* google_protobuf_FileDescriptorProto_add_service(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_ServiceDescriptorProto* google_protobuf_FileDescriptorProto_add_service(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_ServiceDescriptorProto* sub = (struct google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google_protobuf_ServiceDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(48, 96), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(48, 96), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_mutable_extension(google_protobuf_FileDescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_mutable_extension(google_protobuf_FileDescriptorProto* msg, size_t* len) { return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(52, 104), len); } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_resize_extension(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_resize_extension(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(52, 104), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDescriptorProto_add_extension(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDescriptorProto_add_extension(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(52, 104), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(52, 104), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -2609,7 +2675,7 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_set_options(google_protobuf_ _upb_sethas(msg, 3); *UPB_PTR_AT(msg, UPB_SIZE(28, 56), google_protobuf_FileOptions*) = value; } -UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FileOptions* sub = (struct google_protobuf_FileOptions*)google_protobuf_FileDescriptorProto_options(msg); if (sub == NULL) { sub = (struct google_protobuf_FileOptions*)_upb_Message_New(&google_protobuf_FileOptions_msginit, arena); @@ -2622,7 +2688,7 @@ UPB_INLINE void google_protobuf_FileDescriptorProto_set_source_code_info(google_ _upb_sethas(msg, 4); *UPB_PTR_AT(msg, UPB_SIZE(32, 64), google_protobuf_SourceCodeInfo*) = value; } -UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_mutable_source_code_info(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_mutable_source_code_info(google_protobuf_FileDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_SourceCodeInfo* sub = (struct google_protobuf_SourceCodeInfo*)google_protobuf_FileDescriptorProto_source_code_info(msg); if (sub == NULL) { sub = (struct google_protobuf_SourceCodeInfo*)_upb_Message_New(&google_protobuf_SourceCodeInfo_msginit, arena); @@ -2631,25 +2697,23 @@ UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptor } return sub; } -UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_public_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) { +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_public_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 112), len); } -UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_public_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_public_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(56, 112), len, 2, arena); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_add_public_dependency(google_protobuf_FileDescriptorProto *msg, int32_t val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(56, 112), 2, &val, - arena); +UPB_INLINE bool google_protobuf_FileDescriptorProto_add_public_dependency(google_protobuf_FileDescriptorProto* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(56, 112), 2, &val, arena); } -UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_weak_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) { +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_weak_dependency(google_protobuf_FileDescriptorProto* msg, size_t* len) { return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(60, 120), len); } -UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_weak_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_weak_dependency(google_protobuf_FileDescriptorProto* msg, size_t len, upb_Arena* arena) { return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(60, 120), len, 2, arena); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_protobuf_FileDescriptorProto *msg, int32_t val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(60, 120), 2, &val, - arena); +UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_protobuf_FileDescriptorProto* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(60, 120), 2, &val, arena); } UPB_INLINE void google_protobuf_FileDescriptorProto_set_syntax(google_protobuf_FileDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 5); @@ -2687,96 +2751,125 @@ UPB_INLINE char* google_protobuf_DescriptorProto_serialize_ex(const google_proto upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_DescriptorProto_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_name(const google_protobuf_DescriptorProto *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_DescriptorProto_has_name(const google_protobuf_DescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_DescriptorProto_name(const google_protobuf_DescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_field(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); } -UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_field(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_nested_type(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); } -UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_DescriptorProto_nested_type(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_enum_type(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); } -UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_DescriptorProto_enum_type(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_extension_range(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); } -UPB_INLINE const google_protobuf_DescriptorProto_ExtensionRange* const* google_protobuf_DescriptorProto_extension_range(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto_ExtensionRange* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_extension(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); } -UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_extension(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_options(const google_protobuf_DescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_DescriptorProto_has_field(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); +} +UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_field(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_nested_type(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); +} +UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_DescriptorProto_nested_type(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_enum_type(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); +} +UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_DescriptorProto_enum_type(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_extension_range(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); +} +UPB_INLINE const google_protobuf_DescriptorProto_ExtensionRange* const* google_protobuf_DescriptorProto_extension_range(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_DescriptorProto_ExtensionRange* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_extension(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); +} +UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_extension(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_options(const google_protobuf_DescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE const google_protobuf_MessageOptions* google_protobuf_DescriptorProto_options(const google_protobuf_DescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_MessageOptions*); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_oneof_decl(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); } -UPB_INLINE const google_protobuf_OneofDescriptorProto* const* google_protobuf_DescriptorProto_oneof_decl(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_OneofDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_reserved_range(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); } -UPB_INLINE const google_protobuf_DescriptorProto_ReservedRange* const* google_protobuf_DescriptorProto_reserved_range(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto_ReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); } -UPB_INLINE upb_StringView const* google_protobuf_DescriptorProto_reserved_name(const google_protobuf_DescriptorProto *msg, size_t *len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); } +UPB_INLINE bool google_protobuf_DescriptorProto_has_oneof_decl(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); +} +UPB_INLINE const google_protobuf_OneofDescriptorProto* const* google_protobuf_DescriptorProto_oneof_decl(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_OneofDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); +} +UPB_INLINE bool google_protobuf_DescriptorProto_has_reserved_range(const google_protobuf_DescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); +} +UPB_INLINE const google_protobuf_DescriptorProto_ReservedRange* const* google_protobuf_DescriptorProto_reserved_range(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (const google_protobuf_DescriptorProto_ReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); +} +UPB_INLINE upb_StringView const* google_protobuf_DescriptorProto_reserved_name(const google_protobuf_DescriptorProto* msg, size_t* len) { + return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); +} UPB_INLINE void google_protobuf_DescriptorProto_set_name(google_protobuf_DescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 1); *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_field(google_protobuf_DescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_field(google_protobuf_DescriptorProto* msg, size_t* len) { return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_field(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_field(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_mutable_nested_type(google_protobuf_DescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_mutable_nested_type(google_protobuf_DescriptorProto* msg, size_t* len) { return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_resize_nested_type(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_resize_nested_type(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_add_nested_type(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_add_nested_type(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_mutable_enum_type(google_protobuf_DescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_mutable_enum_type(google_protobuf_DescriptorProto* msg, size_t* len) { return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_resize_enum_type(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_resize_enum_type(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_DescriptorProto_add_enum_type(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_DescriptorProto_add_enum_type(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_mutable_extension_range(google_protobuf_DescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_mutable_extension_range(google_protobuf_DescriptorProto* msg, size_t* len) { return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); } -UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_resize_extension_range(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_resize_extension_range(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_add_extension_range(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_add_extension_range(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_DescriptorProto_ExtensionRange* sub = (struct google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_extension(google_protobuf_DescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_extension(google_protobuf_DescriptorProto* msg, size_t* len) { return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len); } -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_extension(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_extension(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_extension(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_extension(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(32, 64), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(32, 64), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -2784,7 +2877,7 @@ UPB_INLINE void google_protobuf_DescriptorProto_set_options(google_protobuf_Desc _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_MessageOptions*) = value; } -UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProto_mutable_options(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProto_mutable_options(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_MessageOptions* sub = (struct google_protobuf_MessageOptions*)google_protobuf_DescriptorProto_options(msg); if (sub == NULL) { sub = (struct google_protobuf_MessageOptions*)_upb_Message_New(&google_protobuf_MessageOptions_msginit, arena); @@ -2793,41 +2886,38 @@ UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProt } return sub; } -UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_mutable_oneof_decl(google_protobuf_DescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_mutable_oneof_decl(google_protobuf_DescriptorProto* msg, size_t* len) { return (google_protobuf_OneofDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len); } -UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_resize_oneof_decl(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_resize_oneof_decl(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_OneofDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_OneofDescriptorProto* google_protobuf_DescriptorProto_add_oneof_decl(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_OneofDescriptorProto* google_protobuf_DescriptorProto_add_oneof_decl(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_OneofDescriptorProto* sub = (struct google_protobuf_OneofDescriptorProto*)_upb_Message_New(&google_protobuf_OneofDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(36, 72), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_mutable_reserved_range(google_protobuf_DescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_mutable_reserved_range(google_protobuf_DescriptorProto* msg, size_t* len) { return (google_protobuf_DescriptorProto_ReservedRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len); } -UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_resize_reserved_range(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_resize_reserved_range(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_DescriptorProto_ReservedRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_add_reserved_range(google_protobuf_DescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_add_reserved_range(google_protobuf_DescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_DescriptorProto_ReservedRange* sub = (struct google_protobuf_DescriptorProto_ReservedRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_mutable_reserved_name(google_protobuf_DescriptorProto *msg, size_t *len) { +UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_mutable_reserved_name(google_protobuf_DescriptorProto* msg, size_t* len) { return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len); } -UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_resize_reserved_name(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_resize_reserved_name(google_protobuf_DescriptorProto* msg, size_t len, upb_Arena* arena) { return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(44, 88), len, UPB_SIZE(3, 4), arena); } -UPB_INLINE bool google_protobuf_DescriptorProto_add_reserved_name(google_protobuf_DescriptorProto *msg, upb_StringView val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(44, 88), UPB_SIZE(3, 4), &val, - arena); +UPB_INLINE bool google_protobuf_DescriptorProto_add_reserved_name(google_protobuf_DescriptorProto* msg, upb_StringView val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(44, 88), UPB_SIZE(3, 4), &val, arena); } /* google.protobuf.DescriptorProto.ExtensionRange */ @@ -2861,15 +2951,21 @@ UPB_INLINE char* google_protobuf_DescriptorProto_ExtensionRange_serialize_ex(con upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_DescriptorProto_ExtensionRange_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_start(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_end(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } -UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_options(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { + return _upb_hasbit(msg, 3); +} UPB_INLINE const google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), const google_protobuf_ExtensionRangeOptions*); } @@ -2886,7 +2982,7 @@ UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_options(googl _upb_sethas(msg, 3); *UPB_PTR_AT(msg, UPB_SIZE(12, 16), google_protobuf_ExtensionRangeOptions*) = value; } -UPB_INLINE struct google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_mutable_options(google_protobuf_DescriptorProto_ExtensionRange *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_mutable_options(google_protobuf_DescriptorProto_ExtensionRange* msg, upb_Arena* arena) { struct google_protobuf_ExtensionRangeOptions* sub = (struct google_protobuf_ExtensionRangeOptions*)google_protobuf_DescriptorProto_ExtensionRange_options(msg); if (sub == NULL) { sub = (struct google_protobuf_ExtensionRangeOptions*)_upb_Message_New(&google_protobuf_ExtensionRangeOptions_msginit, arena); @@ -2927,11 +3023,15 @@ UPB_INLINE char* google_protobuf_DescriptorProto_ReservedRange_serialize_ex(cons upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_start(const google_protobuf_DescriptorProto_ReservedRange *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_start(const google_protobuf_DescriptorProto_ReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_end(const google_protobuf_DescriptorProto_ReservedRange *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_end(const google_protobuf_DescriptorProto_ReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } @@ -2976,19 +3076,22 @@ UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize_ex(const google upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_ExtensionRangeOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_ExtensionRangeOptions_has_uninterpreted_option(const google_protobuf_ExtensionRangeOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ExtensionRangeOptions_uninterpreted_option(const google_protobuf_ExtensionRangeOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } +UPB_INLINE bool google_protobuf_ExtensionRangeOptions_has_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ExtensionRangeOptions_uninterpreted_option(const google_protobuf_ExtensionRangeOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); +} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_mutable_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_mutable_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_resize_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_resize_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ExtensionRangeOptions_add_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ExtensionRangeOptions_add_uninterpreted_option(google_protobuf_ExtensionRangeOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -3024,47 +3127,69 @@ UPB_INLINE char* google_protobuf_FieldDescriptorProto_serialize_ex(const google_ upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_FieldDescriptorProto_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_name(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_name(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_StringView); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_extendee(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_StringView); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_number(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_number(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 3); +} UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_number(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_label(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_label(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 4); +} UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_label(const google_protobuf_FieldDescriptorProto* msg) { return google_protobuf_FieldDescriptorProto_has_label(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) : 1; } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 5); +} UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_type(const google_protobuf_FieldDescriptorProto* msg) { return google_protobuf_FieldDescriptorProto_has_type(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) : 1; } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 6); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_type_name(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_StringView); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 7); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 7); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_default_value(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_StringView); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 8); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 8); +} UPB_INLINE const google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_options(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(64, 104), const google_protobuf_FieldOptions*); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 9); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 9); +} UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_oneof_index(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 10); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 10); +} UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_json_name(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_StringView); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 11); } +UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { + return _upb_hasbit(msg, 11); +} UPB_INLINE bool google_protobuf_FieldDescriptorProto_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool); } @@ -3101,7 +3226,7 @@ UPB_INLINE void google_protobuf_FieldDescriptorProto_set_options(google_protobuf _upb_sethas(msg, 8); *UPB_PTR_AT(msg, UPB_SIZE(64, 104), google_protobuf_FieldOptions*) = value; } -UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options(google_protobuf_FieldDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options(google_protobuf_FieldDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_FieldOptions* sub = (struct google_protobuf_FieldOptions*)google_protobuf_FieldDescriptorProto_options(msg); if (sub == NULL) { sub = (struct google_protobuf_FieldOptions*)_upb_Message_New(&google_protobuf_FieldOptions_msginit, arena); @@ -3154,11 +3279,15 @@ UPB_INLINE char* google_protobuf_OneofDescriptorProto_serialize_ex(const google_ upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_OneofDescriptorProto_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_protobuf_OneofDescriptorProto *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_protobuf_OneofDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_OneofDescriptorProto_name(const google_protobuf_OneofDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE const google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_options(const google_protobuf_OneofDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_OneofOptions*); } @@ -3171,7 +3300,7 @@ UPB_INLINE void google_protobuf_OneofDescriptorProto_set_options(google_protobuf _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_OneofOptions*) = value; } -UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_mutable_options(google_protobuf_OneofDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_mutable_options(google_protobuf_OneofDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_OneofOptions* sub = (struct google_protobuf_OneofOptions*)google_protobuf_OneofDescriptorProto_options(msg); if (sub == NULL) { sub = (struct google_protobuf_OneofOptions*)_upb_Message_New(&google_protobuf_OneofOptions_msginit, arena); @@ -3212,34 +3341,47 @@ UPB_INLINE char* google_protobuf_EnumDescriptorProto_serialize_ex(const google_p upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_EnumDescriptorProto_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_name(const google_protobuf_EnumDescriptorProto *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_name(const google_protobuf_EnumDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_EnumDescriptorProto_name(const google_protobuf_EnumDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_value(const google_protobuf_EnumDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); } -UPB_INLINE const google_protobuf_EnumValueDescriptorProto* const* google_protobuf_EnumDescriptorProto_value(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumValueDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_options(const google_protobuf_EnumDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_value(const google_protobuf_EnumDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); +} +UPB_INLINE const google_protobuf_EnumValueDescriptorProto* const* google_protobuf_EnumDescriptorProto_value(const google_protobuf_EnumDescriptorProto* msg, size_t* len) { + return (const google_protobuf_EnumValueDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); +} +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_options(const google_protobuf_EnumDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE const google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_options(const google_protobuf_EnumDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_EnumOptions*); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_reserved_range(const google_protobuf_EnumDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); } -UPB_INLINE const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* google_protobuf_EnumDescriptorProto_reserved_range(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumDescriptorProto_EnumReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE upb_StringView const* google_protobuf_EnumDescriptorProto_reserved_name(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } +UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_reserved_range(const google_protobuf_EnumDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); +} +UPB_INLINE const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* google_protobuf_EnumDescriptorProto_reserved_range(const google_protobuf_EnumDescriptorProto* msg, size_t* len) { + return (const google_protobuf_EnumDescriptorProto_EnumReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); +} +UPB_INLINE upb_StringView const* google_protobuf_EnumDescriptorProto_reserved_name(const google_protobuf_EnumDescriptorProto* msg, size_t* len) { + return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); +} UPB_INLINE void google_protobuf_EnumDescriptorProto_set_name(google_protobuf_EnumDescriptorProto *msg, upb_StringView value) { _upb_sethas(msg, 1); *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; } -UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_mutable_value(google_protobuf_EnumDescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_mutable_value(google_protobuf_EnumDescriptorProto* msg, size_t* len) { return (google_protobuf_EnumValueDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_EnumValueDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumDescriptorProto_add_value(google_protobuf_EnumDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumDescriptorProto_add_value(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumValueDescriptorProto* sub = (struct google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google_protobuf_EnumValueDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -3247,7 +3389,7 @@ UPB_INLINE void google_protobuf_EnumDescriptorProto_set_options(google_protobuf_ _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_EnumOptions*) = value; } -UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_mutable_options(google_protobuf_EnumDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_mutable_options(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumOptions* sub = (struct google_protobuf_EnumOptions*)google_protobuf_EnumDescriptorProto_options(msg); if (sub == NULL) { sub = (struct google_protobuf_EnumOptions*)_upb_Message_New(&google_protobuf_EnumOptions_msginit, arena); @@ -3256,28 +3398,26 @@ UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorPro } return sub; } -UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_mutable_reserved_range(google_protobuf_EnumDescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_mutable_reserved_range(google_protobuf_EnumDescriptorProto* msg, size_t* len) { return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_resize_reserved_range(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_resize_reserved_range(google_protobuf_EnumDescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_add_reserved_range(google_protobuf_EnumDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_add_reserved_range(google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumDescriptorProto_EnumReservedRange* sub = (struct google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } -UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_mutable_reserved_name(google_protobuf_EnumDescriptorProto *msg, size_t *len) { +UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_mutable_reserved_name(google_protobuf_EnumDescriptorProto* msg, size_t* len) { return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_resize_reserved_name(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_resize_reserved_name(google_protobuf_EnumDescriptorProto* msg, size_t len, upb_Arena* arena) { return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(3, 4), arena); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_add_reserved_name(google_protobuf_EnumDescriptorProto *msg, upb_StringView val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(3, 4), &val, - arena); +UPB_INLINE bool google_protobuf_EnumDescriptorProto_add_reserved_name(google_protobuf_EnumDescriptorProto* msg, upb_StringView val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(3, 4), &val, arena); } /* google.protobuf.EnumDescriptorProto.EnumReservedRange */ @@ -3311,11 +3451,15 @@ UPB_INLINE char* google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } @@ -3360,15 +3504,21 @@ UPB_INLINE char* google_protobuf_EnumValueDescriptorProto_serialize_ex(const goo upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_EnumValueDescriptorProto_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_name(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_name(const google_protobuf_EnumValueDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_EnumValueDescriptorProto_name(const google_protobuf_EnumValueDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_number(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_number(const google_protobuf_EnumValueDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE int32_t google_protobuf_EnumValueDescriptorProto_number(const google_protobuf_EnumValueDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto* msg) { + return _upb_hasbit(msg, 3); +} UPB_INLINE const google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_options(const google_protobuf_EnumValueDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const google_protobuf_EnumValueOptions*); } @@ -3385,7 +3535,7 @@ UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_options(google_prot _upb_sethas(msg, 3); *UPB_PTR_AT(msg, UPB_SIZE(16, 24), google_protobuf_EnumValueOptions*) = value; } -UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_mutable_options(google_protobuf_EnumValueDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_mutable_options(google_protobuf_EnumValueDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_EnumValueOptions* sub = (struct google_protobuf_EnumValueOptions*)google_protobuf_EnumValueDescriptorProto_options(msg); if (sub == NULL) { sub = (struct google_protobuf_EnumValueOptions*)_upb_Message_New(&google_protobuf_EnumValueOptions_msginit, arena); @@ -3426,13 +3576,21 @@ UPB_INLINE char* google_protobuf_ServiceDescriptorProto_serialize_ex(const googl upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_ServiceDescriptorProto_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_name(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_name(const google_protobuf_ServiceDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_ServiceDescriptorProto_name(const google_protobuf_ServiceDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_method(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); } -UPB_INLINE const google_protobuf_MethodDescriptorProto* const* google_protobuf_ServiceDescriptorProto_method(const google_protobuf_ServiceDescriptorProto *msg, size_t *len) { return (const google_protobuf_MethodDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_options(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_method(const google_protobuf_ServiceDescriptorProto* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); +} +UPB_INLINE const google_protobuf_MethodDescriptorProto* const* google_protobuf_ServiceDescriptorProto_method(const google_protobuf_ServiceDescriptorProto* msg, size_t* len) { + return (const google_protobuf_MethodDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); +} +UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_options(const google_protobuf_ServiceDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE const google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_options(const google_protobuf_ServiceDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_ServiceOptions*); } @@ -3441,16 +3599,15 @@ UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_name(google_protobuf_ _upb_sethas(msg, 1); *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value; } -UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_mutable_method(google_protobuf_ServiceDescriptorProto *msg, size_t *len) { +UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_mutable_method(google_protobuf_ServiceDescriptorProto* msg, size_t* len) { return (google_protobuf_MethodDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto* msg, size_t len, upb_Arena* arena) { return (google_protobuf_MethodDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_ServiceDescriptorProto_add_method(google_protobuf_ServiceDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_ServiceDescriptorProto_add_method(google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_MethodDescriptorProto* sub = (struct google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google_protobuf_MethodDescriptorProto_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -3458,7 +3615,7 @@ UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_options(google_protob _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_ServiceOptions*) = value; } -UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_mutable_options(google_protobuf_ServiceDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_mutable_options(google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_ServiceOptions* sub = (struct google_protobuf_ServiceOptions*)google_protobuf_ServiceDescriptorProto_options(msg); if (sub == NULL) { sub = (struct google_protobuf_ServiceOptions*)_upb_Message_New(&google_protobuf_ServiceOptions_msginit, arena); @@ -3499,27 +3656,39 @@ UPB_INLINE char* google_protobuf_MethodDescriptorProto_serialize_ex(const google upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_MethodDescriptorProto_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_name(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_name(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_name(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_input_type(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_input_type(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_input_type(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_output_type(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_output_type(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 3); +} UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_output_type(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_options(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_options(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 4); +} UPB_INLINE const google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_options(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_MethodOptions*); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_client_streaming(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 5); +} UPB_INLINE bool google_protobuf_MethodDescriptorProto_client_streaming(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_server_streaming(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { + return _upb_hasbit(msg, 6); +} UPB_INLINE bool google_protobuf_MethodDescriptorProto_server_streaming(const google_protobuf_MethodDescriptorProto* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } @@ -3540,7 +3709,7 @@ UPB_INLINE void google_protobuf_MethodDescriptorProto_set_options(google_protobu _upb_sethas(msg, 4); *UPB_PTR_AT(msg, UPB_SIZE(28, 56), google_protobuf_MethodOptions*) = value; } -UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_mutable_options(google_protobuf_MethodDescriptorProto *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_mutable_options(google_protobuf_MethodDescriptorProto* msg, upb_Arena* arena) { struct google_protobuf_MethodOptions* sub = (struct google_protobuf_MethodOptions*)google_protobuf_MethodDescriptorProto_options(msg); if (sub == NULL) { sub = (struct google_protobuf_MethodOptions*)_upb_Message_New(&google_protobuf_MethodOptions_msginit, arena); @@ -3589,88 +3758,132 @@ UPB_INLINE char* google_protobuf_FileOptions_serialize_ex(const google_protobuf_ upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_FileOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_package(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_package(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_java_package(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_outer_classname(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_outer_classname(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_java_outer_classname(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_optimize_for(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_FileOptions_has_optimize_for(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 3); +} UPB_INLINE int32_t google_protobuf_FileOptions_optimize_for(const google_protobuf_FileOptions* msg) { return google_protobuf_FileOptions_has_optimize_for(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) : 1; } -UPB_INLINE bool google_protobuf_FileOptions_has_java_multiple_files(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_multiple_files(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 4); +} UPB_INLINE bool google_protobuf_FileOptions_java_multiple_files(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_go_package(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE bool google_protobuf_FileOptions_has_go_package(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 5); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_go_package(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(36, 56), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_cc_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE bool google_protobuf_FileOptions_has_cc_generic_services(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 6); +} UPB_INLINE bool google_protobuf_FileOptions_cc_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 7); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_generic_services(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 7); +} UPB_INLINE bool google_protobuf_FileOptions_java_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_py_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 8); } +UPB_INLINE bool google_protobuf_FileOptions_has_py_generic_services(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 8); +} UPB_INLINE bool google_protobuf_FileOptions_py_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(11, 11), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_generate_equals_and_hash(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 9); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 9); +} UPB_INLINE bool google_protobuf_FileOptions_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_deprecated(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 10); } +UPB_INLINE bool google_protobuf_FileOptions_has_deprecated(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 10); +} UPB_INLINE bool google_protobuf_FileOptions_deprecated(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_string_check_utf8(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 11); } +UPB_INLINE bool google_protobuf_FileOptions_has_java_string_check_utf8(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 11); +} UPB_INLINE bool google_protobuf_FileOptions_java_string_check_utf8(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_cc_enable_arenas(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 12); } +UPB_INLINE bool google_protobuf_FileOptions_has_cc_enable_arenas(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 12); +} UPB_INLINE bool google_protobuf_FileOptions_cc_enable_arenas(const google_protobuf_FileOptions* msg) { return google_protobuf_FileOptions_has_cc_enable_arenas(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) : true; } -UPB_INLINE bool google_protobuf_FileOptions_has_objc_class_prefix(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 13); } +UPB_INLINE bool google_protobuf_FileOptions_has_objc_class_prefix(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 13); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_objc_class_prefix(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 72), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_csharp_namespace(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 14); } +UPB_INLINE bool google_protobuf_FileOptions_has_csharp_namespace(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 14); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_csharp_namespace(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 88), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_swift_prefix(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 15); } +UPB_INLINE bool google_protobuf_FileOptions_has_swift_prefix(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 15); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_swift_prefix(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(60, 104), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_php_class_prefix(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 16); } +UPB_INLINE bool google_protobuf_FileOptions_has_php_class_prefix(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 16); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_php_class_prefix(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(68, 120), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_php_namespace(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 17); } +UPB_INLINE bool google_protobuf_FileOptions_has_php_namespace(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 17); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_php_namespace(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(76, 136), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_php_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 18); } +UPB_INLINE bool google_protobuf_FileOptions_has_php_generic_services(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 18); +} UPB_INLINE bool google_protobuf_FileOptions_php_generic_services(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_php_metadata_namespace(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 19); } +UPB_INLINE bool google_protobuf_FileOptions_has_php_metadata_namespace(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 19); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_php_metadata_namespace(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(84, 152), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_ruby_package(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 20); } +UPB_INLINE bool google_protobuf_FileOptions_has_ruby_package(const google_protobuf_FileOptions* msg) { + return _upb_hasbit(msg, 20); +} UPB_INLINE upb_StringView google_protobuf_FileOptions_ruby_package(const google_protobuf_FileOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_StringView); } -UPB_INLINE bool google_protobuf_FileOptions_has_uninterpreted_option(const google_protobuf_FileOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(100, 184)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FileOptions_uninterpreted_option(const google_protobuf_FileOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(100, 184), len); } +UPB_INLINE bool google_protobuf_FileOptions_has_uninterpreted_option(const google_protobuf_FileOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(100, 184)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FileOptions_uninterpreted_option(const google_protobuf_FileOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(100, 184), len); +} UPB_INLINE void google_protobuf_FileOptions_set_java_package(google_protobuf_FileOptions *msg, upb_StringView value) { _upb_sethas(msg, 1); @@ -3752,16 +3965,15 @@ UPB_INLINE void google_protobuf_FileOptions_set_ruby_package(google_protobuf_Fil _upb_sethas(msg, 20); *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_StringView) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_mutable_uninterpreted_option(google_protobuf_FileOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_mutable_uninterpreted_option(google_protobuf_FileOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(100, 184), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_resize_uninterpreted_option(google_protobuf_FileOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_resize_uninterpreted_option(google_protobuf_FileOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(100, 184), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptions_add_uninterpreted_option(google_protobuf_FileOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptions_add_uninterpreted_option(google_protobuf_FileOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(100, 184), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(100, 184), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -3797,24 +4009,36 @@ UPB_INLINE char* google_protobuf_MessageOptions_serialize_ex(const google_protob upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_MessageOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_MessageOptions_has_message_set_wire_format(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_MessageOptions_has_message_set_wire_format(const google_protobuf_MessageOptions* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE bool google_protobuf_MessageOptions_message_set_wire_format(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_MessageOptions_has_no_standard_descriptor_accessor(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_MessageOptions_has_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE bool google_protobuf_MessageOptions_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } -UPB_INLINE bool google_protobuf_MessageOptions_has_deprecated(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_MessageOptions_has_deprecated(const google_protobuf_MessageOptions* msg) { + return _upb_hasbit(msg, 3); +} UPB_INLINE bool google_protobuf_MessageOptions_deprecated(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool); } -UPB_INLINE bool google_protobuf_MessageOptions_has_map_entry(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE bool google_protobuf_MessageOptions_has_map_entry(const google_protobuf_MessageOptions* msg) { + return _upb_hasbit(msg, 4); +} UPB_INLINE bool google_protobuf_MessageOptions_map_entry(const google_protobuf_MessageOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool); } -UPB_INLINE bool google_protobuf_MessageOptions_has_uninterpreted_option(const google_protobuf_MessageOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MessageOptions_uninterpreted_option(const google_protobuf_MessageOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(8, 8), len); } +UPB_INLINE bool google_protobuf_MessageOptions_has_uninterpreted_option(const google_protobuf_MessageOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MessageOptions_uninterpreted_option(const google_protobuf_MessageOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(8, 8), len); +} UPB_INLINE void google_protobuf_MessageOptions_set_message_set_wire_format(google_protobuf_MessageOptions *msg, bool value) { _upb_sethas(msg, 1); @@ -3832,16 +4056,15 @@ UPB_INLINE void google_protobuf_MessageOptions_set_map_entry(google_protobuf_Mes _upb_sethas(msg, 4); *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_mutable_uninterpreted_option(google_protobuf_MessageOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_mutable_uninterpreted_option(google_protobuf_MessageOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 8), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_resize_uninterpreted_option(google_protobuf_MessageOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_resize_uninterpreted_option(google_protobuf_MessageOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(8, 8), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOptions_add_uninterpreted_option(google_protobuf_MessageOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOptions_add_uninterpreted_option(google_protobuf_MessageOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(8, 8), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(8, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -3877,32 +4100,54 @@ UPB_INLINE char* google_protobuf_FieldOptions_serialize_ex(const google_protobuf upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_FieldOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_FieldOptions_has_ctype(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_FieldOptions_has_ctype(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE int32_t google_protobuf_FieldOptions_ctype(const google_protobuf_FieldOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_FieldOptions_has_packed(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_FieldOptions_has_packed(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE bool google_protobuf_FieldOptions_packed(const google_protobuf_FieldOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool); } -UPB_INLINE bool google_protobuf_FieldOptions_has_deprecated(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_FieldOptions_has_deprecated(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 3); +} UPB_INLINE bool google_protobuf_FieldOptions_deprecated(const google_protobuf_FieldOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool); } -UPB_INLINE bool google_protobuf_FieldOptions_has_lazy(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE bool google_protobuf_FieldOptions_has_lazy(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 4); +} UPB_INLINE bool google_protobuf_FieldOptions_lazy(const google_protobuf_FieldOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool); } -UPB_INLINE bool google_protobuf_FieldOptions_has_jstype(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE bool google_protobuf_FieldOptions_has_jstype(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 5); +} UPB_INLINE int32_t google_protobuf_FieldOptions_jstype(const google_protobuf_FieldOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } -UPB_INLINE bool google_protobuf_FieldOptions_has_weak(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE bool google_protobuf_FieldOptions_has_weak(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 6); +} UPB_INLINE bool google_protobuf_FieldOptions_weak(const google_protobuf_FieldOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool); } -UPB_INLINE bool google_protobuf_FieldOptions_has_uninterpreted_option(const google_protobuf_FieldOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 16)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FieldOptions_uninterpreted_option(const google_protobuf_FieldOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(16, 16), len); } +UPB_INLINE bool google_protobuf_FieldOptions_has_unverified_lazy(const google_protobuf_FieldOptions* msg) { + return _upb_hasbit(msg, 7); +} +UPB_INLINE bool google_protobuf_FieldOptions_unverified_lazy(const google_protobuf_FieldOptions* msg) { + return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); +} +UPB_INLINE bool google_protobuf_FieldOptions_has_uninterpreted_option(const google_protobuf_FieldOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 24)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FieldOptions_uninterpreted_option(const google_protobuf_FieldOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(20, 24), len); +} UPB_INLINE void google_protobuf_FieldOptions_set_ctype(google_protobuf_FieldOptions *msg, int32_t value) { _upb_sethas(msg, 1); @@ -3928,16 +4173,19 @@ UPB_INLINE void google_protobuf_FieldOptions_set_weak(google_protobuf_FieldOptio _upb_sethas(msg, 6); *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_mutable_uninterpreted_option(google_protobuf_FieldOptions *msg, size_t *len) { - return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 16), len); +UPB_INLINE void google_protobuf_FieldOptions_set_unverified_lazy(google_protobuf_FieldOptions *msg, bool value) { + _upb_sethas(msg, 7); + *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_resize_uninterpreted_option(google_protobuf_FieldOptions *msg, size_t len, upb_Arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 16), len, UPB_SIZE(2, 3), arena); +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_mutable_uninterpreted_option(google_protobuf_FieldOptions* msg, size_t* len) { + return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 24), len); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOptions_add_uninterpreted_option(google_protobuf_FieldOptions *msg, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_resize_uninterpreted_option(google_protobuf_FieldOptions* msg, size_t len, upb_Arena* arena) { + return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 24), len, UPB_SIZE(2, 3), arena); +} +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOptions_add_uninterpreted_option(google_protobuf_FieldOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(16, 16), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 24), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -3973,19 +4221,22 @@ UPB_INLINE char* google_protobuf_OneofOptions_serialize_ex(const google_protobuf upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_OneofOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_OneofOptions_has_uninterpreted_option(const google_protobuf_OneofOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_OneofOptions_uninterpreted_option(const google_protobuf_OneofOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } +UPB_INLINE bool google_protobuf_OneofOptions_has_uninterpreted_option(const google_protobuf_OneofOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_OneofOptions_uninterpreted_option(const google_protobuf_OneofOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); +} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_mutable_uninterpreted_option(google_protobuf_OneofOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_mutable_uninterpreted_option(google_protobuf_OneofOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_resize_uninterpreted_option(google_protobuf_OneofOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_resize_uninterpreted_option(google_protobuf_OneofOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOptions_add_uninterpreted_option(google_protobuf_OneofOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOptions_add_uninterpreted_option(google_protobuf_OneofOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4021,16 +4272,24 @@ UPB_INLINE char* google_protobuf_EnumOptions_serialize_ex(const google_protobuf_ upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_EnumOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_EnumOptions_has_allow_alias(const google_protobuf_EnumOptions *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_EnumOptions_has_allow_alias(const google_protobuf_EnumOptions* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE bool google_protobuf_EnumOptions_allow_alias(const google_protobuf_EnumOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_EnumOptions_has_deprecated(const google_protobuf_EnumOptions *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_EnumOptions_has_deprecated(const google_protobuf_EnumOptions* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE bool google_protobuf_EnumOptions_deprecated(const google_protobuf_EnumOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } -UPB_INLINE bool google_protobuf_EnumOptions_has_uninterpreted_option(const google_protobuf_EnumOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumOptions_uninterpreted_option(const google_protobuf_EnumOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } +UPB_INLINE bool google_protobuf_EnumOptions_has_uninterpreted_option(const google_protobuf_EnumOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumOptions_uninterpreted_option(const google_protobuf_EnumOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); +} UPB_INLINE void google_protobuf_EnumOptions_set_allow_alias(google_protobuf_EnumOptions *msg, bool value) { _upb_sethas(msg, 1); @@ -4040,16 +4299,15 @@ UPB_INLINE void google_protobuf_EnumOptions_set_deprecated(google_protobuf_EnumO _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_mutable_uninterpreted_option(google_protobuf_EnumOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_mutable_uninterpreted_option(google_protobuf_EnumOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_resize_uninterpreted_option(google_protobuf_EnumOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_resize_uninterpreted_option(google_protobuf_EnumOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptions_add_uninterpreted_option(google_protobuf_EnumOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptions_add_uninterpreted_option(google_protobuf_EnumOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4085,27 +4343,32 @@ UPB_INLINE char* google_protobuf_EnumValueOptions_serialize_ex(const google_prot upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_EnumValueOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_EnumValueOptions_has_deprecated(const google_protobuf_EnumValueOptions *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_EnumValueOptions_has_deprecated(const google_protobuf_EnumValueOptions* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE bool google_protobuf_EnumValueOptions_deprecated(const google_protobuf_EnumValueOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_EnumValueOptions_has_uninterpreted_option(const google_protobuf_EnumValueOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumValueOptions_uninterpreted_option(const google_protobuf_EnumValueOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } +UPB_INLINE bool google_protobuf_EnumValueOptions_has_uninterpreted_option(const google_protobuf_EnumValueOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumValueOptions_uninterpreted_option(const google_protobuf_EnumValueOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); +} UPB_INLINE void google_protobuf_EnumValueOptions_set_deprecated(google_protobuf_EnumValueOptions *msg, bool value) { _upb_sethas(msg, 1); *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_mutable_uninterpreted_option(google_protobuf_EnumValueOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_mutable_uninterpreted_option(google_protobuf_EnumValueOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_resize_uninterpreted_option(google_protobuf_EnumValueOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_resize_uninterpreted_option(google_protobuf_EnumValueOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValueOptions_add_uninterpreted_option(google_protobuf_EnumValueOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValueOptions_add_uninterpreted_option(google_protobuf_EnumValueOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4141,27 +4404,32 @@ UPB_INLINE char* google_protobuf_ServiceOptions_serialize_ex(const google_protob upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_ServiceOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_ServiceOptions_has_deprecated(const google_protobuf_ServiceOptions *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_ServiceOptions_has_deprecated(const google_protobuf_ServiceOptions* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE bool google_protobuf_ServiceOptions_deprecated(const google_protobuf_ServiceOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_ServiceOptions_has_uninterpreted_option(const google_protobuf_ServiceOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ServiceOptions_uninterpreted_option(const google_protobuf_ServiceOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } +UPB_INLINE bool google_protobuf_ServiceOptions_has_uninterpreted_option(const google_protobuf_ServiceOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ServiceOptions_uninterpreted_option(const google_protobuf_ServiceOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); +} UPB_INLINE void google_protobuf_ServiceOptions_set_deprecated(google_protobuf_ServiceOptions *msg, bool value) { _upb_sethas(msg, 1); *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_mutable_uninterpreted_option(google_protobuf_ServiceOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_mutable_uninterpreted_option(google_protobuf_ServiceOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_resize_uninterpreted_option(google_protobuf_ServiceOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_resize_uninterpreted_option(google_protobuf_ServiceOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOptions_add_uninterpreted_option(google_protobuf_ServiceOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOptions_add_uninterpreted_option(google_protobuf_ServiceOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4197,16 +4465,24 @@ UPB_INLINE char* google_protobuf_MethodOptions_serialize_ex(const google_protobu upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_MethodOptions_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_MethodOptions_has_deprecated(const google_protobuf_MethodOptions *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_MethodOptions_has_deprecated(const google_protobuf_MethodOptions* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE bool google_protobuf_MethodOptions_deprecated(const google_protobuf_MethodOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); } -UPB_INLINE bool google_protobuf_MethodOptions_has_idempotency_level(const google_protobuf_MethodOptions *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_MethodOptions_has_idempotency_level(const google_protobuf_MethodOptions* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE int32_t google_protobuf_MethodOptions_idempotency_level(const google_protobuf_MethodOptions* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_MethodOptions_has_uninterpreted_option(const google_protobuf_MethodOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 16)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MethodOptions_uninterpreted_option(const google_protobuf_MethodOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(12, 16), len); } +UPB_INLINE bool google_protobuf_MethodOptions_has_uninterpreted_option(const google_protobuf_MethodOptions* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 16)); +} +UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MethodOptions_uninterpreted_option(const google_protobuf_MethodOptions* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(12, 16), len); +} UPB_INLINE void google_protobuf_MethodOptions_set_deprecated(google_protobuf_MethodOptions *msg, bool value) { _upb_sethas(msg, 1); @@ -4216,16 +4492,15 @@ UPB_INLINE void google_protobuf_MethodOptions_set_idempotency_level(google_proto _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_mutable_uninterpreted_option(google_protobuf_MethodOptions *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_mutable_uninterpreted_option(google_protobuf_MethodOptions* msg, size_t* len) { return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 16), len); } -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_resize_uninterpreted_option(google_protobuf_MethodOptions *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_resize_uninterpreted_option(google_protobuf_MethodOptions* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 16), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOptions_add_uninterpreted_option(google_protobuf_MethodOptions *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOptions_add_uninterpreted_option(google_protobuf_MethodOptions* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(12, 16), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(12, 16), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4261,43 +4536,58 @@ UPB_INLINE char* google_protobuf_UninterpretedOption_serialize_ex(const google_p upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_UninterpretedOption_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_name(const google_protobuf_UninterpretedOption *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(56, 80)); } -UPB_INLINE const google_protobuf_UninterpretedOption_NamePart* const* google_protobuf_UninterpretedOption_name(const google_protobuf_UninterpretedOption *msg, size_t *len) { return (const google_protobuf_UninterpretedOption_NamePart* const*)_upb_array_accessor(msg, UPB_SIZE(56, 80), len); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_identifier_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_UninterpretedOption_has_name(const google_protobuf_UninterpretedOption* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(56, 80)); +} +UPB_INLINE const google_protobuf_UninterpretedOption_NamePart* const* google_protobuf_UninterpretedOption_name(const google_protobuf_UninterpretedOption* msg, size_t* len) { + return (const google_protobuf_UninterpretedOption_NamePart* const*)_upb_array_accessor(msg, UPB_SIZE(56, 80), len); +} +UPB_INLINE bool google_protobuf_UninterpretedOption_has_identifier_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_identifier_value(const google_protobuf_UninterpretedOption* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_StringView); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_positive_int_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_UninterpretedOption_has_positive_int_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE uint64_t google_protobuf_UninterpretedOption_positive_int_value(const google_protobuf_UninterpretedOption* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), uint64_t); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_negative_int_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_UninterpretedOption_has_negative_int_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 3); +} UPB_INLINE int64_t google_protobuf_UninterpretedOption_negative_int_value(const google_protobuf_UninterpretedOption* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int64_t); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_double_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 4); } +UPB_INLINE bool google_protobuf_UninterpretedOption_has_double_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 4); +} UPB_INLINE double google_protobuf_UninterpretedOption_double_value(const google_protobuf_UninterpretedOption* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), double); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_string_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 5); } +UPB_INLINE bool google_protobuf_UninterpretedOption_has_string_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 5); +} UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_string_value(const google_protobuf_UninterpretedOption* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(40, 48), upb_StringView); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_aggregate_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 6); } +UPB_INLINE bool google_protobuf_UninterpretedOption_has_aggregate_value(const google_protobuf_UninterpretedOption* msg) { + return _upb_hasbit(msg, 6); +} UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_aggregate_value(const google_protobuf_UninterpretedOption* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(48, 64), upb_StringView); } -UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_mutable_name(google_protobuf_UninterpretedOption *msg, size_t *len) { +UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_mutable_name(google_protobuf_UninterpretedOption* msg, size_t* len) { return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 80), len); } -UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_resize_name(google_protobuf_UninterpretedOption *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_resize_name(google_protobuf_UninterpretedOption* msg, size_t len, upb_Arena* arena) { return (google_protobuf_UninterpretedOption_NamePart**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(56, 80), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_add_name(google_protobuf_UninterpretedOption *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_add_name(google_protobuf_UninterpretedOption* msg, upb_Arena* arena) { struct google_protobuf_UninterpretedOption_NamePart* sub = (struct google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google_protobuf_UninterpretedOption_NamePart_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(56, 80), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(56, 80), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4357,11 +4647,15 @@ UPB_INLINE char* google_protobuf_UninterpretedOption_NamePart_serialize_ex(const upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_UninterpretedOption_NamePart_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_name_part(const google_protobuf_UninterpretedOption_NamePart *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_NamePart_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_is_extension(const google_protobuf_UninterpretedOption_NamePart *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } @@ -4406,19 +4700,22 @@ UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize_ex(const google_protob upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_SourceCodeInfo_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_has_location(const google_protobuf_SourceCodeInfo *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_SourceCodeInfo_Location* const* google_protobuf_SourceCodeInfo_location(const google_protobuf_SourceCodeInfo *msg, size_t *len) { return (const google_protobuf_SourceCodeInfo_Location* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } +UPB_INLINE bool google_protobuf_SourceCodeInfo_has_location(const google_protobuf_SourceCodeInfo* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_SourceCodeInfo_Location* const* google_protobuf_SourceCodeInfo_location(const google_protobuf_SourceCodeInfo* msg, size_t* len) { + return (const google_protobuf_SourceCodeInfo_Location* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); +} -UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_mutable_location(google_protobuf_SourceCodeInfo *msg, size_t *len) { +UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_mutable_location(google_protobuf_SourceCodeInfo* msg, size_t* len) { return (google_protobuf_SourceCodeInfo_Location**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_resize_location(google_protobuf_SourceCodeInfo *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_resize_location(google_protobuf_SourceCodeInfo* msg, size_t len, upb_Arena* arena) { return (google_protobuf_SourceCodeInfo_Location**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_add_location(google_protobuf_SourceCodeInfo *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_add_location(google_protobuf_SourceCodeInfo* msg, upb_Arena* arena) { struct google_protobuf_SourceCodeInfo_Location* sub = (struct google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google_protobuf_SourceCodeInfo_Location_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4454,37 +4751,45 @@ UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize_ex(const goog upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_SourceCodeInfo_Location_msginit, options, arena, len); } -UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_path(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_span(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_leading_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_path(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); +} +UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_span(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); +} +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView); } -UPB_INLINE upb_StringView const* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); } +UPB_INLINE upb_StringView const* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { + return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); +} -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_path(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_path(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_path(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_Arena *arena) { +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_path(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, 2, arena); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_path(google_protobuf_SourceCodeInfo_Location *msg, int32_t val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), 2, &val, - arena); +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_path(google_protobuf_SourceCodeInfo_Location* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), 2, &val, arena); } -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_span(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_span(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_span(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_Arena *arena) { +UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_span(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, 2, arena); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf_SourceCodeInfo_Location *msg, int32_t val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), 2, &val, - arena); +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf_SourceCodeInfo_Location* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), 2, &val, arena); } UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_leading_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) { _upb_sethas(msg, 1); @@ -4494,15 +4799,14 @@ UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_trailing_comments(go _upb_sethas(msg, 2); *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value; } -UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_mutable_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { +UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_mutable_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, size_t* len) { return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); } -UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_resize_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_Arena *arena) { +UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_resize_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, size_t len, upb_Arena* arena) { return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(3, 4), arena); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(3, 4), &val, - arena); +UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_leading_detached_comments(google_protobuf_SourceCodeInfo_Location* msg, upb_StringView val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(3, 4), &val, arena); } /* google.protobuf.GeneratedCodeInfo */ @@ -4536,19 +4840,22 @@ UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize_ex(const google_pro upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_msginit, options, arena, len); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_has_annotation(const google_protobuf_GeneratedCodeInfo *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_GeneratedCodeInfo_Annotation* const* google_protobuf_GeneratedCodeInfo_annotation(const google_protobuf_GeneratedCodeInfo *msg, size_t *len) { return (const google_protobuf_GeneratedCodeInfo_Annotation* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_has_annotation(const google_protobuf_GeneratedCodeInfo* msg) { + return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); +} +UPB_INLINE const google_protobuf_GeneratedCodeInfo_Annotation* const* google_protobuf_GeneratedCodeInfo_annotation(const google_protobuf_GeneratedCodeInfo* msg, size_t* len) { + return (const google_protobuf_GeneratedCodeInfo_Annotation* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); +} -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_mutable_annotation(google_protobuf_GeneratedCodeInfo *msg, size_t *len) { +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_mutable_annotation(google_protobuf_GeneratedCodeInfo* msg, size_t* len) { return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); } -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_resize_annotation(google_protobuf_GeneratedCodeInfo *msg, size_t len, upb_Arena *arena) { +UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_resize_annotation(google_protobuf_GeneratedCodeInfo* msg, size_t len, upb_Arena* arena) { return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena); } -UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_add_annotation(google_protobuf_GeneratedCodeInfo *msg, upb_Arena *arena) { +UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_add_annotation(google_protobuf_GeneratedCodeInfo* msg, upb_Arena* arena) { struct google_protobuf_GeneratedCodeInfo_Annotation* sub = (struct google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena); - bool ok = _upb_Array_Append_accessor2( - msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); + bool ok = _upb_Array_Append_accessor2(msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena); if (!ok) return NULL; return sub; } @@ -4584,29 +4891,36 @@ UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize_ex(const upb_Arena* arena, size_t* len) { return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, options, arena, len); } -UPB_INLINE int32_t const* google_protobuf_GeneratedCodeInfo_Annotation_path(const google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 32), len); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_source_file(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_hasbit(msg, 1); } +UPB_INLINE int32_t const* google_protobuf_GeneratedCodeInfo_Annotation_path(const google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* len) { + return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 32), len); +} +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return _upb_hasbit(msg, 1); +} UPB_INLINE upb_StringView google_protobuf_GeneratedCodeInfo_Annotation_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_StringView); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_hasbit(msg, 2); } +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return _upb_hasbit(msg, 2); +} UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_hasbit(msg, 3); } +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { + return _upb_hasbit(msg, 3); +} UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } -UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_mutable_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t *len) { +UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_mutable_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t* len) { return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 32), len); } -UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_resize_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t len, upb_Arena *arena) { +UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_resize_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, size_t len, upb_Arena* arena) { return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 32), len, 2, arena); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t val, upb_Arena *arena) { - return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 32), 2, &val, - arena); +UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_protobuf_GeneratedCodeInfo_Annotation* msg, int32_t val, upb_Arena* arena) { + return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 32), 2, &val, arena); } UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_StringView value) { _upb_sethas(msg, 1); @@ -4794,8 +5108,8 @@ const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, int i); const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i); const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i); -const upb_FieldDef* upb_MessageDef_FindFieldByNumberWithSize( - const upb_MessageDef* m, uint32_t i); +const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, + uint32_t i); const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( const upb_MessageDef* m, const char* name, size_t len); const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( @@ -4923,6 +5237,7 @@ const google_protobuf_MethodOptions* upb_MethodDef_Options( const upb_MethodDef* m); bool upb_MethodDef_HasOptions(const upb_MethodDef* m); const char* upb_MethodDef_FullName(const upb_MethodDef* m); +int upb_MethodDef_Index(const upb_MethodDef* m); const char* upb_MethodDef_Name(const upb_MethodDef* m); const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m); const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m); @@ -4995,7 +5310,15 @@ typedef struct _upb_DefPool_Init { upb_StringView descriptor; /* Serialized descriptor. */ } _upb_DefPool_Init; -bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init); +// Should only be directly called by tests. This variant lets us suppress +// the use of compiled-in tables, forcing a rebuild of the tables at runtime. +bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, + bool rebuild_minitable); + +UPB_INLINE bool _upb_DefPool_LoadDefInit(upb_DefPool* s, + const _upb_DefPool_Init* init) { + return _upb_DefPool_LoadDefInitEx(s, init, false); +} #ifdef __cplusplus @@ -5286,3 +5609,4 @@ size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, #undef UPB_POISON_MEMORY_REGION #undef UPB_UNPOISON_MEMORY_REGION #undef UPB_ASAN +#undef UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 From 2a9f806a69f12772d3ae4e770bd37dccf546c0c4 Mon Sep 17 00:00:00 2001 From: theodorerose Date: Mon, 14 Mar 2022 23:58:36 +0000 Subject: [PATCH 02/54] update python to 3 --- update_version.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/update_version.py b/update_version.py index 3a96991816d6..e1f259eb824e 100755 --- a/update_version.py +++ b/update_version.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Usage: ./update_version.py .. [] # # Example: @@ -201,7 +201,7 @@ def RewritePbH(line): '#if %s < PROTOBUF_MIN_PROTOC_VERSION' % cpp_version, line) return line - + RewriteTextFile('src/google/protobuf/stubs/common.h', RewriteCommon) RewriteTextFile('src/google/protobuf/port_def.inc', RewritePortDef) RewriteTextFile('src/google/protobuf/any.pb.h', RewritePbH) @@ -268,7 +268,7 @@ def UpdateJava(): RewriteXml('protoc-artifacts/pom.xml', lambda document : ReplaceText( Find(document.documentElement, 'version'), GetFullVersion())) - + RewriteTextFile('java/README.md', lambda line : re.sub( r'.*', From ebfa0d345e24165531498e2cded1c3ca87a074c3 Mon Sep 17 00:00:00 2001 From: theodorerose Date: Tue, 15 Mar 2022 21:12:45 +0000 Subject: [PATCH 03/54] Update protobuf version --- Protobuf-C++.podspec | 2 +- Protobuf.podspec | 2 +- configure.ac | 2 +- csharp/Google.Protobuf.Tools.nuspec | 2 +- .../Google.Protobuf/Google.Protobuf.csproj | 2 +- java/README.md | 6 +++--- java/bom/pom.xml | 2 +- java/core/pom.xml | 2 +- java/kotlin-lite/pom.xml | 2 +- java/kotlin/pom.xml | 2 +- java/lite.md | 2 +- java/lite/pom.xml | 2 +- java/pom.xml | 2 +- java/util/pom.xml | 2 +- js/package.json | 2 +- php/ext/google/protobuf/package.xml | 21 ++++++++++++++++--- php/ext/google/protobuf/protobuf.h | 2 +- protobuf_version.bzl | 2 +- protoc-artifacts/pom.xml | 2 +- python/google/protobuf/__init__.py | 2 +- ruby/google-protobuf.gemspec | 2 +- ruby/pom.xml | 4 ++-- src/google/protobuf/port_def.inc | 2 +- src/google/protobuf/stubs/common.h | 2 +- 24 files changed, 44 insertions(+), 29 deletions(-) diff --git a/Protobuf-C++.podspec b/Protobuf-C++.podspec index cc331e3fc03e..9cf983dc00cc 100644 --- a/Protobuf-C++.podspec +++ b/Protobuf-C++.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Protobuf-C++' - s.version = '3.20.0-rc1' + s.version = '3.20.0-rc2' s.summary = 'Protocol Buffers v3 runtime library for C++.' s.homepage = 'https://github.com/google/protobuf' s.license = 'BSD-3-Clause' diff --git a/Protobuf.podspec b/Protobuf.podspec index 3bd7147eafef..ed9df24640f1 100644 --- a/Protobuf.podspec +++ b/Protobuf.podspec @@ -5,7 +5,7 @@ # dependent projects use the :git notation to refer to the library. Pod::Spec.new do |s| s.name = 'Protobuf' - s.version = '3.20.0-rc1' + s.version = '3.20.0-rc2' s.summary = 'Protocol Buffers v.3 runtime library for Objective-C.' s.homepage = 'https://github.com/protocolbuffers/protobuf' s.license = 'BSD-3-Clause' diff --git a/configure.ac b/configure.ac index 2b1cdad667af..c5db5b005abf 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ AC_PREREQ(2.59) # In the SVN trunk, the version should always be the next anticipated release # version with the "-pre" suffix. (We used to use "-SNAPSHOT" but this pushed # the size of one file name in the dist tarfile over the 99-char limit.) -AC_INIT([Protocol Buffers],[3.20.0-rc-1],[protobuf@googlegroups.com],[protobuf]) +AC_INIT([Protocol Buffers],[3.20.0-rc-2],[protobuf@googlegroups.com],[protobuf]) AM_MAINTAINER_MODE([enable]) diff --git a/csharp/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec index 86f12c9211bc..3a3785a4390e 100644 --- a/csharp/Google.Protobuf.Tools.nuspec +++ b/csharp/Google.Protobuf.Tools.nuspec @@ -5,7 +5,7 @@ Google Protocol Buffers tools Tools for Protocol Buffers - Google's data interchange format. See project site for more info. - 3.20.0-rc1 + 3.20.0-rc2 Google Inc. protobuf-packages https://github.com/protocolbuffers/protobuf/blob/master/LICENSE diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj index db5329e30e95..9f8897a02c9c 100644 --- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj +++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj @@ -4,7 +4,7 @@ C# runtime library for Protocol Buffers - Google's data interchange format. Copyright 2015, Google Inc. Google Protocol Buffers - 3.20.0-rc1 + 3.20.0-rc2 7.2 Google Inc. diff --git a/java/README.md b/java/README.md index ecbb9a686bf8..637235aaa432 100644 --- a/java/README.md +++ b/java/README.md @@ -23,7 +23,7 @@ If you are using Maven, use the following: com.google.protobuf protobuf-java - 3.20.0-rc-1 + 3.20.0-rc-2 ``` @@ -37,7 +37,7 @@ protobuf-java-util package: com.google.protobuf protobuf-java-util - 3.20.0-rc-1 + 3.20.0-rc-2 ``` @@ -45,7 +45,7 @@ protobuf-java-util package: If you are using Gradle, add the following to your `build.gradle` file's dependencies: ``` - implementation 'com.google.protobuf:protobuf-java:3.20.0-rc-1' + implementation 'com.google.protobuf:protobuf-java:3.20.0-rc-2' ``` Again, be sure to check that the version number matches (or is newer than) the version number of protoc that you are using. diff --git a/java/bom/pom.xml b/java/bom/pom.xml index c5bcb0ae4032..7af3c7b177ee 100644 --- a/java/bom/pom.xml +++ b/java/bom/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-bom - 3.20.0-rc-1 + 3.20.0-rc-2 pom Protocol Buffers [BOM] diff --git a/java/core/pom.xml b/java/core/pom.xml index bce2b1140f84..7ee824037de4 100644 --- a/java/core/pom.xml +++ b/java/core/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0-rc-1 + 3.20.0-rc-2 protobuf-java diff --git a/java/kotlin-lite/pom.xml b/java/kotlin-lite/pom.xml index 6ccb10094166..9f6d4aa8d353 100644 --- a/java/kotlin-lite/pom.xml +++ b/java/kotlin-lite/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0-rc-1 + 3.20.0-rc-2 protobuf-kotlin-lite diff --git a/java/kotlin/pom.xml b/java/kotlin/pom.xml index 2ae5b683a854..baa4fe43f083 100644 --- a/java/kotlin/pom.xml +++ b/java/kotlin/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0-rc-1 + 3.20.0-rc-2 protobuf-kotlin diff --git a/java/lite.md b/java/lite.md index 1aeb52fca728..0795540538cf 100644 --- a/java/lite.md +++ b/java/lite.md @@ -30,7 +30,7 @@ protobuf Java runtime. If you are using Maven, use the following: com.google.protobuf protobuf-javalite - 3.20.0-rc-1 + 3.20.0-rc-2 ``` diff --git a/java/lite/pom.xml b/java/lite/pom.xml index 35d8ac291c7a..f04b77fbe66e 100644 --- a/java/lite/pom.xml +++ b/java/lite/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0-rc-1 + 3.20.0-rc-2 protobuf-javalite diff --git a/java/pom.xml b/java/pom.xml index 4869c94e73dd..7b868fce0729 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0-rc-1 + 3.20.0-rc-2 pom Protocol Buffers [Parent] diff --git a/java/util/pom.xml b/java/util/pom.xml index 34fcbb3ba487..51ad1a63e1c9 100644 --- a/java/util/pom.xml +++ b/java/util/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0-rc-1 + 3.20.0-rc-2 protobuf-java-util diff --git a/js/package.json b/js/package.json index 3f7e291fd16d..8d347fa3dc38 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "google-protobuf", - "version": "3.20.0-rc.1", + "version": "3.20.0-rc.2", "description": "Protocol Buffers for JavaScript", "main": "google-protobuf.js", "files": [ diff --git a/php/ext/google/protobuf/package.xml b/php/ext/google/protobuf/package.xml index 44c4815c386a..9675d2be2344 100644 --- a/php/ext/google/protobuf/package.xml +++ b/php/ext/google/protobuf/package.xml @@ -10,10 +10,10 @@ protobuf-opensource@google.com yes - 2022-03-04 - + 2022-03-15 + - 3.20.0RC1 + 3.20.0RC2 3.20.0 @@ -1221,5 +1221,20 @@ G A release. + + + 3.20.0RC2 + 3.20.0 + + + beta + beta + + 2022-03-15 + + BSD-3-Clause + + + diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h index 49b4e299df4a..46c560810a2c 100644 --- a/php/ext/google/protobuf/protobuf.h +++ b/php/ext/google/protobuf/protobuf.h @@ -127,7 +127,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_setter, 0, 0, 1) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() -#define PHP_PROTOBUF_VERSION "3.20.0RC1" +#define PHP_PROTOBUF_VERSION "3.20.0RC2" // ptr -> PHP object cache. This is a weak map that caches lazily-created // wrapper objects around upb types: diff --git a/protobuf_version.bzl b/protobuf_version.bzl index b2e158dc79bf..d6c42df98014 100644 --- a/protobuf_version.bzl +++ b/protobuf_version.bzl @@ -1 +1 @@ -PROTOBUF_VERSION = '3.20.0-rc-1' +PROTOBUF_VERSION = '3.20.0-rc-2' diff --git a/protoc-artifacts/pom.xml b/protoc-artifacts/pom.xml index 5df1af0b0584..7150c78c845c 100644 --- a/protoc-artifacts/pom.xml +++ b/protoc-artifacts/pom.xml @@ -8,7 +8,7 @@ com.google.protobuf protoc - 3.20.0-rc-1 + 3.20.0-rc-2 pom Protobuf Compiler diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py index b97fe711460b..cd0daeaeab5e 100644 --- a/python/google/protobuf/__init__.py +++ b/python/google/protobuf/__init__.py @@ -30,4 +30,4 @@ # Copyright 2007 Google Inc. All Rights Reserved. -__version__ = '3.20.0rc1' +__version__ = '3.20.0rc2' diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec index 759a35fb0b19..4612ab74fba7 100644 --- a/ruby/google-protobuf.gemspec +++ b/ruby/google-protobuf.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "google-protobuf" - s.version = "3.20.0.rc.1" + s.version = "3.20.0.rc.2" git_tag = "v#{s.version.to_s.sub('.rc.', '-rc')}" # Converts X.Y.Z.rc.N to vX.Y.Z-rcN, used for the git tag s.licenses = ["BSD-3-Clause"] s.summary = "Protocol Buffers" diff --git a/ruby/pom.xml b/ruby/pom.xml index bf6a8c9d018d..355019e0aa4d 100644 --- a/ruby/pom.xml +++ b/ruby/pom.xml @@ -9,7 +9,7 @@ com.google.protobuf.jruby protobuf-jruby - 3.20.0-rc-1 + 3.20.0-rc-2 Protocol Buffer JRuby native extension Protocol Buffers are a way of encoding structured data in an efficient yet @@ -76,7 +76,7 @@ com.google.protobuf protobuf-java-util - 3.20.0-rc-1 + 3.20.0-rc-2 org.jruby diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc index 552af7a5d64a..bdb2eecbe2e4 100644 --- a/src/google/protobuf/port_def.inc +++ b/src/google/protobuf/port_def.inc @@ -172,7 +172,7 @@ #ifdef PROTOBUF_VERSION_SUFFIX #error PROTOBUF_VERSION_SUFFIX was previously defined #endif -#define PROTOBUF_VERSION_SUFFIX "-rc1" +#define PROTOBUF_VERSION_SUFFIX "-rc2" #if defined(PROTOBUF_NAMESPACE) || defined(PROTOBUF_NAMESPACE_ID) #error PROTOBUF_NAMESPACE or PROTOBUF_NAMESPACE_ID was previously defined diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index fd23dac70485..32bd43616b0e 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -85,7 +85,7 @@ namespace internal { #define GOOGLE_PROTOBUF_VERSION 3020000 // A suffix string for alpha, beta or rc releases. Empty for stable releases. -#define GOOGLE_PROTOBUF_VERSION_SUFFIX "-rc1" +#define GOOGLE_PROTOBUF_VERSION_SUFFIX "-rc2" // The minimum header version which works with the current version of // the library. This constant should only be used by protoc's C++ code From b04d397d0493d0124d7471a88dedc4a0f9f70a35 Mon Sep 17 00:00:00 2001 From: j-min5u Date: Thu, 17 Mar 2022 14:26:29 +0900 Subject: [PATCH 04/54] remove redundant public modifiers --- .../protobuf/compiler/java/java_enum_field.cc | 20 +++++----- .../compiler/java/java_enum_field_lite.cc | 20 +++++----- .../protobuf/compiler/java/java_map_field.cc | 14 +++---- .../compiler/java/java_map_field_lite.cc | 14 +++---- .../protobuf/compiler/java/java_message.cc | 40 +++++++++---------- .../compiler/java/java_message_field.cc | 22 +++++----- .../compiler/java/java_message_field_lite.cc | 22 +++++----- .../compiler/java/java_message_lite.cc | 40 +++++++++---------- .../compiler/java/java_primitive_field.cc | 20 +++++----- .../java/java_primitive_field_lite.cc | 20 +++++----- .../compiler/java/java_string_field.cc | 20 +++++----- .../compiler/java/java_string_field_lite.cc | 22 +++++----- 12 files changed, 137 insertions(+), 137 deletions(-) diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc index 0e6fb44d000a..207e97c557e4 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -291,7 +291,7 @@ void ImmutableEnumFieldGenerator::GenerateKotlinDslMembers( WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, /* builder */ false); printer->Print(variables_, - "public fun ${$clear$kt_capitalized_name$$}$() {\n" + "fun ${$clear$kt_capitalized_name$$}$() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" "}\n"); @@ -299,7 +299,7 @@ void ImmutableEnumFieldGenerator::GenerateKotlinDslMembers( WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); printer->Print( variables_, - "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" + "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" "}\n"); } @@ -1082,12 +1082,12 @@ void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers( " */\n" "@kotlin.OptIn" "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" - "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$kt_deprecation$ public val $kt_name$: " + "$kt_deprecation$ $kt_name$: " "com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " @kotlin.jvm.JvmSynthetic\n" @@ -1100,7 +1100,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "add(value: $kt_type$) {\n" " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" @@ -1112,7 +1112,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslList" + "inline operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "plusAssign(value: $kt_type$) {\n" " add(value)\n" @@ -1123,7 +1123,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n" " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" @@ -1136,7 +1136,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslList" + "inline operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n" " addAll(values)\n" @@ -1148,7 +1148,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers( variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" - "public operator fun com.google.protobuf.kotlin.DslList" + "operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "set(index: kotlin.Int, value: $kt_type$) {\n" " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" @@ -1159,7 +1159,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "clear() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc index 27b62ac52308..caa7fe09fe24 100644 --- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc @@ -296,7 +296,7 @@ void ImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, /* builder */ false); printer->Print(variables_, - "public fun ${$clear$kt_capitalized_name$$}$() {\n" + "fun ${$clear$kt_capitalized_name$$}$() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" "}\n"); @@ -304,7 +304,7 @@ void ImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); printer->Print( variables_, - "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" + "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" "}\n"); } @@ -824,12 +824,12 @@ void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( " */\n" "@kotlin.OptIn" "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" - "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$kt_deprecation$ public val $kt_name$: " + "$kt_deprecation$ val $kt_name$: " "com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " @kotlin.jvm.JvmSynthetic\n" @@ -842,7 +842,7 @@ void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "add(value: $kt_type$) {\n" " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" @@ -854,7 +854,7 @@ void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslList" + "inline operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "plusAssign(value: $kt_type$) {\n" " add(value)\n" @@ -865,7 +865,7 @@ void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n" " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" @@ -878,7 +878,7 @@ void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslList" + "inline operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n" " addAll(values)\n" @@ -890,7 +890,7 @@ void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" - "public operator fun com.google.protobuf.kotlin.DslList" + "operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "set(index: kotlin.Int, value: $kt_type$) {\n" " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" @@ -901,7 +901,7 @@ void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "clear() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc index 606d26e93db3..f04307d1f52c 100644 --- a/src/google/protobuf/compiler/java/java_map_field.cc +++ b/src/google/protobuf/compiler/java/java_map_field.cc @@ -695,13 +695,13 @@ void ImmutableMapFieldGenerator::GenerateKotlinDslMembers( " */\n" "@kotlin.OptIn" "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" - "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); WriteFieldDocComment(printer, descriptor_); printer->Print( variables_, - "$kt_deprecation$ public val $kt_name$: " + "$kt_deprecation$ val $kt_name$: " "com.google.protobuf.kotlin.DslMap" "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " @kotlin.jvm.JvmSynthetic\n" @@ -714,7 +714,7 @@ void ImmutableMapFieldGenerator::GenerateKotlinDslMembers( printer->Print( variables_, "@JvmName(\"put$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslMap" + "fun com.google.protobuf.kotlin.DslMap" "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " .put(key: $kt_key_type$, value: $kt_value_type$) {\n" " $kt_dsl_builder$.${$put$capitalized_name$$}$(key, value)\n" @@ -726,7 +726,7 @@ void ImmutableMapFieldGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@JvmName(\"set$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslMap" + "inline operator fun com.google.protobuf.kotlin.DslMap" "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " .set(key: $kt_key_type$, value: $kt_value_type$) {\n" " put(key, value)\n" @@ -737,7 +737,7 @@ void ImmutableMapFieldGenerator::GenerateKotlinDslMembers( variables_, "@kotlin.jvm.JvmSynthetic\n" "@JvmName(\"remove$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslMap" + "fun com.google.protobuf.kotlin.DslMap" "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " .remove(key: $kt_key_type$) {\n" " $kt_dsl_builder$.${$remove$capitalized_name$$}$(key)\n" @@ -748,7 +748,7 @@ void ImmutableMapFieldGenerator::GenerateKotlinDslMembers( variables_, "@kotlin.jvm.JvmSynthetic\n" "@JvmName(\"putAll$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslMap" + "fun com.google.protobuf.kotlin.DslMap" "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " .putAll(map: kotlin.collections.Map<$kt_key_type$, $kt_value_type$>) " "{\n" @@ -760,7 +760,7 @@ void ImmutableMapFieldGenerator::GenerateKotlinDslMembers( variables_, "@kotlin.jvm.JvmSynthetic\n" "@JvmName(\"clear$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslMap" + "fun com.google.protobuf.kotlin.DslMap" "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " .clear() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc index f6245224068a..c26a964479cd 100644 --- a/src/google/protobuf/compiler/java/java_map_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc @@ -835,13 +835,13 @@ void ImmutableMapFieldLiteGenerator::GenerateKotlinDslMembers( " */\n" "@kotlin.OptIn" "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" - "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); WriteFieldDocComment(printer, descriptor_); printer->Print( variables_, - "$kt_deprecation$ public val $kt_name$: " + "$kt_deprecation$ val $kt_name$: " "com.google.protobuf.kotlin.DslMap" "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " @kotlin.jvm.JvmSynthetic\n" @@ -854,7 +854,7 @@ void ImmutableMapFieldLiteGenerator::GenerateKotlinDslMembers( printer->Print( variables_, "@JvmName(\"put$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslMap" + "fun com.google.protobuf.kotlin.DslMap" "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " .put(key: $kt_key_type$, value: $kt_value_type$) {\n" " $kt_dsl_builder$.${$put$capitalized_name$$}$(key, value)\n" @@ -866,7 +866,7 @@ void ImmutableMapFieldLiteGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@JvmName(\"set$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslMap" + "inline operator fun com.google.protobuf.kotlin.DslMap" "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " .set(key: $kt_key_type$, value: $kt_value_type$) {\n" " put(key, value)\n" @@ -877,7 +877,7 @@ void ImmutableMapFieldLiteGenerator::GenerateKotlinDslMembers( variables_, "@kotlin.jvm.JvmSynthetic\n" "@JvmName(\"remove$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslMap" + "fun com.google.protobuf.kotlin.DslMap" "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " .remove(key: $kt_key_type$) {\n" " $kt_dsl_builder$.${$remove$capitalized_name$$}$(key)\n" @@ -888,7 +888,7 @@ void ImmutableMapFieldLiteGenerator::GenerateKotlinDslMembers( variables_, "@kotlin.jvm.JvmSynthetic\n" "@JvmName(\"putAll$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslMap" + "fun com.google.protobuf.kotlin.DslMap" "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " .putAll(map: kotlin.collections.Map<$kt_key_type$, $kt_value_type$>) " "{\n" @@ -900,7 +900,7 @@ void ImmutableMapFieldLiteGenerator::GenerateKotlinDslMembers( variables_, "@kotlin.jvm.JvmSynthetic\n" "@JvmName(\"clear$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslMap" + "fun com.google.protobuf.kotlin.DslMap" "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " .clear() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 9918abc04f52..53b5bbfea6b3 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -1410,10 +1410,10 @@ void ImmutableMessageGenerator::GenerateKotlinDsl(io::Printer* printer) const { "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" "@com.google.protobuf.kotlin.ProtoDslMarker\n"); printer->Print( - "public class Dsl private constructor(\n" + "class Dsl private constructor(\n" " private val _builder: $message$.Builder\n" ") {\n" - " public companion object {\n" + " companion object {\n" " @kotlin.jvm.JvmSynthetic\n" " @kotlin.PublishedApi\n" " internal fun _create(builder: $message$.Builder): Dsl = " @@ -1435,10 +1435,10 @@ void ImmutableMessageGenerator::GenerateKotlinDsl(io::Printer* printer) const { for (auto oneof : oneofs_) { printer->Print( - "public val $oneof_name$Case: $message$.$oneof_capitalized_name$Case\n" + "val $oneof_name$Case: $message$.$oneof_capitalized_name$Case\n" " @JvmName(\"get$oneof_capitalized_name$Case\")\n" " get() = _builder.get$oneof_capitalized_name$Case()\n\n" - "public fun clear$oneof_capitalized_name$() {\n" + "fun clear$oneof_capitalized_name$() {\n" " _builder.clear$oneof_capitalized_name$()\n" "}\n", "oneof_name", context_->GetOneofGeneratorInfo(oneof)->name, @@ -1459,7 +1459,7 @@ void ImmutableMessageGenerator::GenerateKotlinMembers( io::Printer* printer) const { printer->Print( "@kotlin.jvm.JvmName(\"-initialize$camelcase_name$\")\n" - "public inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> " + "inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> " "kotlin.Unit): " "$message$ " "=\n" @@ -1469,7 +1469,7 @@ void ImmutableMessageGenerator::GenerateKotlinMembers( "message_kt", name_resolver_->GetKotlinExtensionsClassName(descriptor_), "message", name_resolver_->GetClassName(descriptor_, true)); - printer->Print("public object $name$Kt {\n", "name", descriptor_->name()); + printer->Print("object $name$Kt {\n", "name", descriptor_->name()); printer->Indent(); GenerateKotlinDsl(printer); for (int i = 0; i < descriptor_->nested_type_count(); i++) { @@ -1485,7 +1485,7 @@ void ImmutableMessageGenerator::GenerateTopLevelKotlinMembers( io::Printer* printer) const { printer->Print( "@kotlin.jvm.JvmSynthetic\n" - "public inline fun $message$.copy(block: $message_kt$.Dsl.() -> " + "inline fun $message$.copy(block: $message_kt$.Dsl.() -> " "kotlin.Unit): " "$message$ =\n" " $message_kt$.Dsl._create(this.toBuilder()).apply { block() " @@ -1525,7 +1525,7 @@ void ImmutableMessageGenerator::GenerateKotlinExtensions( printer->Print( "@Suppress(\"UNCHECKED_CAST\")\n" "@kotlin.jvm.JvmSynthetic\n" - "public operator fun get(extension: " + "operator fun get(extension: " "com.google.protobuf.ExtensionLite<$message$, T>): T {\n" " return if (extension.isRepeated) {\n" " get(extension as com.google.protobuf.ExtensionLite<$message$, " @@ -1541,7 +1541,7 @@ void ImmutableMessageGenerator::GenerateKotlinExtensions( "@kotlin.OptIn" "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" "@kotlin.jvm.JvmName(\"-getRepeatedExtension\")\n" - "public operator fun get(\n" + "operator fun get(\n" " extension: com.google.protobuf.ExtensionLite<$message$, List>\n" "): com.google.protobuf.kotlin.ExtensionList {\n" " return com.google.protobuf.kotlin.ExtensionList(extension, " @@ -1551,7 +1551,7 @@ void ImmutableMessageGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" - "public operator fun contains(extension: " + "operator fun contains(extension: " "com.google.protobuf.ExtensionLite<$message$, *>): " "Boolean {\n" " return _builder.hasExtension(extension)\n" @@ -1560,7 +1560,7 @@ void ImmutableMessageGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" - "public fun clear(extension: " + "fun clear(extension: " "com.google.protobuf.ExtensionLite<$message$, *>) " "{\n" " _builder.clearExtension(extension)\n" @@ -1580,7 +1580,7 @@ void ImmutableMessageGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun > set(\n" + "inline operator fun > set(\n" " extension: com.google.protobuf.ExtensionLite<$message$, T>,\n" " value: T\n" ") {\n" @@ -1591,7 +1591,7 @@ void ImmutableMessageGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun set(\n" + "inline operator fun set(\n" " extension: com.google.protobuf.ExtensionLite<$message$, " "com.google.protobuf.ByteString>,\n" " value: com.google.protobuf.ByteString\n" @@ -1603,7 +1603,7 @@ void ImmutableMessageGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun set(\n" + "inline operator fun set(\n" " extension: com.google.protobuf.ExtensionLite<$message$, T>,\n" " value: T\n" ") {\n" @@ -1613,7 +1613,7 @@ void ImmutableMessageGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" - "public fun com.google.protobuf.kotlin.ExtensionList com.google.protobuf.kotlin.ExtensionList.add(value: E) {\n" " _builder.addExtension(this.extension, value)\n" "}\n\n", @@ -1622,7 +1622,7 @@ void ImmutableMessageGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun " + "inline operator fun " "com.google.protobuf.kotlin.ExtensionList.plusAssign" "(value: E) {\n" @@ -1632,7 +1632,7 @@ void ImmutableMessageGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" - "public fun com.google.protobuf.kotlin.ExtensionList com.google.protobuf.kotlin.ExtensionList.addAll(values: Iterable) {\n" " for (value in values) {\n" " add(value)\n" @@ -1643,7 +1643,7 @@ void ImmutableMessageGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun " + "inline operator fun " "com.google.protobuf.kotlin.ExtensionList.plusAssign(values: " "Iterable) {\n" @@ -1653,7 +1653,7 @@ void ImmutableMessageGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" - "public operator fun " + "operator fun " "com.google.protobuf.kotlin.ExtensionList.set(index: Int, value: " "E) {\n" @@ -1664,7 +1664,7 @@ void ImmutableMessageGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline fun com.google.protobuf.kotlin.ExtensionList<*, " + "inline fun com.google.protobuf.kotlin.ExtensionList<*, " "$message$>.clear() {\n" " clear(extension)\n" "}\n\n", diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc index 694218c1d49c..004a3cde7f13 100644 --- a/src/google/protobuf/compiler/java/java_message_field.cc +++ b/src/google/protobuf/compiler/java/java_message_field.cc @@ -429,14 +429,14 @@ void ImmutableMessageFieldGenerator::GenerateKotlinDslMembers( WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, /* builder */ false); printer->Print(variables_, - "public fun ${$clear$kt_capitalized_name$$}$() {\n" + "fun ${$clear$kt_capitalized_name$$}$() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" "}\n"); WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); printer->Print( variables_, - "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" + "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" "}\n"); @@ -446,7 +446,7 @@ void ImmutableMessageFieldGenerator::GenerateKotlinDslMembers( void ImmutableMessageFieldGenerator::GenerateKotlinOrNull(io::Printer* printer) const { if (descriptor_->has_optional_keyword()) { printer->Print(variables_, - "public val $classname$Kt.Dsl.$name$OrNull: $kt_type$?\n" + "val $classname$Kt.Dsl.$name$OrNull: $kt_type$?\n" " get() = $kt_dsl_builder$.$name$OrNull\n"); } } @@ -1416,12 +1416,12 @@ void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers( " */\n" "@kotlin.OptIn" "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" - "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$kt_deprecation$ public val $kt_name$: " + "$kt_deprecation$ val $kt_name$: " "com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " @kotlin.jvm.JvmSynthetic\n" @@ -1434,7 +1434,7 @@ void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "add(value: $kt_type$) {\n" " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" @@ -1446,7 +1446,7 @@ void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslList" + "inline operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "plusAssign(value: $kt_type$) {\n" " add(value)\n" @@ -1457,7 +1457,7 @@ void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n" " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" @@ -1470,7 +1470,7 @@ void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslList" + "inline operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n" " addAll(values)\n" @@ -1482,7 +1482,7 @@ void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers( variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" - "public operator fun com.google.protobuf.kotlin.DslList" + "operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "set(index: kotlin.Int, value: $kt_type$) {\n" " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" @@ -1493,7 +1493,7 @@ void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "clear() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.cc b/src/google/protobuf/compiler/java/java_message_field_lite.cc index 4f4265fdf8ce..f04931a8296e 100644 --- a/src/google/protobuf/compiler/java/java_message_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc @@ -298,14 +298,14 @@ void ImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, /* builder */ false); printer->Print(variables_, - "public fun ${$clear$kt_capitalized_name$$}$() {\n" + "fun ${$clear$kt_capitalized_name$$}$() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" "}\n"); WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); printer->Print( variables_, - "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" + "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" "}\n"); GenerateKotlinOrNull(printer); @@ -314,7 +314,7 @@ void ImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( void ImmutableMessageFieldLiteGenerator::GenerateKotlinOrNull(io::Printer* printer) const { if (descriptor_->has_optional_keyword()) { printer->Print(variables_, - "public val $classname$Kt.Dsl.$name$OrNull: $kt_type$?\n" + "val $classname$Kt.Dsl.$name$OrNull: $kt_type$?\n" " get() = $kt_dsl_builder$.$name$OrNull\n"); } } @@ -803,12 +803,12 @@ void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( " */\n" "@kotlin.OptIn" "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" - "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$kt_deprecation$ public val $kt_name$: " + "$kt_deprecation$ val $kt_name$: " "com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " @kotlin.jvm.JvmSynthetic\n" @@ -821,7 +821,7 @@ void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "add(value: $kt_type$) {\n" " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" @@ -833,7 +833,7 @@ void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslList" + "inline operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "plusAssign(value: $kt_type$) {\n" " add(value)\n" @@ -844,7 +844,7 @@ void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n" " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" @@ -857,7 +857,7 @@ void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslList" + "inline operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n" " addAll(values)\n" @@ -869,7 +869,7 @@ void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" - "public operator fun com.google.protobuf.kotlin.DslList" + "operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "set(index: kotlin.Int, value: $kt_type$) {\n" " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" @@ -880,7 +880,7 @@ void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "clear() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc index 8073bac09026..956a08b0ce7c 100644 --- a/src/google/protobuf/compiler/java/java_message_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_lite.cc @@ -731,10 +731,10 @@ void ImmutableMessageLiteGenerator::GenerateKotlinDsl( "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" "@com.google.protobuf.kotlin.ProtoDslMarker\n"); printer->Print( - "public class Dsl private constructor(\n" + "class Dsl private constructor(\n" " private val _builder: $message$.Builder\n" ") {\n" - " public companion object {\n" + " companion object {\n" " @kotlin.jvm.JvmSynthetic\n" " @kotlin.PublishedApi\n" " internal fun _create(builder: $message$.Builder): Dsl = " @@ -756,10 +756,10 @@ void ImmutableMessageLiteGenerator::GenerateKotlinDsl( for (auto oneof : oneofs_) { printer->Print( - "public val $oneof_name$Case: $message$.$oneof_capitalized_name$Case\n" + "val $oneof_name$Case: $message$.$oneof_capitalized_name$Case\n" " @JvmName(\"get$oneof_capitalized_name$Case\")\n" " get() = _builder.get$oneof_capitalized_name$Case()\n\n" - "public fun clear$oneof_capitalized_name$() {\n" + "fun clear$oneof_capitalized_name$() {\n" " _builder.clear$oneof_capitalized_name$()\n" "}\n", "oneof_name", context_->GetOneofGeneratorInfo(oneof)->name, @@ -780,7 +780,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinMembers( io::Printer* printer) const { printer->Print( "@kotlin.jvm.JvmName(\"-initialize$camelcase_name$\")\n" - "public inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> " + "inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> " "kotlin.Unit): " "$message$ =\n" " $message_kt$.Dsl._create($message$.newBuilder()).apply { block() " @@ -789,7 +789,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinMembers( "message_kt", name_resolver_->GetKotlinExtensionsClassName(descriptor_), "message", name_resolver_->GetClassName(descriptor_, true)); - printer->Print("public object $name$Kt {\n", "name", descriptor_->name()); + printer->Print("object $name$Kt {\n", "name", descriptor_->name()); printer->Indent(); GenerateKotlinDsl(printer); for (int i = 0; i < descriptor_->nested_type_count(); i++) { @@ -804,7 +804,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinMembers( void ImmutableMessageLiteGenerator::GenerateTopLevelKotlinMembers( io::Printer* printer) const { printer->Print( - "public inline fun $message$.copy(block: $message_kt$.Dsl.() -> " + "inline fun $message$.copy(block: $message_kt$.Dsl.() -> " "kotlin.Unit): " "$message$ =\n" " $message_kt$.Dsl._create(this.toBuilder()).apply { block() " @@ -846,7 +846,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinExtensions( printer->Print( "@Suppress(\"UNCHECKED_CAST\")\n" "@kotlin.jvm.JvmSynthetic\n" - "public operator fun get(extension: " + "operator fun get(extension: " "com.google.protobuf.ExtensionLite<$message$, T>): T {\n" " return if (extension.isRepeated) {\n" " get(extension as com.google.protobuf.ExtensionLite<$message$, " @@ -862,7 +862,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinExtensions( "@kotlin.OptIn" "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" "@kotlin.jvm.JvmName(\"-getRepeatedExtension\")\n" - "public operator fun get(\n" + "operator fun get(\n" " extension: com.google.protobuf.ExtensionLite<$message$, List>\n" "): com.google.protobuf.kotlin.ExtensionList {\n" " return com.google.protobuf.kotlin.ExtensionList(extension, " @@ -872,7 +872,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" - "public operator fun contains(extension: " + "operator fun contains(extension: " "com.google.protobuf.ExtensionLite<$message$, *>): " "Boolean {\n" " return _builder.hasExtension(extension)\n" @@ -881,7 +881,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" - "public fun clear(extension: " + "fun clear(extension: " "com.google.protobuf.ExtensionLite<$message$, *>) " "{\n" " _builder.clearExtension(extension)\n" @@ -901,7 +901,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun > set(\n" + "inline operator fun > set(\n" " extension: com.google.protobuf.ExtensionLite<$message$, T>,\n" " value: T\n" ") {\n" @@ -912,7 +912,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun set(\n" + "inline operator fun set(\n" " extension: com.google.protobuf.ExtensionLite<$message$, " "com.google.protobuf.ByteString>,\n" " value: com.google.protobuf.ByteString\n" @@ -924,7 +924,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun set(\n" + "inline operator fun set(\n" " extension: com.google.protobuf.ExtensionLite<$message$, T>,\n" " value: T\n" ") {\n" @@ -934,7 +934,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" - "public fun com.google.protobuf.kotlin.ExtensionList com.google.protobuf.kotlin.ExtensionList.add(value: E) {\n" " _builder.addExtension(this.extension, value)\n" "}\n\n", @@ -943,7 +943,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun " + "inline operator fun " "com.google.protobuf.kotlin.ExtensionList.plusAssign" "(value: E) {\n" @@ -953,7 +953,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" - "public fun com.google.protobuf.kotlin.ExtensionList com.google.protobuf.kotlin.ExtensionList.addAll(values: Iterable) {\n" " for (value in values) {\n" " add(value)\n" @@ -964,7 +964,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun " + "inline operator fun " "com.google.protobuf.kotlin.ExtensionList.plusAssign(values: " "Iterable) {\n" @@ -974,7 +974,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" - "public operator fun " + "operator fun " "com.google.protobuf.kotlin.ExtensionList.set(index: Int, value: " "E) {\n" @@ -985,7 +985,7 @@ void ImmutableMessageLiteGenerator::GenerateKotlinExtensions( printer->Print( "@kotlin.jvm.JvmSynthetic\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline fun com.google.protobuf.kotlin.ExtensionList<*, " + "inline fun com.google.protobuf.kotlin.ExtensionList<*, " "$message$>.clear() {\n" " clear(extension)\n" "}\n\n", diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc index 3a338eec5514..fe568b508f08 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field.cc @@ -331,7 +331,7 @@ void ImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, /* builder */ false); printer->Print(variables_, - "public fun ${$clear$kt_capitalized_name$$}$() {\n" + "fun ${$clear$kt_capitalized_name$$}$() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" "}\n"); @@ -339,7 +339,7 @@ void ImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); printer->Print( variables_, - "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" + "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" "}\n"); } @@ -849,12 +849,12 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( " */\n" "@kotlin.OptIn" "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" - "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$kt_deprecation$ public val $kt_name$: " + "$kt_deprecation$ val $kt_name$: " "com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " @kotlin.jvm.JvmSynthetic\n" @@ -867,7 +867,7 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "add(value: $kt_type$) {\n" " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" @@ -879,7 +879,7 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslList" + "inline operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "plusAssign(value: $kt_type$) {\n" " add(value)\n" @@ -890,7 +890,7 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n" " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" @@ -903,7 +903,7 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslList" + "inline operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n" " addAll(values)\n" @@ -915,7 +915,7 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" - "public operator fun com.google.protobuf.kotlin.DslList" + "operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "set(index: kotlin.Int, value: $kt_type$) {\n" " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" @@ -926,7 +926,7 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "clear() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc index 2da5f0d5ab14..8cfb22d0e422 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc @@ -336,7 +336,7 @@ void ImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, /* builder */ false); printer->Print(variables_, - "public fun ${$clear$kt_capitalized_name$$}$() {\n" + "fun ${$clear$kt_capitalized_name$$}$() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" "}\n"); @@ -344,7 +344,7 @@ void ImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); printer->Print( variables_, - "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" + "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" "}\n"); } @@ -671,12 +671,12 @@ void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( " */\n" "@kotlin.OptIn" "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" - "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$kt_deprecation$ public val $kt_name$: " + "$kt_deprecation$ val $kt_name$: " "com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " @kotlin.jvm.JvmSynthetic\n" @@ -689,7 +689,7 @@ void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "add(value: $kt_type$) {\n" " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" @@ -701,7 +701,7 @@ void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslList" + "inline operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "plusAssign(value: $kt_type$) {\n" " add(value)\n" @@ -712,7 +712,7 @@ void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n" " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" @@ -725,7 +725,7 @@ void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslList" + "inline operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n" " addAll(values)\n" @@ -737,7 +737,7 @@ void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" - "public operator fun com.google.protobuf.kotlin.DslList" + "operator fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "set(index: kotlin.Int, value: $kt_type$) {\n" " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" @@ -748,7 +748,7 @@ void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>." "clear() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc index 409d5280f2e1..824bfb044c19 100644 --- a/src/google/protobuf/compiler/java/java_string_field.cc +++ b/src/google/protobuf/compiler/java/java_string_field.cc @@ -390,7 +390,7 @@ void ImmutableStringFieldGenerator::GenerateKotlinDslMembers( WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, /* builder */ false); printer->Print(variables_, - "public fun ${$clear$kt_capitalized_name$$}$() {\n" + "fun ${$clear$kt_capitalized_name$$}$() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" "}\n"); @@ -398,7 +398,7 @@ void ImmutableStringFieldGenerator::GenerateKotlinDslMembers( WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); printer->Print( variables_, - "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" + "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" "}\n"); } @@ -963,13 +963,13 @@ void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers( " */\n" "@kotlin.OptIn" "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" - "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); // property for List WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); printer->Print(variables_, - "$kt_deprecation$public val $kt_name$: " + "$kt_deprecation$ val $kt_name$: " "com.google.protobuf.kotlin.DslList" "\n" " @kotlin.jvm.JvmSynthetic\n" @@ -983,7 +983,7 @@ void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "." "add(value: kotlin.String) {\n" " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" @@ -996,7 +996,7 @@ void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslList" + "inline operator fun com.google.protobuf.kotlin.DslList" "." "plusAssign(value: kotlin.String) {\n" " add(value)\n" @@ -1009,7 +1009,7 @@ void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers( variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "." "addAll(values: kotlin.collections.Iterable) {\n" " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" @@ -1023,7 +1023,7 @@ void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslList" + "inline operator fun com.google.protobuf.kotlin.DslList" "." "plusAssign(values: kotlin.collections.Iterable) {\n" " addAll(values)\n" @@ -1036,7 +1036,7 @@ void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers( variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" - "public operator fun com.google.protobuf.kotlin.DslList" + "operator fun com.google.protobuf.kotlin.DslList" "." "set(index: kotlin.Int, value: kotlin.String) {\n" " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" @@ -1047,7 +1047,7 @@ void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "." "clear() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc index d010634d8a6a..840fc249c05d 100644 --- a/src/google/protobuf/compiler/java/java_string_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc @@ -324,7 +324,7 @@ void ImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, /* builder */ false); printer->Print(variables_, - "public fun ${$clear$kt_capitalized_name$$}$() {\n" + "fun ${$clear$kt_capitalized_name$$}$() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" "}\n"); @@ -332,7 +332,7 @@ void ImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( WriteFieldAccessorDocComment(printer, descriptor_, HAZZER); printer->Print( variables_, - "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" + "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" "}\n"); } @@ -748,17 +748,17 @@ void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( " */\n" "@kotlin.OptIn" "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" - "public class ${$$kt_capitalized_name$Proxy$}$ private constructor()" + "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" " : com.google.protobuf.kotlin.DslProxy()\n"); // property for List WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); printer->Print( variables_, - "$kt_deprecation$public val $kt_name$: " + "$kt_deprecation$ val $kt_name$: " "com.google.protobuf.kotlin.DslList" "\n" - " @kotlin.OptIn" + "@kotlin.OptIn" "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" " get() = com.google.protobuf.kotlin.DslList(\n" " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n" @@ -770,7 +770,7 @@ void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "." "add(value: kotlin.String) {\n" " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" @@ -783,7 +783,7 @@ void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslList" + "inline operator fun com.google.protobuf.kotlin.DslList" "." "plusAssign(value: kotlin.String) {\n" " add(value)\n" @@ -796,7 +796,7 @@ void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "." "addAll(values: kotlin.collections.Iterable) {\n" " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" @@ -810,7 +810,7 @@ void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" "@Suppress(\"NOTHING_TO_INLINE\")\n" - "public inline operator fun com.google.protobuf.kotlin.DslList" + "inline operator fun com.google.protobuf.kotlin.DslList" "." "plusAssign(values: kotlin.collections.Iterable) {\n" " addAll(values)\n" @@ -823,7 +823,7 @@ void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" - "public operator fun com.google.protobuf.kotlin.DslList" + "operator fun com.google.protobuf.kotlin.DslList" "." "set(index: kotlin.Int, value: kotlin.String) {\n" " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" @@ -834,7 +834,7 @@ void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( printer->Print(variables_, "@kotlin.jvm.JvmSynthetic\n" "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" - "public fun com.google.protobuf.kotlin.DslList" + "fun com.google.protobuf.kotlin.DslList" "." "clear() {\n" " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" From 523d94a44505d744f294251f4fbec4065716e999 Mon Sep 17 00:00:00 2001 From: theodorerose Date: Fri, 18 Mar 2022 15:54:55 +0000 Subject: [PATCH 05/54] update PHP release to not fail on existing tag --- php/ext/google/protobuf/package.xml | 4 ++-- php/release.sh | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/php/ext/google/protobuf/package.xml b/php/ext/google/protobuf/package.xml index 9675d2be2344..a8648bfc5fc8 100644 --- a/php/ext/google/protobuf/package.xml +++ b/php/ext/google/protobuf/package.xml @@ -10,8 +10,8 @@ protobuf-opensource@google.com yes - 2022-03-15 - + 2022-03-18 + 3.20.0RC2 3.20.0 diff --git a/php/release.sh b/php/release.sh index 6b0baac78ff5..9a4b13912652 100755 --- a/php/release.sh +++ b/php/release.sh @@ -30,7 +30,11 @@ mv ../protobuf/composer.json composer.json sed -i 's|php/src|src|g' composer.json git add . git commit -m "$VERSION" -git tag "$VERSION" +if [ $(git tag -l "$VERSION") ]; then + echo "tag $VERSION already exists" +else + git tag "$VERSION" +fi popd # Clean up From dbb9619a9d9f232f1798f8f03b3323823457e47e Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Mon, 21 Mar 2022 15:26:27 -0700 Subject: [PATCH 06/54] Cherry-pick to get Ruby 3.1 support in protobuf 3.20.0 (#9657) * Allow pre-compiled binaries for ruby 3.1.0 (#9566) * Allow pre-compiled binaries for ruby 3.1.1 * add comment * fix build and use ruby 3.1.0 * add ruby31 to build CI for tests and release * trying to fix ci * install ruby 3.1.0 in ruby_build_environment.sh * use head for rvm to install 3.1.0 * just install master version of rvm in prepare_build_macos_rc * force install of master rvm in ruby_build_environment.sh * Use coroutine=universal when compiling ruby31 * use ucontext * fix filename * fix coroutine name * use git head for rake-compiler-dock * use newest rake-compiler-dock version * Updated CHANGES.txt for Ruby changes. * Fixed Ruby 3.1 tests by marking intersect? as unimplemented. (#9645) * Fixed Ruby 3.1 tests by marking intersect? as unimplemented. * Updated compatibility tests. Co-authored-by: Marco Concetto Rudilosso --- CHANGES.txt | 7 +++- kokoro/linux/dockerfile/test/ruby/Dockerfile | 1 + kokoro/linux/ruby31/build.sh | 18 +++++++++ kokoro/linux/ruby31/continuous.cfg | 11 +++++ kokoro/linux/ruby31/presubmit.cfg | 11 +++++ kokoro/macos/prepare_build_macos_rc | 2 +- kokoro/macos/ruby31/build.sh | 12 ++++++ kokoro/macos/ruby31/continuous.cfg | 5 +++ kokoro/macos/ruby31/presubmit.cfg | 5 +++ .../ruby/macos/ruby/ruby_build_environment.sh | 40 +++++++++++++++++++ ruby/Rakefile | 4 +- .../v3.0.0/tests/repeated_field_test.rb | 1 + ruby/google-protobuf.gemspec | 3 +- ruby/tests/repeated_field_test.rb | 1 + tests.sh | 5 +++ 15 files changed, 119 insertions(+), 7 deletions(-) create mode 100644 kokoro/linux/ruby31/build.sh create mode 100644 kokoro/linux/ruby31/continuous.cfg create mode 100644 kokoro/linux/ruby31/presubmit.cfg create mode 100644 kokoro/macos/ruby31/build.sh create mode 100644 kokoro/macos/ruby31/continuous.cfg create mode 100644 kokoro/macos/ruby31/presubmit.cfg diff --git a/CHANGES.txt b/CHANGES.txt index 1cba2b7688d8..349f81785046 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -2,8 +2,11 @@ Ruby * Dropped Ruby 2.3 and 2.4 support for CI and releases. (#9311) - * Message.decode/encode: Add max_recursion_depth option (#9218) - * Rename max_recursion_depth to recursion_limit (#9486) + * Added Ruby 3.1 support for CI and releases (#9566). + * Message.decode/encode: Add recursion_limit option (#9218/#9486) + * Allocate with xrealloc()/xfree() so message allocation is visible to the + Ruby GC. In certain tests this leads to much lower memory usage due to more + frequent GC runs (#9586). * Fix conversion of singleton classes in Ruby (#9342) * Suppress warning for intentional circular require (#9556) * JSON will now output shorter strings for double and float fields when possible diff --git a/kokoro/linux/dockerfile/test/ruby/Dockerfile b/kokoro/linux/dockerfile/test/ruby/Dockerfile index cfdc5ba03162..914cd4b4b907 100644 --- a/kokoro/linux/dockerfile/test/ruby/Dockerfile +++ b/kokoro/linux/dockerfile/test/ruby/Dockerfile @@ -35,6 +35,7 @@ RUN /bin/bash -l -c "rvm install 2.5.1" RUN /bin/bash -l -c "rvm install 2.6.0" RUN /bin/bash -l -c "rvm install 2.7.0" RUN /bin/bash -l -c "rvm install 3.0.0" +RUN /bin/bash -l -c "rvm install 3.1.0" RUN /bin/bash -l -c "rvm install jruby-9.2.20.1" RUN /bin/bash -l -c "rvm install jruby-9.3.3.0" diff --git a/kokoro/linux/ruby31/build.sh b/kokoro/linux/ruby31/build.sh new file mode 100644 index 000000000000..c22bdae2efd6 --- /dev/null +++ b/kokoro/linux/ruby31/build.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# +# This is the top-level script we give to Kokoro as the entry point for +# running the "pull request" project: +# +# This script selects a specific Dockerfile (for building a Docker image) and +# a script to run inside that image. Then we delegate to the general +# build_and_run_docker.sh script. + +# Change to repo root +cd $(dirname $0)/../../.. + +export DOCKERHUB_ORGANIZATION=protobuftesting +export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/ruby +export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh +export OUTPUT_DIR=testoutput +export TEST_SET="ruby31" +./kokoro/linux/build_and_run_docker.sh diff --git a/kokoro/linux/ruby31/continuous.cfg b/kokoro/linux/ruby31/continuous.cfg new file mode 100644 index 000000000000..0477912b8cac --- /dev/null +++ b/kokoro/linux/ruby31/continuous.cfg @@ -0,0 +1,11 @@ +# Config file for running tests in Kokoro + +# Location of the build script in repository +build_file: "protobuf/kokoro/linux/ruby31/build.sh" +timeout_mins: 120 + +action { + define_artifacts { + regex: "**/sponge_log.xml" + } +} diff --git a/kokoro/linux/ruby31/presubmit.cfg b/kokoro/linux/ruby31/presubmit.cfg new file mode 100644 index 000000000000..0477912b8cac --- /dev/null +++ b/kokoro/linux/ruby31/presubmit.cfg @@ -0,0 +1,11 @@ +# Config file for running tests in Kokoro + +# Location of the build script in repository +build_file: "protobuf/kokoro/linux/ruby31/build.sh" +timeout_mins: 120 + +action { + define_artifacts { + regex: "**/sponge_log.xml" + } +} diff --git a/kokoro/macos/prepare_build_macos_rc b/kokoro/macos/prepare_build_macos_rc index c0017b64ac82..8e0a87edbbf8 100755 --- a/kokoro/macos/prepare_build_macos_rc +++ b/kokoro/macos/prepare_build_macos_rc @@ -36,5 +36,5 @@ if [[ "${KOKORO_INSTALL_RVM:-}" == "yes" ]] ; then # Old OpenSSL versions cannot handle the SSL certificate used by # https://get.rvm.io, so as a workaround we download RVM directly from # GitHub. See this issue for details: https://github.com/rvm/rvm/issues/5133 - curl -sSL https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer | bash -s stable --ruby + curl -sSL https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer | bash -s master --ruby fi diff --git a/kokoro/macos/ruby31/build.sh b/kokoro/macos/ruby31/build.sh new file mode 100644 index 000000000000..1b5a5a5a60eb --- /dev/null +++ b/kokoro/macos/ruby31/build.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Build file to set up and run tests + +# Change to repo root +cd $(dirname $0)/../../.. + +# Prepare worker environment to run tests +KOKORO_INSTALL_RVM=yes +source kokoro/macos/prepare_build_macos_rc + +./tests.sh ruby31 diff --git a/kokoro/macos/ruby31/continuous.cfg b/kokoro/macos/ruby31/continuous.cfg new file mode 100644 index 000000000000..19e16b3eaf5c --- /dev/null +++ b/kokoro/macos/ruby31/continuous.cfg @@ -0,0 +1,5 @@ +# Config file for running tests in Kokoro + +# Location of the build script in repository +build_file: "protobuf/kokoro/macos/ruby31/build.sh" +timeout_mins: 1440 diff --git a/kokoro/macos/ruby31/presubmit.cfg b/kokoro/macos/ruby31/presubmit.cfg new file mode 100644 index 000000000000..19e16b3eaf5c --- /dev/null +++ b/kokoro/macos/ruby31/presubmit.cfg @@ -0,0 +1,5 @@ +# Config file for running tests in Kokoro + +# Location of the build script in repository +build_file: "protobuf/kokoro/macos/ruby31/build.sh" +timeout_mins: 1440 diff --git a/kokoro/release/ruby/macos/ruby/ruby_build_environment.sh b/kokoro/release/ruby/macos/ruby/ruby_build_environment.sh index 98270d138338..c3fcd3c584b1 100755 --- a/kokoro/release/ruby/macos/ruby/ruby_build_environment.sh +++ b/kokoro/release/ruby/macos/ruby/ruby_build_environment.sh @@ -3,12 +3,25 @@ set -ex set +ex # rvm script is very verbose and exits with errorcode + +curl -sSL https://rvm.io/mpapis.asc | gpg --import - +curl -sSL https://rvm.io/pkuczynski.asc | gpg --import - + +# Old OpenSSL versions cannot handle the SSL certificate used by +# https://get.rvm.io, so as a workaround we download RVM directly from +# GitHub. See this issue for details: https://github.com/rvm/rvm/issues/5133 +curl -sSL https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer | bash -s master --ruby + source $HOME/.rvm/scripts/rvm set -e # rvm commands are very verbose time rvm install 2.5.0 rvm use 2.5.0 gem install rake-compiler --no-document gem install bundler --no-document +time rvm install 3.1.0 +rvm use 3.1.0 +gem install rake-compiler --no-document +gem install bundler --no-document time rvm install 2.7.0 rvm use 2.7.0 --default gem install rake-compiler --no-document @@ -20,6 +33,8 @@ set -ex rm -rf ~/.rake-compiler CROSS_RUBY=$(mktemp tmpfile.XXXXXXXX) +CROSS_RUBY31=$(mktemp tmpfile.XXXXXXXX) + curl https://raw.githubusercontent.com/rake-compiler/rake-compiler/72184e51779b6a3b9b8580b036a052fdc3181ced/tasks/bin/cross-ruby.rake > "$CROSS_RUBY" @@ -52,8 +67,33 @@ patch "$CROSS_RUBY" << EOF end EOF +cp $CROSS_RUBY $CROSS_RUBY31 + +patch "$CROSS_RUBY31" << EOF +--- cross-ruby.rake 2022-03-04 11:49:52.000000000 +0000 ++++ patched 2022-03-04 11:58:22.000000000 +0000 +@@ -114,6 +114,7 @@ + '--enable-static', + '--disable-shared', + '--disable-install-doc', ++ '--with-coroutine=ucontext', + '--without-gmp', + '--with-ext=', + 'LDFLAGS=-pipe', +EOF + MAKE="make -j8" +set +x # rvm commands are very verbose +rvm use 3.1.0 +set -x +ruby --version | grep 'ruby 3.1.0' +for v in 3.1.0 ; do + ccache -c + rake -f "$CROSS_RUBY31" cross-ruby VERSION="$v" HOST=x86_64-darwin MAKE="$MAKE" + rake -f "$CROSS_RUBY31" cross-ruby VERSION="$v" HOST=aarch64-darwin MAKE="$MAKE" +done + set +x # rvm commands are very verbose rvm use 2.7.0 set -x diff --git a/ruby/Rakefile b/ruby/Rakefile index 6f71a2a7214c..1892e6209fe3 100644 --- a/ruby/Rakefile +++ b/ruby/Rakefile @@ -127,7 +127,7 @@ else ['x86-mingw32', 'x64-mingw32', 'x86_64-linux', 'x86-linux'].each do |plat| RakeCompilerDock.sh <<-"EOT", platform: plat bundle && \ - IN_DOCKER=true rake native:#{plat} pkg/#{spec.full_name}-#{plat}.gem RUBY_CC_VERSION=3.0.0:2.7.0:2.6.0:2.5.0 + IN_DOCKER=true rake native:#{plat} pkg/#{spec.full_name}-#{plat}.gem RUBY_CC_VERSION=3.1.0:3.0.0:2.7.0:2.6.0:2.5.0 EOT end end @@ -135,7 +135,7 @@ else if RUBY_PLATFORM =~ /darwin/ task 'gem:native' do system "rake genproto" - system "rake cross native gem RUBY_CC_VERSION=3.0.0:2.7.0:2.6.0:2.5.1" + system "rake cross native gem RUBY_CC_VERSION=3.1.0:3.0.0:2.7.0:2.6.0:2.5.1" end else task 'gem:native' => [:genproto, 'gem:windows', 'gem:java'] diff --git a/ruby/compatibility_tests/v3.0.0/tests/repeated_field_test.rb b/ruby/compatibility_tests/v3.0.0/tests/repeated_field_test.rb index 4f70f52dc4a9..caebde1db781 100755 --- a/ruby/compatibility_tests/v3.0.0/tests/repeated_field_test.rb +++ b/ruby/compatibility_tests/v3.0.0/tests/repeated_field_test.rb @@ -21,6 +21,7 @@ def test_acts_like_an_array :nitems, :iter_for_reverse_each, :indexes, :append, :prepend] arr_methods -= [:union, :difference, :filter!] arr_methods -= [:intersection, :deconstruct] # ruby 2.7 methods we can ignore + arr_methods -= [:intersect?] # ruby 3.1 methods we can ignore arr_methods.each do |method_name| assert m.repeated_string.respond_to?(method_name) == true, "does not respond to #{method_name}" end diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec index 4612ab74fba7..402a6a52f9b5 100644 --- a/ruby/google-protobuf.gemspec +++ b/ruby/google-protobuf.gemspec @@ -17,8 +17,7 @@ Gem::Specification.new do |s| else s.files += Dir.glob('ext/**/*') s.extensions= ["ext/google/protobuf_c/extconf.rb"] - s.add_development_dependency "rake-compiler-dock", "= 1.1.0" - end + s.add_development_dependency "rake-compiler-dock", "= 1.2.1" end s.test_files = ["tests/basic.rb", "tests/stress.rb", "tests/generated_code_test.rb"] diff --git a/ruby/tests/repeated_field_test.rb b/ruby/tests/repeated_field_test.rb index 1df6e1d4f154..7ffc0f180175 100755 --- a/ruby/tests/repeated_field_test.rb +++ b/ruby/tests/repeated_field_test.rb @@ -21,6 +21,7 @@ def test_acts_like_an_array :nitems, :iter_for_reverse_each, :indexes, :append, :prepend] arr_methods -= [:union, :difference, :filter!] arr_methods -= [:intersection, :deconstruct] # ruby 2.7 methods we can ignore + arr_methods -= [:intersect?] # ruby 3.1 methods we can ignore arr_methods.each do |method_name| assert m.repeated_string.respond_to?(method_name) == true, "does not respond to #{method_name}" end diff --git a/tests.sh b/tests.sh index ce66731e08e4..73460fda3da0 100755 --- a/tests.sh +++ b/tests.sh @@ -422,6 +422,10 @@ build_ruby30() { internal_build_cpp # For conformance tests. cd ruby && bash travis-test.sh ruby-3.0.2 && cd .. } +build_ruby31() { + internal_build_cpp # For conformance tests. + cd ruby && bash travis-test.sh ruby-3.1.0 && cd .. +} build_jruby92() { internal_build_cpp # For conformance tests. @@ -593,6 +597,7 @@ Usage: $0 { cpp | ruby26 | ruby27 | ruby30 | + ruby31 | jruby92 | jruby93 | ruby_all | From d06af454b532beda18cf70a6b60487d09b48cf80 Mon Sep 17 00:00:00 2001 From: "David L. Jones" Date: Wed, 23 Mar 2022 17:44:58 -0700 Subject: [PATCH 07/54] Regenerate BUILD file lists --- BUILD | 117 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 60 insertions(+), 57 deletions(-) diff --git a/BUILD b/BUILD index 887e5e3845f2..5de4aa3f2ffc 100644 --- a/BUILD +++ b/BUILD @@ -159,6 +159,7 @@ cc_library( "src/google/protobuf/any_lite.cc", "src/google/protobuf/arena.cc", "src/google/protobuf/arenastring.cc", + "src/google/protobuf/arenaz_sampler.cc", "src/google/protobuf/extension_set.cc", "src/google/protobuf/generated_enum_util.cc", "src/google/protobuf/generated_message_tctable_lite.cc", @@ -419,21 +420,21 @@ cc_library( # AUTOGEN(protoc_lib_srcs) "src/google/protobuf/compiler/code_generator.cc", "src/google/protobuf/compiler/command_line_interface.cc", - "src/google/protobuf/compiler/cpp/cpp_enum.cc", - "src/google/protobuf/compiler/cpp/cpp_enum_field.cc", - "src/google/protobuf/compiler/cpp/cpp_extension.cc", - "src/google/protobuf/compiler/cpp/cpp_field.cc", - "src/google/protobuf/compiler/cpp/cpp_file.cc", - "src/google/protobuf/compiler/cpp/cpp_generator.cc", - "src/google/protobuf/compiler/cpp/cpp_helpers.cc", - "src/google/protobuf/compiler/cpp/cpp_map_field.cc", - "src/google/protobuf/compiler/cpp/cpp_message.cc", - "src/google/protobuf/compiler/cpp/cpp_message_field.cc", - "src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc", - "src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc", - "src/google/protobuf/compiler/cpp/cpp_primitive_field.cc", - "src/google/protobuf/compiler/cpp/cpp_service.cc", - "src/google/protobuf/compiler/cpp/cpp_string_field.cc", + "src/google/protobuf/compiler/cpp/enum.cc", + "src/google/protobuf/compiler/cpp/enum_field.cc", + "src/google/protobuf/compiler/cpp/extension.cc", + "src/google/protobuf/compiler/cpp/field.cc", + "src/google/protobuf/compiler/cpp/file.cc", + "src/google/protobuf/compiler/cpp/generator.cc", + "src/google/protobuf/compiler/cpp/helpers.cc", + "src/google/protobuf/compiler/cpp/map_field.cc", + "src/google/protobuf/compiler/cpp/message.cc", + "src/google/protobuf/compiler/cpp/message_field.cc", + "src/google/protobuf/compiler/cpp/padding_optimizer.cc", + "src/google/protobuf/compiler/cpp/parse_function_generator.cc", + "src/google/protobuf/compiler/cpp/primitive_field.cc", + "src/google/protobuf/compiler/cpp/service.cc", + "src/google/protobuf/compiler/cpp/string_field.cc", "src/google/protobuf/compiler/csharp/csharp_doc_comment.cc", "src/google/protobuf/compiler/csharp/csharp_enum.cc", "src/google/protobuf/compiler/csharp/csharp_enum_field.cc", @@ -450,35 +451,35 @@ cc_library( "src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc", "src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc", "src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc", - "src/google/protobuf/compiler/java/java_context.cc", - "src/google/protobuf/compiler/java/java_doc_comment.cc", - "src/google/protobuf/compiler/java/java_enum.cc", - "src/google/protobuf/compiler/java/java_enum_field.cc", - "src/google/protobuf/compiler/java/java_enum_field_lite.cc", - "src/google/protobuf/compiler/java/java_enum_lite.cc", - "src/google/protobuf/compiler/java/java_extension.cc", - "src/google/protobuf/compiler/java/java_extension_lite.cc", - "src/google/protobuf/compiler/java/java_field.cc", - "src/google/protobuf/compiler/java/java_file.cc", - "src/google/protobuf/compiler/java/java_generator.cc", - "src/google/protobuf/compiler/java/java_generator_factory.cc", - "src/google/protobuf/compiler/java/java_helpers.cc", - "src/google/protobuf/compiler/java/java_kotlin_generator.cc", - "src/google/protobuf/compiler/java/java_map_field.cc", - "src/google/protobuf/compiler/java/java_map_field_lite.cc", - "src/google/protobuf/compiler/java/java_message.cc", - "src/google/protobuf/compiler/java/java_message_builder.cc", - "src/google/protobuf/compiler/java/java_message_builder_lite.cc", - "src/google/protobuf/compiler/java/java_message_field.cc", - "src/google/protobuf/compiler/java/java_message_field_lite.cc", - "src/google/protobuf/compiler/java/java_message_lite.cc", - "src/google/protobuf/compiler/java/java_name_resolver.cc", - "src/google/protobuf/compiler/java/java_primitive_field.cc", - "src/google/protobuf/compiler/java/java_primitive_field_lite.cc", - "src/google/protobuf/compiler/java/java_service.cc", - "src/google/protobuf/compiler/java/java_shared_code_generator.cc", - "src/google/protobuf/compiler/java/java_string_field.cc", - "src/google/protobuf/compiler/java/java_string_field_lite.cc", + "src/google/protobuf/compiler/java/context.cc", + "src/google/protobuf/compiler/java/doc_comment.cc", + "src/google/protobuf/compiler/java/enum.cc", + "src/google/protobuf/compiler/java/enum_field.cc", + "src/google/protobuf/compiler/java/enum_field_lite.cc", + "src/google/protobuf/compiler/java/enum_lite.cc", + "src/google/protobuf/compiler/java/extension.cc", + "src/google/protobuf/compiler/java/extension_lite.cc", + "src/google/protobuf/compiler/java/field.cc", + "src/google/protobuf/compiler/java/file.cc", + "src/google/protobuf/compiler/java/generator.cc", + "src/google/protobuf/compiler/java/generator_factory.cc", + "src/google/protobuf/compiler/java/helpers.cc", + "src/google/protobuf/compiler/java/kotlin_generator.cc", + "src/google/protobuf/compiler/java/map_field.cc", + "src/google/protobuf/compiler/java/map_field_lite.cc", + "src/google/protobuf/compiler/java/message.cc", + "src/google/protobuf/compiler/java/message_builder.cc", + "src/google/protobuf/compiler/java/message_builder_lite.cc", + "src/google/protobuf/compiler/java/message_field.cc", + "src/google/protobuf/compiler/java/message_field_lite.cc", + "src/google/protobuf/compiler/java/message_lite.cc", + "src/google/protobuf/compiler/java/name_resolver.cc", + "src/google/protobuf/compiler/java/primitive_field.cc", + "src/google/protobuf/compiler/java/primitive_field_lite.cc", + "src/google/protobuf/compiler/java/service.cc", + "src/google/protobuf/compiler/java/shared_code_generator.cc", + "src/google/protobuf/compiler/java/string_field.cc", + "src/google/protobuf/compiler/java/string_field_lite.cc", "src/google/protobuf/compiler/js/js_generator.cc", "src/google/protobuf/compiler/js/well_known_types_embed.cc", "src/google/protobuf/compiler/objectivec/objectivec_enum.cc", @@ -496,9 +497,9 @@ cc_library( "src/google/protobuf/compiler/php/php_generator.cc", "src/google/protobuf/compiler/plugin.cc", "src/google/protobuf/compiler/plugin.pb.cc", - "src/google/protobuf/compiler/python/python_generator.cc", - "src/google/protobuf/compiler/python/python_helpers.cc", - "src/google/protobuf/compiler/python/python_pyi_generator.cc", + "src/google/protobuf/compiler/python/generator.cc", + "src/google/protobuf/compiler/python/helpers.cc", + "src/google/protobuf/compiler/python/pyi_generator.cc", "src/google/protobuf/compiler/ruby/ruby_generator.cc", "src/google/protobuf/compiler/subprocess.cc", "src/google/protobuf/compiler/zip_writer.cc", @@ -605,8 +606,8 @@ LITE_TEST_PROTOS = ["src/" + s for s in RELATIVE_LITE_TEST_PROTOS] RELATIVE_TEST_PROTOS = [ # AUTOGEN(test_protos) "google/protobuf/any_test.proto", - "google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto", - "google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto", + "google/protobuf/compiler/cpp/test_bad_identifiers.proto", + "google/protobuf/compiler/cpp/test_large_enum_value.proto", "google/protobuf/map_proto2_unittest.proto", "google/protobuf/map_unittest.proto", "google/protobuf/unittest.proto", @@ -765,23 +766,24 @@ cc_test( "src/google/protobuf/any_test.cc", "src/google/protobuf/arena_unittest.cc", "src/google/protobuf/arenastring_unittest.cc", + "src/google/protobuf/arenaz_sampler_test.cc", "src/google/protobuf/compiler/annotation_test_util.cc", "src/google/protobuf/compiler/command_line_interface_unittest.cc", - "src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc", - "src/google/protobuf/compiler/cpp/cpp_move_unittest.cc", - "src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc", - "src/google/protobuf/compiler/cpp/cpp_unittest.cc", - "src/google/protobuf/compiler/cpp/cpp_unittest.inc", + "src/google/protobuf/compiler/cpp/bootstrap_unittest.cc", "src/google/protobuf/compiler/cpp/metadata_test.cc", + "src/google/protobuf/compiler/cpp/move_unittest.cc", + "src/google/protobuf/compiler/cpp/plugin_unittest.cc", + "src/google/protobuf/compiler/cpp/unittest.cc", + "src/google/protobuf/compiler/cpp/unittest.inc", "src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc", "src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc", "src/google/protobuf/compiler/importer_unittest.cc", - "src/google/protobuf/compiler/java/java_doc_comment_unittest.cc", - "src/google/protobuf/compiler/java/java_plugin_unittest.cc", + "src/google/protobuf/compiler/java/doc_comment_unittest.cc", + "src/google/protobuf/compiler/java/plugin_unittest.cc", "src/google/protobuf/compiler/mock_code_generator.cc", "src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc", "src/google/protobuf/compiler/parser_unittest.cc", - "src/google/protobuf/compiler/python/python_plugin_unittest.cc", + "src/google/protobuf/compiler/python/plugin_unittest.cc", "src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc", "src/google/protobuf/descriptor_database_unittest.cc", "src/google/protobuf/descriptor_unittest.cc", @@ -789,6 +791,7 @@ cc_test( "src/google/protobuf/dynamic_message_unittest.cc", "src/google/protobuf/extension_set_unittest.cc", "src/google/protobuf/generated_message_reflection_unittest.cc", + "src/google/protobuf/generated_message_tctable_lite_test.cc", "src/google/protobuf/inlined_string_field_unittest.cc", "src/google/protobuf/io/coded_stream_unittest.cc", "src/google/protobuf/io/io_win32_unittest.cc", From b012ef28b9dc6b789b6f451a68b0b3ac0dd823fe Mon Sep 17 00:00:00 2001 From: "David L. Jones" Date: Wed, 23 Mar 2022 18:10:27 -0700 Subject: [PATCH 08/54] Regenerate cmake file lists. --- cmake/extract_includes.bat.in | 255 +++++++++++++++++----------------- cmake/libprotobuf.cmake | 1 - cmake/libprotoc.cmake | 16 +-- cmake/tests.cmake | 5 +- 4 files changed, 133 insertions(+), 144 deletions(-) diff --git a/cmake/extract_includes.bat.in b/cmake/extract_includes.bat.in index 636c143fb6d2..41d4556f75be 100644 --- a/cmake/extract_includes.bat.in +++ b/cmake/extract_includes.bat.in @@ -13,131 +13,130 @@ mkdir include\google\protobuf\compiler\ruby mkdir include\google\protobuf\io mkdir include\google\protobuf\stubs mkdir include\google\protobuf\util -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\any.h" include\google\protobuf\any.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\any.pb.h" include\google\protobuf\any.pb.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\api.pb.h" include\google\protobuf\api.pb.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\arena.h" include\google\protobuf\arena.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\arena_impl.h" include\google\protobuf\arena_impl.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\arenastring.h" include\google\protobuf\arenastring.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\arenaz_sampler.h" include\google\protobuf\arenaz_sampler.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\code_generator.h" include\google\protobuf\compiler\code_generator.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\command_line_interface.h" include\google\protobuf\compiler\command_line_interface.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\cpp\file.h" include\google\protobuf\compiler\cpp\cpp_file.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\cpp\generator.h" include\google\protobuf\compiler\cpp\cpp_generator.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\cpp\helpers.h" include\google\protobuf\compiler\cpp\cpp_helpers.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\cpp\names.h" include\google\protobuf\compiler\cpp\cpp_names.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\csharp\csharp_doc_comment.h" include\google\protobuf\compiler\csharp\csharp_doc_comment.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\csharp\csharp_generator.h" include\google\protobuf\compiler\csharp\csharp_generator.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\csharp\csharp_names.h" include\google\protobuf\compiler\csharp\csharp_names.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\csharp\csharp_options.h" include\google\protobuf\compiler\csharp\csharp_options.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\importer.h" include\google\protobuf\compiler\importer.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\java\generator.h" include\google\protobuf\compiler\java\java_generator.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\java\kotlin_generator.h" include\google\protobuf\compiler\java\java_kotlin_generator.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\java\names.h" include\google\protobuf\compiler\java\java_names.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\js\js_generator.h" include\google\protobuf\compiler\js\js_generator.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\objectivec\objectivec_generator.h" include\google\protobuf\compiler\objectivec\objectivec_generator.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\objectivec\objectivec_helpers.h" include\google\protobuf\compiler\objectivec\objectivec_helpers.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\parser.h" include\google\protobuf\compiler\parser.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\php\php_generator.h" include\google\protobuf\compiler\php\php_generator.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\plugin.h" include\google\protobuf\compiler\plugin.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\plugin.pb.h" include\google\protobuf\compiler\plugin.pb.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\python\generator.h" include\google\protobuf\compiler\python\python_generator.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\python\pyi_generator.h" include\google\protobuf\compiler\python\python_pyi_generator.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\python\helpers.h" include\google\protobuf\compiler\python\python_helpers.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\ruby\ruby_generator.h" include\google\protobuf\compiler\ruby\ruby_generator.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\descriptor.h" include\google\protobuf\descriptor.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\descriptor.pb.h" include\google\protobuf\descriptor.pb.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\descriptor_database.h" include\google\protobuf\descriptor_database.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\duration.pb.h" include\google\protobuf\duration.pb.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\dynamic_message.h" include\google\protobuf\dynamic_message.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\empty.pb.h" include\google\protobuf\empty.pb.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\explicitly_constructed.h" include\google\protobuf\explicitly_constructed.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\extension_set.h" include\google\protobuf\extension_set.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\extension_set_inl.h" include\google\protobuf\extension_set_inl.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\field_access_listener.h" include\google\protobuf\field_access_listener.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\field_mask.pb.h" include\google\protobuf\field_mask.pb.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\generated_enum_reflection.h" include\google\protobuf\generated_enum_reflection.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\generated_enum_util.h" include\google\protobuf\generated_enum_util.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\generated_message_bases.h" include\google\protobuf\generated_message_bases.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\generated_message_reflection.h" include\google\protobuf\generated_message_reflection.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\generated_message_tctable_decl.h" include\google\protobuf\generated_message_tctable_decl.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\generated_message_tctable_impl.h" include\google\protobuf\generated_message_tctable_impl.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\generated_message_util.h" include\google\protobuf\generated_message_util.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\has_bits.h" include\google\protobuf\has_bits.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\implicit_weak_message.h" include\google\protobuf\implicit_weak_message.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\inlined_string_field.h" include\google\protobuf\inlined_string_field.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\io\coded_stream.h" include\google\protobuf\io\coded_stream.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\io\gzip_stream.h" include\google\protobuf\io\gzip_stream.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\io\io_win32.h" include\google\protobuf\io\io_win32.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\io\printer.h" include\google\protobuf\io\printer.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\io\strtod.h" include\google\protobuf\io\strtod.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\io\tokenizer.h" include\google\protobuf\io\tokenizer.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\io\zero_copy_stream.h" include\google\protobuf\io\zero_copy_stream.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\io\zero_copy_stream_impl.h" include\google\protobuf\io\zero_copy_stream_impl.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\io\zero_copy_stream_impl_lite.h" include\google\protobuf\io\zero_copy_stream_impl_lite.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\map.h" include\google\protobuf\map.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\map_entry.h" include\google\protobuf\map_entry.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\map_entry_lite.h" include\google\protobuf\map_entry_lite.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\map_field.h" include\google\protobuf\map_field.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\map_field_inl.h" include\google\protobuf\map_field_inl.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\map_field_lite.h" include\google\protobuf\map_field_lite.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\map_type_handler.h" include\google\protobuf\map_type_handler.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\message.h" include\google\protobuf\message.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\message_lite.h" include\google\protobuf\message_lite.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\metadata.h" include\google\protobuf\metadata.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\metadata_lite.h" include\google\protobuf\metadata_lite.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\parse_context.h" include\google\protobuf\parse_context.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\port.h" include\google\protobuf\port.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\port_def.inc" include\google\protobuf\port_def.inc -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\port_undef.inc" include\google\protobuf\port_undef.inc -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\reflection.h" include\google\protobuf\reflection.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\reflection_ops.h" include\google\protobuf\reflection_ops.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\repeated_field.h" include\google\protobuf\repeated_field.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\repeated_ptr_field.h" include\google\protobuf\repeated_ptr_field.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\service.h" include\google\protobuf\service.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\source_context.pb.h" include\google\protobuf\source_context.pb.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\struct.pb.h" include\google\protobuf\struct.pb.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\bytestream.h" include\google\protobuf\stubs\bytestream.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\callback.h" include\google\protobuf\stubs\callback.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\casts.h" include\google\protobuf\stubs\casts.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\common.h" include\google\protobuf\stubs\common.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\hash.h" include\google\protobuf\stubs\hash.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\logging.h" include\google\protobuf\stubs\logging.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\macros.h" include\google\protobuf\stubs\macros.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\map_util.h" include\google\protobuf\stubs\map_util.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\mutex.h" include\google\protobuf\stubs\mutex.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\once.h" include\google\protobuf\stubs\once.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\platform_macros.h" include\google\protobuf\stubs\platform_macros.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\port.h" include\google\protobuf\stubs\port.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\status.h" include\google\protobuf\stubs\status.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\stl_util.h" include\google\protobuf\stubs\stl_util.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\stringpiece.h" include\google\protobuf\stubs\stringpiece.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\strutil.h" include\google\protobuf\stubs\strutil.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\stubs\template_util.h" include\google\protobuf\stubs\template_util.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\text_format.h" include\google\protobuf\text_format.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\timestamp.pb.h" include\google\protobuf\timestamp.pb.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\type.pb.h" include\google\protobuf\type.pb.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\unknown_field_set.h" include\google\protobuf\unknown_field_set.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\util\delimited_message_util.h" include\google\protobuf\util\delimited_message_util.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\util\field_comparator.h" include\google\protobuf\util\field_comparator.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\util\field_mask_util.h" include\google\protobuf\util\field_mask_util.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\util\json_util.h" include\google\protobuf\util\json_util.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\util\message_differencer.h" include\google\protobuf\util\message_differencer.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\util\time_util.h" include\google\protobuf\util\time_util.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\util\type_resolver.h" include\google\protobuf\util\type_resolver.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\util\type_resolver_util.h" include\google\protobuf\util\type_resolver_util.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\wire_format.h" include\google\protobuf\wire_format.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\wire_format_lite.h" include\google\protobuf\wire_format_lite.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\wrappers.pb.h" include\google\protobuf\wrappers.pb.h -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\any.proto" include\google\protobuf\any.proto -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\api.proto" include\google\protobuf\api.proto -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\compiler\plugin.proto" include\google\protobuf\compiler\plugin.proto -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\descriptor.proto" include\google\protobuf\descriptor.proto -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\duration.proto" include\google\protobuf\duration.proto -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\empty.proto" include\google\protobuf\empty.proto -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\field_mask.proto" include\google\protobuf\field_mask.proto -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\source_context.proto" include\google\protobuf\source_context.proto -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\struct.proto" include\google\protobuf\struct.proto -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\timestamp.proto" include\google\protobuf\timestamp.proto -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\type.proto" include\google\protobuf\type.proto -copy "${PROTOBUF_SOURCE_WIN32_PATH}\src\google\protobuf\wrappers.proto" include\google\protobuf\wrappers.proto +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\any.h" include\google\protobuf\any.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\any.pb.h" include\google\protobuf\any.pb.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\api.pb.h" include\google\protobuf\api.pb.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\arena.h" include\google\protobuf\arena.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\arena_impl.h" include\google\protobuf\arena_impl.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\arenastring.h" include\google\protobuf\arenastring.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\arenaz_sampler.h" include\google\protobuf\arenaz_sampler.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\code_generator.h" include\google\protobuf\compiler\code_generator.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\command_line_interface.h" include\google\protobuf\compiler\command_line_interface.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\cpp\file.h" include\google\protobuf\compiler\cpp\file.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\cpp\generator.h" include\google\protobuf\compiler\cpp\generator.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\cpp\helpers.h" include\google\protobuf\compiler\cpp\helpers.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\cpp\names.h" include\google\protobuf\compiler\cpp\names.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_doc_comment.h" include\google\protobuf\compiler\csharp\csharp_doc_comment.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_generator.h" include\google\protobuf\compiler\csharp\csharp_generator.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_names.h" include\google\protobuf\compiler\csharp\csharp_names.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_options.h" include\google\protobuf\compiler\csharp\csharp_options.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\importer.h" include\google\protobuf\compiler\importer.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\generator.h" include\google\protobuf\compiler\java\generator.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\kotlin_generator.h" include\google\protobuf\compiler\java\kotlin_generator.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\names.h" include\google\protobuf\compiler\java\names.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\js\js_generator.h" include\google\protobuf\compiler\js\js_generator.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\objectivec\objectivec_generator.h" include\google\protobuf\compiler\objectivec\objectivec_generator.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\objectivec\objectivec_helpers.h" include\google\protobuf\compiler\objectivec\objectivec_helpers.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\parser.h" include\google\protobuf\compiler\parser.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\php\php_generator.h" include\google\protobuf\compiler\php\php_generator.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\plugin.h" include\google\protobuf\compiler\plugin.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\plugin.pb.h" include\google\protobuf\compiler\plugin.pb.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\python\generator.h" include\google\protobuf\compiler\python\generator.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\python\pyi_generator.h" include\google\protobuf\compiler\python\pyi_generator.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\ruby\ruby_generator.h" include\google\protobuf\compiler\ruby\ruby_generator.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\descriptor.h" include\google\protobuf\descriptor.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\descriptor.pb.h" include\google\protobuf\descriptor.pb.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\descriptor_database.h" include\google\protobuf\descriptor_database.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\duration.pb.h" include\google\protobuf\duration.pb.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\dynamic_message.h" include\google\protobuf\dynamic_message.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\empty.pb.h" include\google\protobuf\empty.pb.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\explicitly_constructed.h" include\google\protobuf\explicitly_constructed.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\extension_set.h" include\google\protobuf\extension_set.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\extension_set_inl.h" include\google\protobuf\extension_set_inl.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\field_access_listener.h" include\google\protobuf\field_access_listener.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\field_mask.pb.h" include\google\protobuf\field_mask.pb.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_enum_reflection.h" include\google\protobuf\generated_enum_reflection.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_enum_util.h" include\google\protobuf\generated_enum_util.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_bases.h" include\google\protobuf\generated_message_bases.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_reflection.h" include\google\protobuf\generated_message_reflection.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_tctable_decl.h" include\google\protobuf\generated_message_tctable_decl.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_tctable_impl.h" include\google\protobuf\generated_message_tctable_impl.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_util.h" include\google\protobuf\generated_message_util.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\has_bits.h" include\google\protobuf\has_bits.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\implicit_weak_message.h" include\google\protobuf\implicit_weak_message.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\inlined_string_field.h" include\google\protobuf\inlined_string_field.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\coded_stream.h" include\google\protobuf\io\coded_stream.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\gzip_stream.h" include\google\protobuf\io\gzip_stream.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\io_win32.h" include\google\protobuf\io\io_win32.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\printer.h" include\google\protobuf\io\printer.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\strtod.h" include\google\protobuf\io\strtod.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\tokenizer.h" include\google\protobuf\io\tokenizer.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\zero_copy_stream.h" include\google\protobuf\io\zero_copy_stream.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\zero_copy_stream_impl.h" include\google\protobuf\io\zero_copy_stream_impl.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\zero_copy_stream_impl_lite.h" include\google\protobuf\io\zero_copy_stream_impl_lite.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map.h" include\google\protobuf\map.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_entry.h" include\google\protobuf\map_entry.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_entry_lite.h" include\google\protobuf\map_entry_lite.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_field.h" include\google\protobuf\map_field.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_field_inl.h" include\google\protobuf\map_field_inl.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_field_lite.h" include\google\protobuf\map_field_lite.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\map_type_handler.h" include\google\protobuf\map_type_handler.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\message.h" include\google\protobuf\message.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\message_lite.h" include\google\protobuf\message_lite.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\metadata.h" include\google\protobuf\metadata.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\metadata_lite.h" include\google\protobuf\metadata_lite.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\parse_context.h" include\google\protobuf\parse_context.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\port.h" include\google\protobuf\port.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\port_def.inc" include\google\protobuf\port_def.inc +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\port_undef.inc" include\google\protobuf\port_undef.inc +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection.h" include\google\protobuf\reflection.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection_ops.h" include\google\protobuf\reflection_ops.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_field.h" include\google\protobuf\repeated_field.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_ptr_field.h" include\google\protobuf\repeated_ptr_field.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\service.h" include\google\protobuf\service.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\source_context.pb.h" include\google\protobuf\source_context.pb.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\struct.pb.h" include\google\protobuf\struct.pb.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\bytestream.h" include\google\protobuf\stubs\bytestream.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\callback.h" include\google\protobuf\stubs\callback.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\casts.h" include\google\protobuf\stubs\casts.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\common.h" include\google\protobuf\stubs\common.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\hash.h" include\google\protobuf\stubs\hash.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\logging.h" include\google\protobuf\stubs\logging.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\macros.h" include\google\protobuf\stubs\macros.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\map_util.h" include\google\protobuf\stubs\map_util.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\mutex.h" include\google\protobuf\stubs\mutex.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\once.h" include\google\protobuf\stubs\once.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\platform_macros.h" include\google\protobuf\stubs\platform_macros.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\port.h" include\google\protobuf\stubs\port.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\status.h" include\google\protobuf\stubs\status.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\stl_util.h" include\google\protobuf\stubs\stl_util.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\stringpiece.h" include\google\protobuf\stubs\stringpiece.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\strutil.h" include\google\protobuf\stubs\strutil.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\template_util.h" include\google\protobuf\stubs\template_util.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\text_format.h" include\google\protobuf\text_format.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\timestamp.pb.h" include\google\protobuf\timestamp.pb.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\type.pb.h" include\google\protobuf\type.pb.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\unknown_field_set.h" include\google\protobuf\unknown_field_set.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\delimited_message_util.h" include\google\protobuf\util\delimited_message_util.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\field_comparator.h" include\google\protobuf\util\field_comparator.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\field_mask_util.h" include\google\protobuf\util\field_mask_util.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\json_util.h" include\google\protobuf\util\json_util.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\message_differencer.h" include\google\protobuf\util\message_differencer.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\time_util.h" include\google\protobuf\util\time_util.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\type_resolver.h" include\google\protobuf\util\type_resolver.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\type_resolver_util.h" include\google\protobuf\util\type_resolver_util.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wire_format.h" include\google\protobuf\wire_format.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wire_format_lite.h" include\google\protobuf\wire_format_lite.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wrappers.pb.h" include\google\protobuf\wrappers.pb.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\any.proto" include\google\protobuf\any.proto +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\api.proto" include\google\protobuf\api.proto +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\plugin.proto" include\google\protobuf\compiler\plugin.proto +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\descriptor.proto" include\google\protobuf\descriptor.proto +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\duration.proto" include\google\protobuf\duration.proto +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\empty.proto" include\google\protobuf\empty.proto +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\field_mask.proto" include\google\protobuf\field_mask.proto +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\source_context.proto" include\google\protobuf\source_context.proto +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\struct.proto" include\google\protobuf\struct.proto +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\timestamp.proto" include\google\protobuf\timestamp.proto +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\type.proto" include\google\protobuf\type.proto +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wrappers.proto" include\google\protobuf\wrappers.proto diff --git a/cmake/libprotobuf.cmake b/cmake/libprotobuf.cmake index 5ce18768f29e..be5b22970034 100644 --- a/cmake/libprotobuf.cmake +++ b/cmake/libprotobuf.cmake @@ -20,7 +20,6 @@ set(libprotobuf_files ${protobuf_SOURCE_DIR}/src/google/protobuf/io/tokenizer.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/map_field.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/message.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_internal.h ${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_ops.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/service.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/source_context.pb.cc diff --git a/cmake/libprotoc.cmake b/cmake/libprotoc.cmake index 76ec605ea40c..607c2748e3b1 100644 --- a/cmake/libprotoc.cmake +++ b/cmake/libprotoc.cmake @@ -36,7 +36,6 @@ set(libprotoc_files ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/doc_comment.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/enum.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/enum_field.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/enum_field.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/enum_field_lite.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/enum_lite.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/extension.cc @@ -65,28 +64,17 @@ set(libprotoc_files ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/js/js_generator.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/js/well_known_types_embed.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_enum.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_enum.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_extension.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_extension.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_field.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_field.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_file.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_file.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_generator.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_map_field.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_message.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_message.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_message_field.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_oneof.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/php_generator.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.pb.cc @@ -96,7 +84,6 @@ set(libprotoc_files ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/ruby/ruby_generator.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/subprocess.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/zip_writer.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/zip_writer.h ) set(libprotoc_headers @@ -110,14 +97,17 @@ set(libprotoc_headers ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_generator.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_names.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_options.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/importer.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/generator.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/kotlin_generator.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/names.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/js/js_generator.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_generator.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_helpers.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/parser.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/php_generator.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.pb.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/generator.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/pyi_generator.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/ruby/ruby_generator.h diff --git a/cmake/tests.cmake b/cmake/tests.cmake index a24b153ce596..75ad3a62ce87 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -56,6 +56,7 @@ set(tests_protos google/protobuf/unittest_drop_unknown_fields.proto google/protobuf/unittest_embed_optimize_for.proto google/protobuf/unittest_empty.proto + google/protobuf/unittest_enormous_descriptor.proto google/protobuf/unittest_import.proto google/protobuf/unittest_import_public.proto google/protobuf/unittest_lazy_dependencies.proto @@ -128,10 +129,10 @@ set(common_lite_test_files set(common_test_files ${common_lite_test_files} - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/mock_code_generator.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/map_test_util.inc ${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_tester.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/test_util.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/test_util.inc ${protobuf_SOURCE_DIR}/src/google/protobuf/testing/file.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/testing/googletest.cc ) @@ -142,7 +143,6 @@ set(tests_files ${protobuf_SOURCE_DIR}/src/google/protobuf/arenastring_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arenaz_sampler_test.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/annotation_test_util.cc - ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/annotation_test_util.h ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/command_line_interface_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/bootstrap_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/metadata_test.cc @@ -155,6 +155,7 @@ set(tests_files ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/importer_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/doc_comment_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/plugin_unittest.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/mock_code_generator.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/parser_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/plugin_unittest.cc From 75418a54aefdc8da9f9c909e2a08b9816953ff30 Mon Sep 17 00:00:00 2001 From: "David L. Jones" Date: Wed, 23 Mar 2022 18:11:56 -0700 Subject: [PATCH 09/54] Update ignored file paths after renaming. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4fe3edde37aa..8afb522dae7d 100644 --- a/.gitignore +++ b/.gitignore @@ -46,7 +46,7 @@ src/.libs any_test.pb.* map*unittest.pb.* unittest*.pb.* -cpp_test*.pb.* +src/google/protobuf/compiler/cpp/test*.pb.* src/google/protobuf/util/**/*.pb.cc src/google/protobuf/util/**/*.pb.h From bc799d78f81115940eec953e2937245c70e3e6e4 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Thu, 24 Mar 2022 11:51:33 -0700 Subject: [PATCH 10/54] Added missing files and fixed file roles. (#9672) --- php/ext/google/protobuf/package.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/php/ext/google/protobuf/package.xml b/php/ext/google/protobuf/package.xml index a8648bfc5fc8..17d6b9f99834 100644 --- a/php/ext/google/protobuf/package.xml +++ b/php/ext/google/protobuf/package.xml @@ -46,10 +46,12 @@ - - - + + + + + From 10df21ed5e06df20385f1ee8ca01ecd22e0e4087 Mon Sep 17 00:00:00 2001 From: Jensaarai Date: Thu, 24 Mar 2022 22:45:59 -0700 Subject: [PATCH 11/54] Add .NET 6 target to Google.Protobuf test projects * .NET 5 reaches end-of-support in May, so update the Benchmarks project to `net6.0` * Update some NuGet packages to latest. --- .../Google.Protobuf.Benchmarks.csproj | 4 ++-- .../Google.Protobuf.Test.TestProtos.csproj | 2 +- .../Google.Protobuf.Test/Google.Protobuf.Test.csproj | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/csharp/src/Google.Protobuf.Benchmarks/Google.Protobuf.Benchmarks.csproj b/csharp/src/Google.Protobuf.Benchmarks/Google.Protobuf.Benchmarks.csproj index ac8e009adc3d..fee5f6525790 100644 --- a/csharp/src/Google.Protobuf.Benchmarks/Google.Protobuf.Benchmarks.csproj +++ b/csharp/src/Google.Protobuf.Benchmarks/Google.Protobuf.Benchmarks.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net6.0 ../../keys/Google.Protobuf.snk true False @@ -15,7 +15,7 @@ - + diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj b/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj index ad8445b7bfe9..fb26b7c01e36 100644 --- a/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj +++ b/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj @@ -15,7 +15,7 @@ - + diff --git a/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj index 641cb0a08886..a22ef944615c 100644 --- a/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj +++ b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj @@ -1,7 +1,7 @@  - net462;netcoreapp3.1;net60 + net462;netcoreapp3.1;net6.0 ../../keys/Google.Protobuf.snk true False @@ -14,14 +14,14 @@ - - - + + + - + From 25045e3f69933dfc5582487eae2500bc5dea1be6 Mon Sep 17 00:00:00 2001 From: Darly Paredes Date: Fri, 25 Mar 2022 19:20:51 +0000 Subject: [PATCH 12/54] Update protobuf version --- Protobuf-C++.podspec | 2 +- Protobuf.podspec | 2 +- configure.ac | 2 +- csharp/Google.Protobuf.Tools.nuspec | 2 +- .../Google.Protobuf/Google.Protobuf.csproj | 2 +- java/README.md | 6 ++--- java/bom/pom.xml | 2 +- java/core/pom.xml | 2 +- java/kotlin-lite/pom.xml | 2 +- java/kotlin/pom.xml | 2 +- java/lite.md | 2 +- java/lite/pom.xml | 2 +- java/pom.xml | 2 +- java/util/pom.xml | 2 +- js/package.json | 2 +- php/ext/google/protobuf/package.xml | 25 +++++++++++++++---- php/ext/google/protobuf/protobuf.h | 2 +- protobuf_version.bzl | 2 +- protoc-artifacts/pom.xml | 2 +- python/google/protobuf/__init__.py | 2 +- ruby/google-protobuf.gemspec | 2 +- ruby/pom.xml | 4 +-- src/google/protobuf/port_def.inc | 2 +- src/google/protobuf/stubs/common.h | 2 +- 24 files changed, 46 insertions(+), 31 deletions(-) diff --git a/Protobuf-C++.podspec b/Protobuf-C++.podspec index 9cf983dc00cc..afc0743af55c 100644 --- a/Protobuf-C++.podspec +++ b/Protobuf-C++.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Protobuf-C++' - s.version = '3.20.0-rc2' + s.version = '3.20.0' s.summary = 'Protocol Buffers v3 runtime library for C++.' s.homepage = 'https://github.com/google/protobuf' s.license = 'BSD-3-Clause' diff --git a/Protobuf.podspec b/Protobuf.podspec index ed9df24640f1..92c53c915932 100644 --- a/Protobuf.podspec +++ b/Protobuf.podspec @@ -5,7 +5,7 @@ # dependent projects use the :git notation to refer to the library. Pod::Spec.new do |s| s.name = 'Protobuf' - s.version = '3.20.0-rc2' + s.version = '3.20.0' s.summary = 'Protocol Buffers v.3 runtime library for Objective-C.' s.homepage = 'https://github.com/protocolbuffers/protobuf' s.license = 'BSD-3-Clause' diff --git a/configure.ac b/configure.ac index c5db5b005abf..4db50ce8afde 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ AC_PREREQ(2.59) # In the SVN trunk, the version should always be the next anticipated release # version with the "-pre" suffix. (We used to use "-SNAPSHOT" but this pushed # the size of one file name in the dist tarfile over the 99-char limit.) -AC_INIT([Protocol Buffers],[3.20.0-rc-2],[protobuf@googlegroups.com],[protobuf]) +AC_INIT([Protocol Buffers],[3.20.0],[protobuf@googlegroups.com],[protobuf]) AM_MAINTAINER_MODE([enable]) diff --git a/csharp/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec index 3a3785a4390e..21b6a624dd4f 100644 --- a/csharp/Google.Protobuf.Tools.nuspec +++ b/csharp/Google.Protobuf.Tools.nuspec @@ -5,7 +5,7 @@ Google Protocol Buffers tools Tools for Protocol Buffers - Google's data interchange format. See project site for more info. - 3.20.0-rc2 + 3.20.0 Google Inc. protobuf-packages https://github.com/protocolbuffers/protobuf/blob/master/LICENSE diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj index 9f8897a02c9c..22253cbc11c9 100644 --- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj +++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj @@ -4,7 +4,7 @@ C# runtime library for Protocol Buffers - Google's data interchange format. Copyright 2015, Google Inc. Google Protocol Buffers - 3.20.0-rc2 + 3.20.0 7.2 Google Inc. diff --git a/java/README.md b/java/README.md index 637235aaa432..df68050d108a 100644 --- a/java/README.md +++ b/java/README.md @@ -23,7 +23,7 @@ If you are using Maven, use the following: com.google.protobuf protobuf-java - 3.20.0-rc-2 + 3.20.0 ``` @@ -37,7 +37,7 @@ protobuf-java-util package: com.google.protobuf protobuf-java-util - 3.20.0-rc-2 + 3.20.0 ``` @@ -45,7 +45,7 @@ protobuf-java-util package: If you are using Gradle, add the following to your `build.gradle` file's dependencies: ``` - implementation 'com.google.protobuf:protobuf-java:3.20.0-rc-2' + implementation 'com.google.protobuf:protobuf-java:3.20.0' ``` Again, be sure to check that the version number matches (or is newer than) the version number of protoc that you are using. diff --git a/java/bom/pom.xml b/java/bom/pom.xml index 7af3c7b177ee..5ebf16a61bc8 100644 --- a/java/bom/pom.xml +++ b/java/bom/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-bom - 3.20.0-rc-2 + 3.20.0 pom Protocol Buffers [BOM] diff --git a/java/core/pom.xml b/java/core/pom.xml index 7ee824037de4..9dadd70833b5 100644 --- a/java/core/pom.xml +++ b/java/core/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0-rc-2 + 3.20.0 protobuf-java diff --git a/java/kotlin-lite/pom.xml b/java/kotlin-lite/pom.xml index 9f6d4aa8d353..11a01024ffc3 100644 --- a/java/kotlin-lite/pom.xml +++ b/java/kotlin-lite/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0-rc-2 + 3.20.0 protobuf-kotlin-lite diff --git a/java/kotlin/pom.xml b/java/kotlin/pom.xml index baa4fe43f083..fe9e0e52b5f1 100644 --- a/java/kotlin/pom.xml +++ b/java/kotlin/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0-rc-2 + 3.20.0 protobuf-kotlin diff --git a/java/lite.md b/java/lite.md index 0795540538cf..fc88a0415abf 100644 --- a/java/lite.md +++ b/java/lite.md @@ -30,7 +30,7 @@ protobuf Java runtime. If you are using Maven, use the following: com.google.protobuf protobuf-javalite - 3.20.0-rc-2 + 3.20.0 ``` diff --git a/java/lite/pom.xml b/java/lite/pom.xml index f04b77fbe66e..c2f7e376699e 100644 --- a/java/lite/pom.xml +++ b/java/lite/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0-rc-2 + 3.20.0 protobuf-javalite diff --git a/java/pom.xml b/java/pom.xml index 7b868fce0729..82f31fb35f9a 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0-rc-2 + 3.20.0 pom Protocol Buffers [Parent] diff --git a/java/util/pom.xml b/java/util/pom.xml index 51ad1a63e1c9..d9eadd6c29da 100644 --- a/java/util/pom.xml +++ b/java/util/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0-rc-2 + 3.20.0 protobuf-java-util diff --git a/js/package.json b/js/package.json index 8d347fa3dc38..e5c9a606c192 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "google-protobuf", - "version": "3.20.0-rc.2", + "version": "3.20.0", "description": "Protocol Buffers for JavaScript", "main": "google-protobuf.js", "files": [ diff --git a/php/ext/google/protobuf/package.xml b/php/ext/google/protobuf/package.xml index 17d6b9f99834..b529dc92f8e3 100644 --- a/php/ext/google/protobuf/package.xml +++ b/php/ext/google/protobuf/package.xml @@ -10,15 +10,15 @@ protobuf-opensource@google.com yes - 2022-03-18 - + 2022-03-25 + - 3.20.0RC2 + 3.20.0 3.20.0 - beta - beta + stable + stable BSD-3-Clause @@ -1238,5 +1238,20 @@ G A release. + + + 3.20.0 + 3.20.0 + + + stable + stable + + 2022-03-25 + + BSD-3-Clause + + + diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h index 46c560810a2c..d9d3d8e572ba 100644 --- a/php/ext/google/protobuf/protobuf.h +++ b/php/ext/google/protobuf/protobuf.h @@ -127,7 +127,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_setter, 0, 0, 1) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() -#define PHP_PROTOBUF_VERSION "3.20.0RC2" +#define PHP_PROTOBUF_VERSION "3.20.0" // ptr -> PHP object cache. This is a weak map that caches lazily-created // wrapper objects around upb types: diff --git a/protobuf_version.bzl b/protobuf_version.bzl index d6c42df98014..a62513fb3099 100644 --- a/protobuf_version.bzl +++ b/protobuf_version.bzl @@ -1 +1 @@ -PROTOBUF_VERSION = '3.20.0-rc-2' +PROTOBUF_VERSION = '3.20.0' diff --git a/protoc-artifacts/pom.xml b/protoc-artifacts/pom.xml index 7150c78c845c..a667c52dc84d 100644 --- a/protoc-artifacts/pom.xml +++ b/protoc-artifacts/pom.xml @@ -8,7 +8,7 @@ com.google.protobuf protoc - 3.20.0-rc-2 + 3.20.0 pom Protobuf Compiler diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py index cd0daeaeab5e..39555e643e2e 100644 --- a/python/google/protobuf/__init__.py +++ b/python/google/protobuf/__init__.py @@ -30,4 +30,4 @@ # Copyright 2007 Google Inc. All Rights Reserved. -__version__ = '3.20.0rc2' +__version__ = '3.20.0' diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec index 402a6a52f9b5..fa99970d025f 100644 --- a/ruby/google-protobuf.gemspec +++ b/ruby/google-protobuf.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "google-protobuf" - s.version = "3.20.0.rc.2" + s.version = "3.20.0" git_tag = "v#{s.version.to_s.sub('.rc.', '-rc')}" # Converts X.Y.Z.rc.N to vX.Y.Z-rcN, used for the git tag s.licenses = ["BSD-3-Clause"] s.summary = "Protocol Buffers" diff --git a/ruby/pom.xml b/ruby/pom.xml index 355019e0aa4d..5482c6fcfbb8 100644 --- a/ruby/pom.xml +++ b/ruby/pom.xml @@ -9,7 +9,7 @@ com.google.protobuf.jruby protobuf-jruby - 3.20.0-rc-2 + 3.20.0 Protocol Buffer JRuby native extension Protocol Buffers are a way of encoding structured data in an efficient yet @@ -76,7 +76,7 @@ com.google.protobuf protobuf-java-util - 3.20.0-rc-2 + 3.20.0 org.jruby diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc index bdb2eecbe2e4..5f0b63b470b3 100644 --- a/src/google/protobuf/port_def.inc +++ b/src/google/protobuf/port_def.inc @@ -172,7 +172,7 @@ #ifdef PROTOBUF_VERSION_SUFFIX #error PROTOBUF_VERSION_SUFFIX was previously defined #endif -#define PROTOBUF_VERSION_SUFFIX "-rc2" +#define PROTOBUF_VERSION_SUFFIX "" #if defined(PROTOBUF_NAMESPACE) || defined(PROTOBUF_NAMESPACE_ID) #error PROTOBUF_NAMESPACE or PROTOBUF_NAMESPACE_ID was previously defined diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index 32bd43616b0e..f88ab442fcad 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -85,7 +85,7 @@ namespace internal { #define GOOGLE_PROTOBUF_VERSION 3020000 // A suffix string for alpha, beta or rc releases. Empty for stable releases. -#define GOOGLE_PROTOBUF_VERSION_SUFFIX "-rc2" +#define GOOGLE_PROTOBUF_VERSION_SUFFIX "" // The minimum header version which works with the current version of // the library. This constant should only be used by protoc's C++ code From fb6016eaed1ec67d6dbb56a8a583ec62b807af15 Mon Sep 17 00:00:00 2001 From: Jensaarai Date: Thu, 24 Mar 2022 22:58:13 -0700 Subject: [PATCH 13/54] Add .editorconfig for csharp directory Nicer experience for e.g. VS Code --- csharp/.editorconfig | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 csharp/.editorconfig diff --git a/csharp/.editorconfig b/csharp/.editorconfig new file mode 100644 index 000000000000..a59f5a597255 --- /dev/null +++ b/csharp/.editorconfig @@ -0,0 +1,18 @@ +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +indent_style = space +tab_width = 4 + +# New line preferences +# See https://github.com/protocolbuffers/protobuf/issues/9526 +#end_of_line = lf +insert_final_newline = false +trim_trailing_whitespace = true \ No newline at end of file From b5a35bcc7e4cc4ff00eb105449b300fca3a8b0d2 Mon Sep 17 00:00:00 2001 From: Jensaarai Date: Fri, 25 Mar 2022 23:16:48 -0700 Subject: [PATCH 14/54] Add C# .editorconfig to Makefile.am --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index b72f54ff297d..7739acf1b9ae 100644 --- a/Makefile.am +++ b/Makefile.am @@ -50,6 +50,7 @@ pkgconfig_DATA = protobuf.pc protobuf-lite.pc csharp_EXTRA_DIST= \ global.json \ + csharp/.editorconfig \ csharp/.gitignore \ csharp/CHANGES.txt \ csharp/Google.Protobuf.Tools.targets \ From 8e7f93669612a06cafc39625f61258b9d6b77a3c Mon Sep 17 00:00:00 2001 From: Jason Lunn Date: Mon, 28 Mar 2022 18:43:53 -0400 Subject: [PATCH 15/54] Implement `respond_to?` in RubyMessage (#9677) All synthetic methods implemented by `method_missing` are now supported by `respond_to?`. Fixes issue #9202. * Fix null pointer exceptions exposed by new regression tests. * Fix clear_ on oneofs so that it is safe to call repeatedly and so that respond_to? does not depend on whether the oneof is currently cleared. * Code cleanup: reenable more tests on JRuby. * Align JRuby behavior with CRuby by throwing a RuntimeError when attempting to assign to a oneof. --- .../google/protobuf/jruby/RubyDescriptor.java | 2 + .../google/protobuf/jruby/RubyMessage.java | 99 ++++++++- ruby/tests/basic.rb | 65 ++++-- ruby/tests/basic_proto2.rb | 17 +- ruby/tests/common_tests.rb | 192 +++++++++++++++++- 5 files changed, 344 insertions(+), 31 deletions(-) diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java index a59596a5b6b4..bfe7ec325540 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java @@ -209,6 +209,8 @@ public IRubyObject allocate(Ruby runtime, RubyClass klazz) { klass.include(new IRubyObject[] {messageExts}); klass.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this); klass.defineAnnotatedMethods(RubyMessage.class); + // Workaround for https://github.com/jruby/jruby/issues/7154 + klass.searchMethod("respond_to?").setIsBuiltin(false); return klass; } diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java index 0d76116097af..2167f15dc473 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java @@ -260,6 +260,86 @@ public IRubyObject eq(ThreadContext context, IRubyObject other) { return runtime.getTrue(); } + /* + * call-seq: + * Message.respond_to?(method_name, search_private_and_protected) => boolean + * + * Parallels method_missing, returning true when this object implements a method with the given + * method_name. + */ + @JRubyMethod(name="respond_to?", required = 1, optional = 1) + public IRubyObject respondTo(ThreadContext context, IRubyObject [] args) { + String methodName = args[0].asJavaString(); + if (descriptor.findFieldByName(methodName) != null) { + return context.runtime.getTrue(); + } + RubyDescriptor rubyDescriptor = (RubyDescriptor) getDescriptor(context, metaClass); + IRubyObject oneofDescriptor = rubyDescriptor.lookupOneof(context, args[0]); + if (!oneofDescriptor.isNil()) { + return context.runtime.getTrue(); + } + if (methodName.startsWith(CLEAR_PREFIX)) { + String strippedMethodName = methodName.substring(6); + oneofDescriptor = rubyDescriptor.lookupOneof(context, context.runtime.newSymbol(strippedMethodName)); + if (!oneofDescriptor.isNil()) { + return context.runtime.getTrue(); + } + + if (descriptor.findFieldByName(strippedMethodName) != null) { + return context.runtime.getTrue(); + } + } + if (methodName.startsWith(HAS_PREFIX) && methodName.endsWith(QUESTION_MARK)) { + String strippedMethodName = methodName.substring(4, methodName.length() - 1); + FieldDescriptor fieldDescriptor = descriptor.findFieldByName(strippedMethodName); + if (fieldDescriptor != null && + (!proto3 || fieldDescriptor.getContainingOneof() == null || fieldDescriptor + .getContainingOneof().isSynthetic()) && + fieldDescriptor.hasPresence()) { + return context.runtime.getTrue(); + } + oneofDescriptor = rubyDescriptor.lookupOneof(context, RubyString.newString(context.runtime, strippedMethodName)); + if (!oneofDescriptor.isNil()) { + return context.runtime.getTrue(); + } + } + if (methodName.endsWith(AS_VALUE_SUFFIX)) { + FieldDescriptor fieldDescriptor = descriptor.findFieldByName( + methodName.substring(0, methodName.length() - 9)); + if (fieldDescriptor != null && isWrappable(fieldDescriptor)) { + return context.runtime.getTrue(); + } + } + if (methodName.endsWith(CONST_SUFFIX)) { + FieldDescriptor fieldDescriptor = descriptor.findFieldByName( + methodName.substring(0, methodName.length() - 6)); + if (fieldDescriptor != null) { + if (fieldDescriptor.getType() == FieldDescriptor.Type.ENUM) { + return context.runtime.getTrue(); + } + } + } + if (methodName.endsWith(Utils.EQUAL_SIGN)) { + String strippedMethodName = methodName.substring(0, methodName.length() - 1); + FieldDescriptor fieldDescriptor = descriptor.findFieldByName(strippedMethodName); + if (fieldDescriptor != null) { + return context.runtime.getTrue(); + } + if (strippedMethodName.endsWith(AS_VALUE_SUFFIX)) { + strippedMethodName = methodName.substring(0, strippedMethodName.length() - 9); + fieldDescriptor = descriptor.findFieldByName(strippedMethodName); + if (fieldDescriptor != null && isWrappable(fieldDescriptor)) { + return context.runtime.getTrue(); + } + } + } + boolean includePrivate = false; + if (args.length == 2) { + includePrivate = context.runtime.getTrue().equals(args[1]); + } + return metaClass.respondsToMethod(methodName, includePrivate) ? context.runtime.getTrue() : context.runtime.getFalse(); + } + /* * call-seq: * Message.method_missing(*args) @@ -291,10 +371,9 @@ public IRubyObject eq(ThreadContext context, IRubyObject other) { public IRubyObject methodMissing(ThreadContext context, IRubyObject[] args) { Ruby runtime = context.runtime; String methodName = args[0].asJavaString(); + RubyDescriptor rubyDescriptor = (RubyDescriptor) getDescriptor(context, metaClass); if (args.length == 1) { - RubyDescriptor rubyDescriptor = (RubyDescriptor) getDescriptor(context, metaClass); - // If we find a Oneof return it's name (use lookupOneof because it has an index) IRubyObject oneofDescriptor = rubyDescriptor.lookupOneof(context, args[0]); @@ -331,9 +410,12 @@ public IRubyObject methodMissing(ThreadContext context, IRubyObject[] args) { if (methodName.startsWith(CLEAR_PREFIX)) { methodName = methodName.substring(6); oneofDescriptor = rubyDescriptor.lookupOneof(context, runtime.newSymbol(methodName)); - if (!oneofDescriptor.isNil()) { fieldDescriptor = oneofCases.get(((RubyOneofDescriptor) oneofDescriptor).getDescriptor()); + if (fieldDescriptor == null) { + // Clearing an already cleared oneof; return here to avoid NoMethodError. + return context.nil; + } } if (fieldDescriptor == null) { @@ -379,8 +461,7 @@ public IRubyObject methodMissing(ThreadContext context, IRubyObject[] args) { } else if (methodName.endsWith(CONST_SUFFIX)) { methodName = methodName.substring(0, methodName.length() - 6); fieldDescriptor = descriptor.findFieldByName(methodName); - - if (fieldDescriptor.getType() == FieldDescriptor.Type.ENUM) { + if (fieldDescriptor != null && fieldDescriptor.getType() == FieldDescriptor.Type.ENUM) { IRubyObject enumValue = getFieldInternal(context, fieldDescriptor); if (!enumValue.isNil()) { @@ -404,17 +485,21 @@ public IRubyObject methodMissing(ThreadContext context, IRubyObject[] args) { methodName = methodName.substring(0, methodName.length() - 1); // Trim equals sign FieldDescriptor fieldDescriptor = descriptor.findFieldByName(methodName); - if (fieldDescriptor != null) { return setFieldInternal(context, fieldDescriptor, args[1]); } + IRubyObject oneofDescriptor = rubyDescriptor.lookupOneof(context, RubyString.newString(context.runtime, methodName)); + if (!oneofDescriptor.isNil()) { + throw runtime.newRuntimeError("Oneof accessors are read-only."); + } + if (methodName.endsWith(AS_VALUE_SUFFIX)) { methodName = methodName.substring(0, methodName.length() - 9); fieldDescriptor = descriptor.findFieldByName(methodName); - if (fieldDescriptor != null) { + if (fieldDescriptor != null && isWrappable(fieldDescriptor)) { if (args[1].isNil()) { return setFieldInternal(context, fieldDescriptor, args[1]); } diff --git a/ruby/tests/basic.rb b/ruby/tests/basic.rb index 4ff1c155834d..5b781b7a692a 100755 --- a/ruby/tests/basic.rb +++ b/ruby/tests/basic.rb @@ -66,8 +66,11 @@ def test_issue_8311_crash def test_issue_8559_crash msg = TestMessage.new msg.repeated_int32 = ::Google::Protobuf::RepeatedField.new(:int32, [1, 2, 3]) - # TODO: Remove the platform check once https://github.com/jruby/jruby/issues/6818 is released in JRuby 9.3.0.0 - GC.start(full_mark: true, immediate_sweep: true) unless RUBY_PLATFORM == "java" + + # https://github.com/jruby/jruby/issues/6818 was fixed in JRuby 9.3.0.0 + if cruby_or_jruby_9_3_or_higher? + GC.start(full_mark: true, immediate_sweep: true) + end TestMessage.encode(msg) end @@ -99,7 +102,7 @@ def test_issue_9507 begin encoded = msgclass.encode(m) - rescue java.lang.NullPointerException => e + rescue java.lang.NullPointerException flunk "NPE rescued" end decoded = msgclass.decode(encoded) @@ -173,7 +176,7 @@ def test_set_clear_defaults m = TestSingularFields.new m.singular_int32 = -42 - assert_equal -42, m.singular_int32 + assert_equal( -42, m.singular_int32 ) m.clear_singular_int32 assert_equal 0, m.singular_int32 @@ -568,8 +571,6 @@ def test_to_h def test_json_maps - # TODO: Fix JSON in JRuby version. - return if RUBY_PLATFORM == "java" m = MapMessage.new(:map_string_int32 => {"a" => 1}) expected = {mapStringInt32: {a: 1}, mapStringMsg: {}, mapStringEnum: {}} expected_preserve = {map_string_int32: {a: 1}, map_string_msg: {}, map_string_enum: {}} @@ -583,8 +584,6 @@ def test_json_maps end def test_json_maps_emit_defaults_submsg - # TODO: Fix JSON in JRuby version. - return if RUBY_PLATFORM == "java" m = MapMessage.new(:map_string_msg => {"a" => TestMessage2.new(foo: 0)}) expected = {mapStringInt32: {}, mapStringMsg: {a: {foo: 0}}, mapStringEnum: {}} @@ -594,8 +593,6 @@ def test_json_maps_emit_defaults_submsg end def test_json_emit_defaults_submsg - # TODO: Fix JSON in JRuby version. - return if RUBY_PLATFORM == "java" m = TestSingularFields.new(singular_msg: proto_module::TestMessage2.new) expected = { @@ -618,8 +615,6 @@ def test_json_emit_defaults_submsg end def test_respond_to - # This test fails with JRuby 1.7.23, likely because of an old JRuby bug. - return if RUBY_PLATFORM == "java" msg = MapMessage.new assert msg.respond_to?(:map_string_int32) assert !msg.respond_to?(:bacon) @@ -694,5 +689,51 @@ def test_utf8 m2 = proto_module::TestMessage.decode(proto_module::TestMessage.encode(m)) assert_equal m2, m end + + def test_map_fields_respond_to? # regression test for issue 9202 + msg = proto_module::MapMessage.new + assert msg.respond_to?(:map_string_int32=) + msg.map_string_int32 = Google::Protobuf::Map.new(:string, :int32) + assert msg.respond_to?(:map_string_int32) + assert_equal( Google::Protobuf::Map.new(:string, :int32), msg.map_string_int32 ) + assert msg.respond_to?(:clear_map_string_int32) + msg.clear_map_string_int32 + + assert !msg.respond_to?(:has_map_string_int32?) + assert_raise NoMethodError do + msg.has_map_string_int32? + end + assert !msg.respond_to?(:map_string_int32_as_value) + assert_raise NoMethodError do + msg.map_string_int32_as_value + end + assert !msg.respond_to?(:map_string_int32_as_value=) + assert_raise NoMethodError do + msg.map_string_int32_as_value = :boom + end + end + end + + def test_oneof_fields_respond_to? # regression test for issue 9202 + msg = proto_module::OneofMessage.new + # `has_` prefix + "?" suffix actions should only work for oneofs fields. + assert msg.has_my_oneof? + assert msg.respond_to? :has_my_oneof? + assert !msg.respond_to?( :has_a? ) + assert_raise NoMethodError do + msg.has_a? + end + assert !msg.respond_to?( :has_b? ) + assert_raise NoMethodError do + msg.has_b? + end + assert !msg.respond_to?( :has_c? ) + assert_raise NoMethodError do + msg.has_c? + end + assert !msg.respond_to?( :has_d? ) + assert_raise NoMethodError do + msg.has_d? + end end end diff --git a/ruby/tests/basic_proto2.rb b/ruby/tests/basic_proto2.rb index a7114ea6edf5..5391c302ee93 100755 --- a/ruby/tests/basic_proto2.rb +++ b/ruby/tests/basic_proto2.rb @@ -142,7 +142,7 @@ def test_set_clear_defaults m = TestMessageDefaults.new m.optional_int32 = -42 - assert_equal -42, m.optional_int32 + assert_equal( -42, m.optional_int32 ) assert m.has_optional_int32? m.clear_optional_int32 assert_equal 1, m.optional_int32 @@ -255,5 +255,20 @@ def test_file_descriptor assert_equal "tests/basic_test_proto2.proto", file_descriptor.name assert_equal :proto2, file_descriptor.syntax end + + def test_oneof_fields_respond_to? # regression test for issue 9202 + msg = proto_module::OneofMessage.new(a: "foo") + # `has_` prefix + "?" suffix actions should only work for oneofs fields. + assert msg.respond_to? :has_my_oneof? + assert msg.has_my_oneof? + assert msg.respond_to? :has_a? + assert msg.has_a? + assert msg.respond_to? :has_b? + assert !msg.has_b? + assert msg.respond_to? :has_c? + assert !msg.has_c? + assert msg.respond_to? :has_d? + assert !msg.has_d? + end end end diff --git a/ruby/tests/common_tests.rb b/ruby/tests/common_tests.rb index 358846916dba..5918c8a8b136 100644 --- a/ruby/tests/common_tests.rb +++ b/ruby/tests/common_tests.rb @@ -796,7 +796,7 @@ def test_repeated_push m.repeated_string += %w[two three] assert_equal %w[one two three], m.repeated_string - m.repeated_string.push *['four', 'five'] + m.repeated_string.push( *['four', 'five'] ) assert_equal %w[one two three four five], m.repeated_string m.repeated_string.push 'six', 'seven' @@ -1085,8 +1085,6 @@ def test_reflection end def test_json - # TODO: Fix JSON in JRuby version. - return if RUBY_PLATFORM == "java" m = proto_module::TestMessage.new(:optional_int32 => 1234, :optional_int64 => -0x1_0000_0000, :optional_uint32 => 0x8000_0000, @@ -1288,6 +1286,7 @@ def test_wrappers_set_to_default m2 = proto_module::Wrapper.decode(m.to_proto) run_asserts.call(m2) m3 = proto_module::Wrapper.decode_json(m.to_json) + run_asserts.call(m3) end def test_wrapper_getters @@ -1539,8 +1538,6 @@ def test_wrapper_setters_as_value assert_nil m.bytes_as_value } - m = proto_module::Wrapper.new - m2 = proto_module::Wrapper.new( double: Google::Protobuf::DoubleValue.new(value: 2.0), float: Google::Protobuf::FloatValue.new(value: 4.0), @@ -1787,27 +1784,200 @@ def test_eq assert_nil h[m2] end + def cruby_or_jruby_9_3_or_higher? + # https://github.com/jruby/jruby/issues/6818 was fixed in JRuby 9.3.0.0 + match = RUBY_PLATFORM == "java" && + JRUBY_VERSION.match(/^(\d+)\.(\d+)\.\d+\.\d+$/) + match && (match[1].to_i > 9 || (match[1].to_i == 9 && match[2].to_i >= 3)) + end + def test_object_gc m = proto_module::TestMessage.new(optional_msg: proto_module::TestMessage2.new) m.optional_msg - # TODO: Remove the platform check once https://github.com/jruby/jruby/issues/6818 is released in JRuby 9.3.0.0 - GC.start(full_mark: true, immediate_sweep: true) unless RUBY_PLATFORM == "java" + # https://github.com/jruby/jruby/issues/6818 was fixed in JRuby 9.3.0.0 + GC.start(full_mark: true, immediate_sweep: true) if cruby_or_jruby_9_3_or_higher? m.optional_msg.inspect end def test_object_gc_freeze m = proto_module::TestMessage.new m.repeated_float.freeze - # TODO: Remove the platform check once https://github.com/jruby/jruby/issues/6818 is released in JRuby 9.3.0.0 - GC.start(full_mark: true) unless RUBY_PLATFORM == "java" + # https://github.com/jruby/jruby/issues/6818 was fixed in JRuby 9.3.0.0 + GC.start(full_mark: true) if cruby_or_jruby_9_3_or_higher? # Make sure we remember that the object is frozen. # The wrapper object contains this information, so we need to ensure that # the previous GC did not collect it. assert m.repeated_float.frozen? - # TODO: Remove the platform check once https://github.com/jruby/jruby/issues/6818 is released in JRuby 9.3.0.0 - GC.start(full_mark: true, immediate_sweep: true) unless RUBY_PLATFORM == "java" + # https://github.com/jruby/jruby/issues/6818 was fixed in JRuby 9.3.0.0 + GC.start(full_mark: true, immediate_sweep: true) if cruby_or_jruby_9_3_or_higher? assert m.repeated_float.frozen? end + + def test_optional_fields_respond_to? # regression test for issue 9202 + msg = proto_module::TestMessage.new + assert msg.respond_to? :optional_int32= + msg.optional_int32 = 42 + + assert msg.respond_to? :optional_int32 + assert_equal 42, msg.optional_int32 + + assert msg.respond_to? :clear_optional_int32 + msg.clear_optional_int32 + assert_equal 0, msg.optional_int32 + + assert msg.respond_to? :has_optional_int32? + assert !msg.has_optional_int32? + + assert !msg.respond_to?( :optional_int32_as_value= ) + assert_raise NoMethodError do + msg.optional_int32_as_value = 42 + end + + assert !msg.respond_to?( :optional_int32_as_value ) + assert_raise NoMethodError do + msg.optional_int32_as_value + end + + assert msg.respond_to? :optional_enum_const + assert_equal 0, msg.optional_enum_const + + assert !msg.respond_to?( :foo ) + assert_raise NoMethodError do + msg.foo + end + + assert !msg.respond_to?( :foo_const ) + assert_raise NoMethodError do + msg.foo_const + end + + assert !msg.respond_to?( :optional_int32_const ) + assert_raise NoMethodError do + msg.optional_int32_const + end + end + + def test_oneof_fields_respond_to? # regression test for issue 9202 + msg = proto_module::OneofMessage.new + + # names of the elements of a oneof and the oneof itself are valid actions. + assert msg.respond_to? :my_oneof + assert_nil msg.my_oneof + assert msg.respond_to? :a + assert_equal "", msg.a + assert msg.respond_to? :b + assert_equal 0, msg.b + assert msg.respond_to? :c + assert_nil msg.c + assert msg.respond_to? :d + assert_equal :Default, msg.d + + # `clear` prefix actions work on elements of a oneof and the oneof itself. + assert msg.respond_to? :clear_my_oneof + msg.clear_my_oneof + # Repeatedly clearing a oneof used to cause a NoMethodError under JRuby + msg.clear_my_oneof + assert msg.respond_to? :clear_a + msg.clear_a + assert msg.respond_to? :clear_b + msg.clear_b + assert msg.respond_to? :clear_c + msg.clear_c + assert msg.respond_to? :clear_d + msg.clear_d + + # `=` suffix actions should work on elements of a oneof but not the oneof itself. + assert !msg.respond_to?( :my_oneof= ) + error = assert_raise RuntimeError do + msg.my_oneof = nil + end + assert_equal "Oneof accessors are read-only.", error.message + assert msg.respond_to? :a= + msg.a = "foo" + assert msg.respond_to? :b= + msg.b = 42 + assert msg.respond_to? :c= + msg.c = proto_module::TestMessage2.new + assert msg.respond_to? :d= + msg.d = :Default + + # `has_` prefix + "?" suffix actions work for oneofs fields. + assert msg.respond_to? :has_my_oneof? + assert msg.has_my_oneof? + + # `_as_value` suffix actions should only work for wrapped fields. + assert !msg.respond_to?( :my_oneof_as_value ) + assert_raise NoMethodError do + msg.my_oneof_as_value + end + assert !msg.respond_to?( :a_as_value ) + assert_raise NoMethodError do + msg.a_as_value + end + assert !msg.respond_to?( :b_as_value ) + assert_raise NoMethodError do + msg.b_as_value + end + assert !msg.respond_to?( :c_as_value ) + assert_raise NoMethodError do + msg.c_as_value + end + assert !msg.respond_to?( :d_as_value ) + assert_raise NoMethodError do + msg.d_as_value + end + + # `_as_value=` suffix actions should only work for wrapped fields. + assert !msg.respond_to?( :my_oneof_as_value= ) + assert_raise NoMethodError do + msg.my_oneof_as_value = :boom + end + assert !msg.respond_to?( :a_as_value= ) + assert_raise NoMethodError do + msg.a_as_value = "" + end + assert !msg.respond_to?( :b_as_value= ) + assert_raise NoMethodError do + msg.b_as_value = 42 + end + assert !msg.respond_to?( :c_as_value= ) + assert_raise NoMethodError do + msg.c_as_value = proto_module::TestMessage2.new + end + assert !msg.respond_to?( :d_as_value= ) + assert_raise NoMethodError do + msg.d_as_value = :Default + end + + # `_const` suffix actions should only work for enum fields. + assert !msg.respond_to?( :my_oneof_const ) + assert_raise NoMethodError do + msg.my_oneof_const + end + assert !msg.respond_to?( :a_const ) + assert_raise NoMethodError do + msg.a_const + end + assert !msg.respond_to?( :b_const ) + assert_raise NoMethodError do + msg.b_const + end + assert !msg.respond_to?( :c_const ) + assert_raise NoMethodError do + msg.c_const + end + assert msg.respond_to? :d_const + assert_equal 0, msg.d_const + end + + def test_wrapped_fields_respond_to? # regression test for issue 9202 + msg = proto_module::Wrapper.new + assert msg.respond_to?( :double_as_value= ) + msg.double_as_value = 42 + assert msg.respond_to?( :double_as_value ) + assert_equal 42, msg.double_as_value + assert_equal Google::Protobuf::DoubleValue.new(value: 42), msg.double + end end From 5b28ae70c0a231359008c1c228bc872e99610ccd Mon Sep 17 00:00:00 2001 From: Jason Lunn Date: Mon, 28 Mar 2022 18:58:54 -0400 Subject: [PATCH 16/54] Run all JRuby source files through `google-java-format.` --- .../google/protobuf/jruby/RubyDescriptor.java | 334 +-- .../protobuf/jruby/RubyDescriptorPool.java | 263 +- .../com/google/protobuf/jruby/RubyEnum.java | 70 +- .../protobuf/jruby/RubyEnumDescriptor.java | 259 +- .../protobuf/jruby/RubyFieldDescriptor.java | 411 +-- .../protobuf/jruby/RubyFileDescriptor.java | 105 +- .../com/google/protobuf/jruby/RubyMap.java | 805 +++--- .../google/protobuf/jruby/RubyMessage.java | 2434 +++++++++-------- .../protobuf/jruby/RubyOneofDescriptor.java | 118 +- .../google/protobuf/jruby/RubyProtobuf.java | 69 +- .../protobuf/jruby/RubyRepeatedField.java | 717 ++--- .../protobuf/jruby/SentinelOuterClass.java | 467 ++-- .../java/com/google/protobuf/jruby/Utils.java | 604 ++-- .../main/java/google/ProtobufJavaService.java | 41 +- 14 files changed, 3433 insertions(+), 3264 deletions(-) diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java index bfe7ec325540..b80925331525 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptor.java @@ -35,6 +35,8 @@ import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Descriptors.OneofDescriptor; +import java.util.HashMap; +import java.util.Map; import org.jruby.*; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; @@ -44,182 +46,186 @@ import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; -import java.util.HashMap; -import java.util.Map; - - @JRubyClass(name = "Descriptor", include = "Enumerable") public class RubyDescriptor extends RubyObject { - public static void createRubyDescriptor(Ruby runtime) { - RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); - RubyClass cDescriptor = protobuf.defineClassUnder("Descriptor", runtime.getObject(), new ObjectAllocator() { - @Override - public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + public static void createRubyDescriptor(Ruby runtime) { + RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); + RubyClass cDescriptor = + protobuf.defineClassUnder( + "Descriptor", + runtime.getObject(), + new ObjectAllocator() { + @Override + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new RubyDescriptor(runtime, klazz); - } - }); - cDescriptor.includeModule(runtime.getEnumerable()); - cDescriptor.defineAnnotatedMethods(RubyDescriptor.class); - cFieldDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::FieldDescriptor"); - cOneofDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::OneofDescriptor"); + } + }); + cDescriptor.includeModule(runtime.getEnumerable()); + cDescriptor.defineAnnotatedMethods(RubyDescriptor.class); + cFieldDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::FieldDescriptor"); + cOneofDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::OneofDescriptor"); + } + + public RubyDescriptor(Ruby runtime, RubyClass klazz) { + super(runtime, klazz); + } + + /* + * call-seq: + * Descriptor.name => name + * + * Returns the name of this message type as a fully-qualified string (e.g., + * My.Package.MessageType). + */ + @JRubyMethod(name = "name") + public IRubyObject getName(ThreadContext context) { + return name; + } + + /* + * call-seq: + * Descriptor.lookup(name) => FieldDescriptor + * + * Returns the field descriptor for the field with the given name, if present, + * or nil if none. + */ + @JRubyMethod + public IRubyObject lookup(ThreadContext context, IRubyObject fieldName) { + return Helpers.nullToNil(fieldDescriptors.get(fieldName), context.nil); + } + + /* + * call-seq: + * Descriptor.msgclass => message_klass + * + * Returns the Ruby class created for this message type. Valid only once the + * message type has been added to a pool. + */ + @JRubyMethod + public IRubyObject msgclass(ThreadContext context) { + return klazz; + } + + /* + * call-seq: + * Descriptor.each(&block) + * + * Iterates over fields in this message type, yielding to the block on each one. + */ + @JRubyMethod + public IRubyObject each(ThreadContext context, Block block) { + for (Map.Entry entry : fieldDescriptors.entrySet()) { + block.yield(context, entry.getValue()); } - - public RubyDescriptor(Ruby runtime, RubyClass klazz) { - super(runtime, klazz); + return context.nil; + } + + /* + * call-seq: + * Descriptor.file_descriptor + * + * Returns the FileDescriptor object this message belongs to. + */ + @JRubyMethod(name = "file_descriptor") + public IRubyObject getFileDescriptor(ThreadContext context) { + return RubyFileDescriptor.getRubyFileDescriptor(context, descriptor); + } + + /* + * call-seq: + * Descriptor.each_oneof(&block) => nil + * + * Invokes the given block for each oneof in this message type, passing the + * corresponding OneofDescriptor. + */ + @JRubyMethod(name = "each_oneof") + public IRubyObject eachOneof(ThreadContext context, Block block) { + for (RubyOneofDescriptor oneofDescriptor : oneofDescriptors.values()) { + block.yieldSpecific(context, oneofDescriptor); } - - /* - * call-seq: - * Descriptor.name => name - * - * Returns the name of this message type as a fully-qualified string (e.g., - * My.Package.MessageType). - */ - @JRubyMethod(name = "name") - public IRubyObject getName(ThreadContext context) { - return name; + return context.nil; + } + + /* + * call-seq: + * Descriptor.lookup_oneof(name) => OneofDescriptor + * + * Returns the oneof descriptor for the oneof with the given name, if present, + * or nil if none. + */ + @JRubyMethod(name = "lookup_oneof") + public IRubyObject lookupOneof(ThreadContext context, IRubyObject name) { + return Helpers.nullToNil(oneofDescriptors.get(Utils.symToString(name)), context.nil); + } + + protected FieldDescriptor getField(String name) { + return descriptor.findFieldByName(name); + } + + protected void setDescriptor( + ThreadContext context, Descriptor descriptor, RubyDescriptorPool pool) { + Ruby runtime = context.runtime; + Map cache = new HashMap(); + this.descriptor = descriptor; + + // Populate the field caches + fieldDescriptors = new HashMap(); + oneofDescriptors = new HashMap(); + + for (FieldDescriptor fieldDescriptor : descriptor.getFields()) { + RubyFieldDescriptor fd = + (RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK); + fd.setDescriptor(context, fieldDescriptor, pool); + fieldDescriptors.put(runtime.newString(fieldDescriptor.getName()), fd); + cache.put(fieldDescriptor, fd); } - /* - * call-seq: - * Descriptor.lookup(name) => FieldDescriptor - * - * Returns the field descriptor for the field with the given name, if present, - * or nil if none. - */ - @JRubyMethod - public IRubyObject lookup(ThreadContext context, IRubyObject fieldName) { - return Helpers.nullToNil(fieldDescriptors.get(fieldName), context.nil); + for (OneofDescriptor oneofDescriptor : descriptor.getRealOneofs()) { + RubyOneofDescriptor ood = + (RubyOneofDescriptor) cOneofDescriptor.newInstance(context, Block.NULL_BLOCK); + ood.setDescriptor(context, oneofDescriptor, cache); + oneofDescriptors.put(runtime.newString(oneofDescriptor.getName()), ood); } - /* - * call-seq: - * Descriptor.msgclass => message_klass - * - * Returns the Ruby class created for this message type. Valid only once the - * message type has been added to a pool. - */ - @JRubyMethod - public IRubyObject msgclass(ThreadContext context) { - return klazz; - } + // Make sure our class is built + this.klazz = buildClassFromDescriptor(context); + } - /* - * call-seq: - * Descriptor.each(&block) - * - * Iterates over fields in this message type, yielding to the block on each one. - */ - @JRubyMethod - public IRubyObject each(ThreadContext context, Block block) { - for (Map.Entry entry : fieldDescriptors.entrySet()) { - block.yield(context, entry.getValue()); - } - return context.nil; - } + protected void setName(IRubyObject name) { + this.name = name; + } - /* - * call-seq: - * Descriptor.file_descriptor - * - * Returns the FileDescriptor object this message belongs to. - */ - @JRubyMethod(name = "file_descriptor") - public IRubyObject getFileDescriptor(ThreadContext context) { - return RubyFileDescriptor.getRubyFileDescriptor(context, descriptor); - } - - /* - * call-seq: - * Descriptor.each_oneof(&block) => nil - * - * Invokes the given block for each oneof in this message type, passing the - * corresponding OneofDescriptor. - */ - @JRubyMethod(name = "each_oneof") - public IRubyObject eachOneof(ThreadContext context, Block block) { - for (RubyOneofDescriptor oneofDescriptor : oneofDescriptors.values()) { - block.yieldSpecific(context, oneofDescriptor); - } - return context.nil; - } + private RubyClass buildClassFromDescriptor(ThreadContext context) { + Ruby runtime = context.runtime; - /* - * call-seq: - * Descriptor.lookup_oneof(name) => OneofDescriptor - * - * Returns the oneof descriptor for the oneof with the given name, if present, - * or nil if none. - */ - @JRubyMethod(name = "lookup_oneof") - public IRubyObject lookupOneof(ThreadContext context, IRubyObject name) { - return Helpers.nullToNil(oneofDescriptors.get(Utils.symToString(name)), context.nil); - } - - protected FieldDescriptor getField(String name) { - return descriptor.findFieldByName(name); - } - - protected void setDescriptor(ThreadContext context, Descriptor descriptor, RubyDescriptorPool pool) { - Ruby runtime = context.runtime; - Map cache = new HashMap(); - this.descriptor = descriptor; - - // Populate the field caches - fieldDescriptors = new HashMap(); - oneofDescriptors = new HashMap(); - - for (FieldDescriptor fieldDescriptor : descriptor.getFields()) { - RubyFieldDescriptor fd = (RubyFieldDescriptor) cFieldDescriptor.newInstance(context, Block.NULL_BLOCK); - fd.setDescriptor(context, fieldDescriptor, pool); - fieldDescriptors.put(runtime.newString(fieldDescriptor.getName()), fd); - cache.put(fieldDescriptor, fd); - } - - for (OneofDescriptor oneofDescriptor : descriptor.getRealOneofs()) { - RubyOneofDescriptor ood = (RubyOneofDescriptor) cOneofDescriptor.newInstance(context, Block.NULL_BLOCK); - ood.setDescriptor(context, oneofDescriptor, cache); - oneofDescriptors.put(runtime.newString(oneofDescriptor.getName()), ood); - } - - // Make sure our class is built - this.klazz = buildClassFromDescriptor(context); - } - - protected void setName(IRubyObject name) { - this.name = name; - } - - private RubyClass buildClassFromDescriptor(ThreadContext context) { - Ruby runtime = context.runtime; - - ObjectAllocator allocator = new ObjectAllocator() { - @Override - public IRubyObject allocate(Ruby runtime, RubyClass klazz) { - return new RubyMessage(runtime, klazz, descriptor); - } + ObjectAllocator allocator = + new ObjectAllocator() { + @Override + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new RubyMessage(runtime, klazz, descriptor); + } }; - // rb_define_class_id - RubyClass klass = RubyClass.newClass(runtime, runtime.getObject()); - klass.setAllocator(allocator); - klass.makeMetaClass(runtime.getObject().getMetaClass()); - klass.inherit(runtime.getObject()); - RubyModule messageExts = runtime.getClassFromPath("Google::Protobuf::MessageExts"); - klass.include(new IRubyObject[] {messageExts}); - klass.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this); - klass.defineAnnotatedMethods(RubyMessage.class); - // Workaround for https://github.com/jruby/jruby/issues/7154 - klass.searchMethod("respond_to?").setIsBuiltin(false); - return klass; - } - - private static RubyClass cFieldDescriptor; - private static RubyClass cOneofDescriptor; - - private Descriptor descriptor; - private IRubyObject name; - private Map fieldDescriptors; - private Map oneofDescriptors; - private RubyClass klazz; + // rb_define_class_id + RubyClass klass = RubyClass.newClass(runtime, runtime.getObject()); + klass.setAllocator(allocator); + klass.makeMetaClass(runtime.getObject().getMetaClass()); + klass.inherit(runtime.getObject()); + RubyModule messageExts = runtime.getClassFromPath("Google::Protobuf::MessageExts"); + klass.include(new IRubyObject[] {messageExts}); + klass.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this); + klass.defineAnnotatedMethods(RubyMessage.class); + // Workaround for https://github.com/jruby/jruby/issues/7154 + klass.searchMethod("respond_to?").setIsBuiltin(false); + return klass; + } + + private static RubyClass cFieldDescriptor; + private static RubyClass cOneofDescriptor; + + private Descriptor descriptor; + private IRubyObject name; + private Map fieldDescriptors; + private Map oneofDescriptors; + private RubyClass klazz; } diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java index 6cdb341427b4..d65b412a0a9e 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyDescriptorPool.java @@ -38,6 +38,10 @@ import com.google.protobuf.Descriptors.EnumDescriptor; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.InvalidProtocolBufferException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.jruby.*; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; @@ -45,136 +49,147 @@ import org.jruby.runtime.*; import org.jruby.runtime.builtin.IRubyObject; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - @JRubyClass(name = "DescriptorPool") public class RubyDescriptorPool extends RubyObject { - public static void createRubyDescriptorPool(Ruby runtime) { - RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); - RubyClass cDescriptorPool = protobuf.defineClassUnder("DescriptorPool", runtime.getObject(), new ObjectAllocator() { - @Override - public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + public static void createRubyDescriptorPool(Ruby runtime) { + RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); + RubyClass cDescriptorPool = + protobuf.defineClassUnder( + "DescriptorPool", + runtime.getObject(), + new ObjectAllocator() { + @Override + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new RubyDescriptorPool(runtime, klazz); - } - }); - - cDescriptorPool.defineAnnotatedMethods(RubyDescriptorPool.class); - descriptorPool = (RubyDescriptorPool) cDescriptorPool.newInstance(runtime.getCurrentContext(), Block.NULL_BLOCK); - cDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Descriptor"); - cEnumDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::EnumDescriptor"); - } - - public RubyDescriptorPool(Ruby runtime, RubyClass klazz) { - super(runtime, klazz); - this.fileDescriptors = new ArrayList<>(); - this.symtab = new HashMap(); - } - - @JRubyMethod - public IRubyObject build(ThreadContext context, Block block) { - RubyClass cBuilder = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Internal::Builder"); - RubyBasicObject ctx = (RubyBasicObject) cBuilder.newInstance(context, this, Block.NULL_BLOCK); - ctx.instance_eval(context, block); - ctx.callMethod(context, "build"); // Needs to be called to support the deprecated syntax - return context.nil; + } + }); + + cDescriptorPool.defineAnnotatedMethods(RubyDescriptorPool.class); + descriptorPool = + (RubyDescriptorPool) + cDescriptorPool.newInstance(runtime.getCurrentContext(), Block.NULL_BLOCK); + cDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Descriptor"); + cEnumDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::EnumDescriptor"); + } + + public RubyDescriptorPool(Ruby runtime, RubyClass klazz) { + super(runtime, klazz); + this.fileDescriptors = new ArrayList<>(); + this.symtab = new HashMap(); + } + + @JRubyMethod + public IRubyObject build(ThreadContext context, Block block) { + RubyClass cBuilder = + (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::Internal::Builder"); + RubyBasicObject ctx = (RubyBasicObject) cBuilder.newInstance(context, this, Block.NULL_BLOCK); + ctx.instance_eval(context, block); + ctx.callMethod(context, "build"); // Needs to be called to support the deprecated syntax + return context.nil; + } + + /* + * call-seq: + * DescriptorPool.lookup(name) => descriptor + * + * Finds a Descriptor or EnumDescriptor by name and returns it, or nil if none + * exists with the given name. + * + * This currently lazy loads the ruby descriptor objects as they are requested. + * This allows us to leave the heavy lifting to the java library + */ + @JRubyMethod + public IRubyObject lookup(ThreadContext context, IRubyObject name) { + return Helpers.nullToNil(symtab.get(name), context.nil); + } + + /* + * call-seq: + * DescriptorPool.generated_pool => descriptor_pool + * + * Class method that returns the global DescriptorPool. This is a singleton into + * which generated-code message and enum types are registered. The user may also + * register types in this pool for convenience so that they do not have to hold + * a reference to a private pool instance. + */ + @JRubyMethod(meta = true, name = "generated_pool") + public static IRubyObject generatedPool(ThreadContext context, IRubyObject recv) { + return descriptorPool; + } + + @JRubyMethod(required = 1) + public IRubyObject add_serialized_file(ThreadContext context, IRubyObject data) { + byte[] bin = data.convertToString().getBytes(); + try { + FileDescriptorProto.Builder builder = FileDescriptorProto.newBuilder().mergeFrom(bin); + registerFileDescriptor(context, builder); + } catch (InvalidProtocolBufferException e) { + throw RaiseException.from( + context.runtime, + (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::ParseError"), + e.getMessage()); } - - /* - * call-seq: - * DescriptorPool.lookup(name) => descriptor - * - * Finds a Descriptor or EnumDescriptor by name and returns it, or nil if none - * exists with the given name. - * - * This currently lazy loads the ruby descriptor objects as they are requested. - * This allows us to leave the heavy lifting to the java library - */ - @JRubyMethod - public IRubyObject lookup(ThreadContext context, IRubyObject name) { - return Helpers.nullToNil(symtab.get(name), context.nil); - } - - /* - * call-seq: - * DescriptorPool.generated_pool => descriptor_pool - * - * Class method that returns the global DescriptorPool. This is a singleton into - * which generated-code message and enum types are registered. The user may also - * register types in this pool for convenience so that they do not have to hold - * a reference to a private pool instance. - */ - @JRubyMethod(meta = true, name = "generated_pool") - public static IRubyObject generatedPool(ThreadContext context, IRubyObject recv) { - return descriptorPool; - } - - @JRubyMethod(required = 1) - public IRubyObject add_serialized_file (ThreadContext context, IRubyObject data ) { - byte[] bin = data.convertToString().getBytes(); - try { - FileDescriptorProto.Builder builder = FileDescriptorProto.newBuilder().mergeFrom(bin); - registerFileDescriptor(context, builder); - } catch (InvalidProtocolBufferException e) { - throw RaiseException.from(context.runtime, (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::ParseError"), e.getMessage()); - } - return context.nil; - } - - protected void registerFileDescriptor(ThreadContext context, FileDescriptorProto.Builder builder) { - final FileDescriptor fd; - try { - fd = FileDescriptor.buildFrom(builder.build(), existingFileDescriptors()); - } catch (DescriptorValidationException e) { - throw context.runtime.newRuntimeError(e.getMessage()); - } - - String packageName = fd.getPackage(); - if (!packageName.isEmpty()) { - packageName = packageName + "."; - } - - // Need to make sure enums are registered first in case anything references them - for (EnumDescriptor ed : fd.getEnumTypes()) registerEnumDescriptor(context, ed, packageName); - for (Descriptor message : fd.getMessageTypes()) registerDescriptor(context, message, packageName); - - // Mark this as a loaded file - fileDescriptors.add(fd); + return context.nil; + } + + protected void registerFileDescriptor( + ThreadContext context, FileDescriptorProto.Builder builder) { + final FileDescriptor fd; + try { + fd = FileDescriptor.buildFrom(builder.build(), existingFileDescriptors()); + } catch (DescriptorValidationException e) { + throw context.runtime.newRuntimeError(e.getMessage()); } - private void registerDescriptor(ThreadContext context, Descriptor descriptor, String parentPath) { - String fullName = parentPath + descriptor.getName(); - String fullPath = fullName + "."; - RubyString name = context.runtime.newString(fullName); - - RubyDescriptor des = (RubyDescriptor) cDescriptor.newInstance(context, Block.NULL_BLOCK); - des.setName(name); - des.setDescriptor(context, descriptor, this); - symtab.put(name, des); - - // Need to make sure enums are registered first in case anything references them - for (EnumDescriptor ed : descriptor.getEnumTypes()) registerEnumDescriptor(context, ed, fullPath); - for (Descriptor message : descriptor.getNestedTypes()) registerDescriptor(context, message, fullPath); - } - - private void registerEnumDescriptor(ThreadContext context, EnumDescriptor descriptor, String parentPath) { - RubyString name = context.runtime.newString(parentPath + descriptor.getName()); - RubyEnumDescriptor des = (RubyEnumDescriptor) cEnumDescriptor.newInstance(context, Block.NULL_BLOCK); - des.setName(name); - des.setDescriptor(context, descriptor); - symtab.put(name, des); + String packageName = fd.getPackage(); + if (!packageName.isEmpty()) { + packageName = packageName + "."; } - private FileDescriptor[] existingFileDescriptors() { - return fileDescriptors.toArray(new FileDescriptor[fileDescriptors.size()]); - } - - private static RubyClass cDescriptor; - private static RubyClass cEnumDescriptor; - private static RubyDescriptorPool descriptorPool; - - private List fileDescriptors; - private Map symtab; + // Need to make sure enums are registered first in case anything references them + for (EnumDescriptor ed : fd.getEnumTypes()) registerEnumDescriptor(context, ed, packageName); + for (Descriptor message : fd.getMessageTypes()) + registerDescriptor(context, message, packageName); + + // Mark this as a loaded file + fileDescriptors.add(fd); + } + + private void registerDescriptor(ThreadContext context, Descriptor descriptor, String parentPath) { + String fullName = parentPath + descriptor.getName(); + String fullPath = fullName + "."; + RubyString name = context.runtime.newString(fullName); + + RubyDescriptor des = (RubyDescriptor) cDescriptor.newInstance(context, Block.NULL_BLOCK); + des.setName(name); + des.setDescriptor(context, descriptor, this); + symtab.put(name, des); + + // Need to make sure enums are registered first in case anything references them + for (EnumDescriptor ed : descriptor.getEnumTypes()) + registerEnumDescriptor(context, ed, fullPath); + for (Descriptor message : descriptor.getNestedTypes()) + registerDescriptor(context, message, fullPath); + } + + private void registerEnumDescriptor( + ThreadContext context, EnumDescriptor descriptor, String parentPath) { + RubyString name = context.runtime.newString(parentPath + descriptor.getName()); + RubyEnumDescriptor des = + (RubyEnumDescriptor) cEnumDescriptor.newInstance(context, Block.NULL_BLOCK); + des.setName(name); + des.setDescriptor(context, descriptor); + symtab.put(name, des); + } + + private FileDescriptor[] existingFileDescriptors() { + return fileDescriptors.toArray(new FileDescriptor[fileDescriptors.size()]); + } + + private static RubyClass cDescriptor; + private static RubyClass cEnumDescriptor; + private static RubyDescriptorPool descriptorPool; + + private List fileDescriptors; + private Map symtab; } diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java index 17525dfe4495..95d961e11a2c 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyEnum.java @@ -38,41 +38,41 @@ import org.jruby.runtime.builtin.IRubyObject; public class RubyEnum { - /* - * call-seq: - * Enum.lookup(number) => name - * - * This module method, provided on each generated enum module, looks up an enum - * value by number and returns its name as a Ruby symbol, or nil if not found. - */ - @JRubyMethod(meta = true) - public static IRubyObject lookup(ThreadContext context, IRubyObject recv, IRubyObject number) { - RubyEnumDescriptor rubyEnumDescriptor = (RubyEnumDescriptor) getDescriptor(context, recv); - return rubyEnumDescriptor.numberToName(context, number); - } + /* + * call-seq: + * Enum.lookup(number) => name + * + * This module method, provided on each generated enum module, looks up an enum + * value by number and returns its name as a Ruby symbol, or nil if not found. + */ + @JRubyMethod(meta = true) + public static IRubyObject lookup(ThreadContext context, IRubyObject recv, IRubyObject number) { + RubyEnumDescriptor rubyEnumDescriptor = (RubyEnumDescriptor) getDescriptor(context, recv); + return rubyEnumDescriptor.numberToName(context, number); + } - /* - * call-seq: - * Enum.resolve(name) => number - * - * This module method, provided on each generated enum module, looks up an enum - * value by name (as a Ruby symbol) and returns its name, or nil if not found. - */ - @JRubyMethod(meta = true) - public static IRubyObject resolve(ThreadContext context, IRubyObject recv, IRubyObject name) { - RubyEnumDescriptor rubyEnumDescriptor = (RubyEnumDescriptor) getDescriptor(context, recv); - return rubyEnumDescriptor.nameToNumber(context, name); - } + /* + * call-seq: + * Enum.resolve(name) => number + * + * This module method, provided on each generated enum module, looks up an enum + * value by name (as a Ruby symbol) and returns its name, or nil if not found. + */ + @JRubyMethod(meta = true) + public static IRubyObject resolve(ThreadContext context, IRubyObject recv, IRubyObject name) { + RubyEnumDescriptor rubyEnumDescriptor = (RubyEnumDescriptor) getDescriptor(context, recv); + return rubyEnumDescriptor.nameToNumber(context, name); + } - /* - * call-seq: - * Enum.descriptor - * - * This module method, provided on each generated enum module, returns the - * EnumDescriptor corresponding to this enum type. - */ - @JRubyMethod(meta = true, name = "descriptor") - public static IRubyObject getDescriptor(ThreadContext context, IRubyObject recv) { - return ((RubyModule) recv).getInstanceVariable(Utils.DESCRIPTOR_INSTANCE_VAR); - } + /* + * call-seq: + * Enum.descriptor + * + * This module method, provided on each generated enum module, returns the + * EnumDescriptor corresponding to this enum type. + */ + @JRubyMethod(meta = true, name = "descriptor") + public static IRubyObject getDescriptor(ThreadContext context, IRubyObject recv) { + return ((RubyModule) recv).getInstanceVariable(Utils.DESCRIPTOR_INSTANCE_VAR); + } } diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java index 26f00db66623..65328676e11e 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java @@ -39,8 +39,8 @@ import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyModule; -import org.jruby.RubyObject; import org.jruby.RubyNumeric; +import org.jruby.RubyObject; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; import org.jruby.runtime.Block; @@ -50,132 +50,147 @@ @JRubyClass(name = "EnumDescriptor", include = "Enumerable") public class RubyEnumDescriptor extends RubyObject { - public static void createRubyEnumDescriptor(Ruby runtime) { - RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf"); - RubyClass cEnumDescriptor = mProtobuf.defineClassUnder("EnumDescriptor", runtime.getObject(), new ObjectAllocator() { - @Override - public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + public static void createRubyEnumDescriptor(Ruby runtime) { + RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf"); + RubyClass cEnumDescriptor = + mProtobuf.defineClassUnder( + "EnumDescriptor", + runtime.getObject(), + new ObjectAllocator() { + @Override + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new RubyEnumDescriptor(runtime, klazz); - } - }); - cEnumDescriptor.includeModule(runtime.getEnumerable()); - cEnumDescriptor.defineAnnotatedMethods(RubyEnumDescriptor.class); - } - - public RubyEnumDescriptor(Ruby runtime, RubyClass klazz) { - super(runtime, klazz); - } - - /* - * call-seq: - * EnumDescriptor.name => name - * - * Returns the name of this enum type. - */ - @JRubyMethod(name = "name") - public IRubyObject getName(ThreadContext context) { - return this.name; - } - - /* - * call-seq: - * EnumDescriptor.each(&block) - * - * Iterates over key => value mappings in this enum's definition, yielding to - * the block with (key, value) arguments for each one. - */ - @JRubyMethod - public IRubyObject each(ThreadContext context, Block block) { - Ruby runtime = context.runtime; - for (EnumValueDescriptor enumValueDescriptor : descriptor.getValues()) { - block.yield(context, runtime.newArray(runtime.newSymbol(enumValueDescriptor.getName()), - runtime.newFixnum(enumValueDescriptor.getNumber()))); - } - return context.nil; - } - - /* - * call-seq: - * EnumDescriptor.enummodule => module - * - * Returns the Ruby module corresponding to this enum type. Cannot be called - * until the enum descriptor has been added to a pool. - */ - @JRubyMethod - public IRubyObject enummodule(ThreadContext context) { - return module; - } - - /* - * call-seq: - * EnumDescriptor.file_descriptor - * - * Returns the FileDescriptor object this enum belongs to. - */ - @JRubyMethod(name = "file_descriptor") - public IRubyObject getFileDescriptor(ThreadContext context) { - return RubyFileDescriptor.getRubyFileDescriptor(context, descriptor); - } - - public boolean isValidValue(ThreadContext context, IRubyObject value) { - EnumValueDescriptor enumValue; - - if (Utils.isRubyNum(value)) { - enumValue = descriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value)); - } else { - enumValue = descriptor.findValueByName(value.asJavaString()); - } - - return enumValue != null; + } + }); + cEnumDescriptor.includeModule(runtime.getEnumerable()); + cEnumDescriptor.defineAnnotatedMethods(RubyEnumDescriptor.class); + } + + public RubyEnumDescriptor(Ruby runtime, RubyClass klazz) { + super(runtime, klazz); + } + + /* + * call-seq: + * EnumDescriptor.name => name + * + * Returns the name of this enum type. + */ + @JRubyMethod(name = "name") + public IRubyObject getName(ThreadContext context) { + return this.name; + } + + /* + * call-seq: + * EnumDescriptor.each(&block) + * + * Iterates over key => value mappings in this enum's definition, yielding to + * the block with (key, value) arguments for each one. + */ + @JRubyMethod + public IRubyObject each(ThreadContext context, Block block) { + Ruby runtime = context.runtime; + for (EnumValueDescriptor enumValueDescriptor : descriptor.getValues()) { + block.yield( + context, + runtime.newArray( + runtime.newSymbol(enumValueDescriptor.getName()), + runtime.newFixnum(enumValueDescriptor.getNumber()))); } - - protected IRubyObject nameToNumber(ThreadContext context, IRubyObject name) { - EnumValueDescriptor value = descriptor.findValueByName(name.asJavaString()); - return value == null ? context.nil : context.runtime.newFixnum(value.getNumber()); + return context.nil; + } + + /* + * call-seq: + * EnumDescriptor.enummodule => module + * + * Returns the Ruby module corresponding to this enum type. Cannot be called + * until the enum descriptor has been added to a pool. + */ + @JRubyMethod + public IRubyObject enummodule(ThreadContext context) { + return module; + } + + /* + * call-seq: + * EnumDescriptor.file_descriptor + * + * Returns the FileDescriptor object this enum belongs to. + */ + @JRubyMethod(name = "file_descriptor") + public IRubyObject getFileDescriptor(ThreadContext context) { + return RubyFileDescriptor.getRubyFileDescriptor(context, descriptor); + } + + public boolean isValidValue(ThreadContext context, IRubyObject value) { + EnumValueDescriptor enumValue; + + if (Utils.isRubyNum(value)) { + enumValue = descriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value)); + } else { + enumValue = descriptor.findValueByName(value.asJavaString()); } - protected IRubyObject numberToName(ThreadContext context, IRubyObject number) { - EnumValueDescriptor value = descriptor.findValueByNumber(RubyNumeric.num2int(number)); - return value == null ? context.nil : context.runtime.newSymbol(value.getName()); + return enumValue != null; + } + + protected IRubyObject nameToNumber(ThreadContext context, IRubyObject name) { + EnumValueDescriptor value = descriptor.findValueByName(name.asJavaString()); + return value == null ? context.nil : context.runtime.newFixnum(value.getNumber()); + } + + protected IRubyObject numberToName(ThreadContext context, IRubyObject number) { + EnumValueDescriptor value = descriptor.findValueByNumber(RubyNumeric.num2int(number)); + return value == null ? context.nil : context.runtime.newSymbol(value.getName()); + } + + protected void setDescriptor(ThreadContext context, EnumDescriptor descriptor) { + this.descriptor = descriptor; + this.module = buildModuleFromDescriptor(context); + } + + protected void setName(IRubyObject name) { + this.name = name; + } + + private RubyModule buildModuleFromDescriptor(ThreadContext context) { + Ruby runtime = context.runtime; + + RubyModule enumModule = RubyModule.newModule(runtime); + boolean defaultValueRequiredButNotFound = + descriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO3; + for (EnumValueDescriptor value : descriptor.getValues()) { + String name = value.getName(); + // Make sure its a valid constant name before trying to create it + if (Character.isUpperCase(name.codePointAt(0))) { + enumModule.defineConstant(name, runtime.newFixnum(value.getNumber())); + } else { + runtime + .getWarnings() + .warn( + "Enum value " + + name + + " does not start with an uppercase letter as is required for Ruby" + + " constants."); + } + if (value.getNumber() == 0) { + defaultValueRequiredButNotFound = false; + } } - protected void setDescriptor(ThreadContext context, EnumDescriptor descriptor) { - this.descriptor = descriptor; - this.module = buildModuleFromDescriptor(context); + if (defaultValueRequiredButNotFound) { + throw Utils.createTypeError( + context, "Enum definition " + name + " does not contain a value for '0'"); } - - protected void setName(IRubyObject name) { - this.name = name; - } - - private RubyModule buildModuleFromDescriptor(ThreadContext context) { - Ruby runtime = context.runtime; - - RubyModule enumModule = RubyModule.newModule(runtime); - boolean defaultValueRequiredButNotFound = descriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO3; - for (EnumValueDescriptor value : descriptor.getValues()) { - String name = value.getName(); - // Make sure its a valid constant name before trying to create it - if (Character.isUpperCase(name.codePointAt(0))) { - enumModule.defineConstant(name, runtime.newFixnum(value.getNumber())); - } else { - runtime.getWarnings().warn("Enum value " + name + " does not start with an uppercase letter as is required for Ruby constants."); - } - if (value.getNumber() == 0) { - defaultValueRequiredButNotFound = false; - } - } - - if (defaultValueRequiredButNotFound) { - throw Utils.createTypeError(context, "Enum definition " + name + " does not contain a value for '0'"); - } - enumModule.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this); - enumModule.defineAnnotatedMethods(RubyEnum.class); - return enumModule; - } - - private EnumDescriptor descriptor; - private EnumDescriptorProto.Builder builder; - private IRubyObject name; - private RubyModule module; + enumModule.instance_variable_set(runtime.newString(Utils.DESCRIPTOR_INSTANCE_VAR), this); + enumModule.defineAnnotatedMethods(RubyEnum.class); + return enumModule; + } + + private EnumDescriptor descriptor; + private EnumDescriptorProto.Builder builder; + private IRubyObject name; + private RubyModule module; } diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java index e9594d831d22..bc1fe0cbe64d 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyFieldDescriptor.java @@ -43,228 +43,237 @@ @JRubyClass(name = "FieldDescriptor") public class RubyFieldDescriptor extends RubyObject { - public static void createRubyFieldDescriptor(Ruby runtime) { - RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf"); - RubyClass cFieldDescriptor = mProtobuf.defineClassUnder("FieldDescriptor", runtime.getObject(), new ObjectAllocator() { - @Override - public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + public static void createRubyFieldDescriptor(Ruby runtime) { + RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf"); + RubyClass cFieldDescriptor = + mProtobuf.defineClassUnder( + "FieldDescriptor", + runtime.getObject(), + new ObjectAllocator() { + @Override + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new RubyFieldDescriptor(runtime, klazz); - } - }); - cFieldDescriptor.defineAnnotatedMethods(RubyFieldDescriptor.class); - } + } + }); + cFieldDescriptor.defineAnnotatedMethods(RubyFieldDescriptor.class); + } - public RubyFieldDescriptor(Ruby runtime, RubyClass klazz) { - super(runtime, klazz); - } + public RubyFieldDescriptor(Ruby runtime, RubyClass klazz) { + super(runtime, klazz); + } - /* - * call-seq: - * FieldDescriptor.default => default - * - * Returns this field's default, as a Ruby object, or nil if not yet set. - */ - // VALUE FieldDescriptor_default(VALUE _self) { - // DEFINE_SELF(FieldDescriptor, self, _self); - // return layout_get_default(self->fielddef); - // } + /* + * call-seq: + * FieldDescriptor.default => default + * + * Returns this field's default, as a Ruby object, or nil if not yet set. + */ + // VALUE FieldDescriptor_default(VALUE _self) { + // DEFINE_SELF(FieldDescriptor, self, _self); + // return layout_get_default(self->fielddef); + // } - /* - * call-seq: - * FieldDescriptor.label => label - * - * Returns this field's label (i.e., plurality), as a Ruby symbol. - * - * Valid field labels are: - * :optional, :repeated - */ - @JRubyMethod(name = "label") - public IRubyObject getLabel(ThreadContext context) { - if (label == null) { - calculateLabel(context); - } - return label; + /* + * call-seq: + * FieldDescriptor.label => label + * + * Returns this field's label (i.e., plurality), as a Ruby symbol. + * + * Valid field labels are: + * :optional, :repeated + */ + @JRubyMethod(name = "label") + public IRubyObject getLabel(ThreadContext context) { + if (label == null) { + calculateLabel(context); } + return label; + } - /* - * call-seq: - * FieldDescriptor.name => name - * - * Returns the name of this field as a Ruby String, or nil if it is not set. - */ - @JRubyMethod(name = "name") - public IRubyObject getName(ThreadContext context) { - return this.name; - } + /* + * call-seq: + * FieldDescriptor.name => name + * + * Returns the name of this field as a Ruby String, or nil if it is not set. + */ + @JRubyMethod(name = "name") + public IRubyObject getName(ThreadContext context) { + return this.name; + } - /* - * call-seq: - * FieldDescriptor.subtype => message_or_enum_descriptor - * - * Returns the message or enum descriptor corresponding to this field's type if - * it is a message or enum field, respectively, or nil otherwise. Cannot be - * called *until* the containing message type is added to a pool (and thus - * resolved). - */ - @JRubyMethod(name = "subtype") - public IRubyObject getSubtype(ThreadContext context) { - if (subtype == null) { - calculateSubtype(context); - } - return subtype; + /* + * call-seq: + * FieldDescriptor.subtype => message_or_enum_descriptor + * + * Returns the message or enum descriptor corresponding to this field's type if + * it is a message or enum field, respectively, or nil otherwise. Cannot be + * called *until* the containing message type is added to a pool (and thus + * resolved). + */ + @JRubyMethod(name = "subtype") + public IRubyObject getSubtype(ThreadContext context) { + if (subtype == null) { + calculateSubtype(context); } + return subtype; + } - /* - * call-seq: - * FieldDescriptor.type => type - * - * Returns this field's type, as a Ruby symbol, or nil if not yet set. - * - * Valid field types are: - * :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string, - * :bytes, :message. - */ - @JRubyMethod(name = "type") - public IRubyObject getType(ThreadContext context) { - return Utils.fieldTypeToRuby(context, descriptor.getType()); - } + /* + * call-seq: + * FieldDescriptor.type => type + * + * Returns this field's type, as a Ruby symbol, or nil if not yet set. + * + * Valid field types are: + * :int32, :int64, :uint32, :uint64, :float, :double, :bool, :string, + * :bytes, :message. + */ + @JRubyMethod(name = "type") + public IRubyObject getType(ThreadContext context) { + return Utils.fieldTypeToRuby(context, descriptor.getType()); + } - /* - * call-seq: - * FieldDescriptor.number => number - * - * Returns the tag number for this field. - */ - @JRubyMethod(name = "number") - public IRubyObject getNumber(ThreadContext context) { - return this.number; - } + /* + * call-seq: + * FieldDescriptor.number => number + * + * Returns the tag number for this field. + */ + @JRubyMethod(name = "number") + public IRubyObject getNumber(ThreadContext context) { + return this.number; + } - /* - * call-seq: - * FieldDescriptor.submsg_name => submsg_name - * - * Returns the name of the message or enum type corresponding to this field, if - * it is a message or enum field (respectively), or nil otherwise. This type - * name will be resolved within the context of the pool to which the containing - * message type is added. - */ - // VALUE FieldDescriptor_submsg_name(VALUE _self) { - // DEFINE_SELF(FieldDescriptor, self, _self); - // switch (upb_fielddef_type(self->fielddef)) { - // case UPB_TYPE_ENUM: - // return rb_str_new2( - // upb_enumdef_fullname(upb_fielddef_enumsubdef(self->fielddef))); - // case UPB_TYPE_MESSAGE: - // return rb_str_new2( - // upb_msgdef_fullname(upb_fielddef_msgsubdef(self->fielddef))); - // default: - // return Qnil; - // } - // } - /* - * call-seq: - * FieldDescriptor.submsg_name = submsg_name - * - * Sets the name of the message or enum type corresponding to this field, if it - * is a message or enum field (respectively). This type name will be resolved - * within the context of the pool to which the containing message type is added. - * Cannot be called on field that are not of message or enum type, or on fields - * that are part of a message type already added to a pool. - */ - // @JRubyMethod(name = "submsg_name=") - // public IRubyObject setSubmsgName(ThreadContext context, IRubyObject name) { - // this.builder.setTypeName("." + Utils.escapeIdentifier(name.asJavaString())); - // return context.runtime.getNil(); - // } + /* + * call-seq: + * FieldDescriptor.submsg_name => submsg_name + * + * Returns the name of the message or enum type corresponding to this field, if + * it is a message or enum field (respectively), or nil otherwise. This type + * name will be resolved within the context of the pool to which the containing + * message type is added. + */ + // VALUE FieldDescriptor_submsg_name(VALUE _self) { + // DEFINE_SELF(FieldDescriptor, self, _self); + // switch (upb_fielddef_type(self->fielddef)) { + // case UPB_TYPE_ENUM: + // return rb_str_new2( + // upb_enumdef_fullname(upb_fielddef_enumsubdef(self->fielddef))); + // case UPB_TYPE_MESSAGE: + // return rb_str_new2( + // upb_msgdef_fullname(upb_fielddef_msgsubdef(self->fielddef))); + // default: + // return Qnil; + // } + // } + /* + * call-seq: + * FieldDescriptor.submsg_name = submsg_name + * + * Sets the name of the message or enum type corresponding to this field, if it + * is a message or enum field (respectively). This type name will be resolved + * within the context of the pool to which the containing message type is added. + * Cannot be called on field that are not of message or enum type, or on fields + * that are part of a message type already added to a pool. + */ + // @JRubyMethod(name = "submsg_name=") + // public IRubyObject setSubmsgName(ThreadContext context, IRubyObject name) { + // this.builder.setTypeName("." + Utils.escapeIdentifier(name.asJavaString())); + // return context.runtime.getNil(); + // } - /* - * call-seq: - * FieldDescriptor.clear(message) - * - * Clears the field from the message if it's set. - */ - @JRubyMethod(name = "clear") - public IRubyObject clearValue(ThreadContext context, IRubyObject message) { - return ((RubyMessage) message).clearField(context, descriptor); - } + /* + * call-seq: + * FieldDescriptor.clear(message) + * + * Clears the field from the message if it's set. + */ + @JRubyMethod(name = "clear") + public IRubyObject clearValue(ThreadContext context, IRubyObject message) { + return ((RubyMessage) message).clearField(context, descriptor); + } - /* - * call-seq: - * FieldDescriptor.get(message) => value - * - * Returns the value set for this field on the given message. Raises an - * exception if message is of the wrong type. - */ - @JRubyMethod(name = "get") - public IRubyObject getValue(ThreadContext context, IRubyObject message) { - return ((RubyMessage) message).getField(context, descriptor); - } + /* + * call-seq: + * FieldDescriptor.get(message) => value + * + * Returns the value set for this field on the given message. Raises an + * exception if message is of the wrong type. + */ + @JRubyMethod(name = "get") + public IRubyObject getValue(ThreadContext context, IRubyObject message) { + return ((RubyMessage) message).getField(context, descriptor); + } - /* - * call-seq: - * FieldDescriptor.has?(message) => boolean - * - * Returns whether the value is set on the given message. Raises an - * exception when calling for fields that do not have presence. - */ - @JRubyMethod(name = "has?") - public IRubyObject has(ThreadContext context, IRubyObject message) { - return ((RubyMessage) message).hasField(context, descriptor); - } + /* + * call-seq: + * FieldDescriptor.has?(message) => boolean + * + * Returns whether the value is set on the given message. Raises an + * exception when calling for fields that do not have presence. + */ + @JRubyMethod(name = "has?") + public IRubyObject has(ThreadContext context, IRubyObject message) { + return ((RubyMessage) message).hasField(context, descriptor); + } - /* - * call-seq: - * FieldDescriptor.set(message, value) - * - * Sets the value corresponding to this field to the given value on the given - * message. Raises an exception if message is of the wrong type. Performs the - * ordinary type-checks for field setting. - */ - @JRubyMethod(name = "set") - public IRubyObject setValue(ThreadContext context, IRubyObject message, IRubyObject value) { - ((RubyMessage) message).setField(context, descriptor, value); - return context.nil; - } + /* + * call-seq: + * FieldDescriptor.set(message, value) + * + * Sets the value corresponding to this field to the given value on the given + * message. Raises an exception if message is of the wrong type. Performs the + * ordinary type-checks for field setting. + */ + @JRubyMethod(name = "set") + public IRubyObject setValue(ThreadContext context, IRubyObject message, IRubyObject value) { + ((RubyMessage) message).setField(context, descriptor, value); + return context.nil; + } - protected void setDescriptor(ThreadContext context, FieldDescriptor descriptor, RubyDescriptorPool pool) { - if (descriptor.isRequired() && descriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO3) { - throw Utils.createTypeError(context, descriptor.getName() + " is labeled required but required fields are unsupported in proto3"); - } - this.descriptor = descriptor; - this.name = context.runtime.newString(descriptor.getName()); - this.pool = pool; + protected void setDescriptor( + ThreadContext context, FieldDescriptor descriptor, RubyDescriptorPool pool) { + if (descriptor.isRequired() + && descriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO3) { + throw Utils.createTypeError( + context, + descriptor.getName() + + " is labeled required but required fields are unsupported in proto3"); } + this.descriptor = descriptor; + this.name = context.runtime.newString(descriptor.getName()); + this.pool = pool; + } - private void calculateLabel(ThreadContext context) { - if (descriptor.isRepeated()) { - this.label = context.runtime.newSymbol("repeated"); - } else if (descriptor.isOptional()) { - this.label = context.runtime.newSymbol("optional"); - } else { - this.label = context.nil; - } + private void calculateLabel(ThreadContext context) { + if (descriptor.isRepeated()) { + this.label = context.runtime.newSymbol("repeated"); + } else if (descriptor.isOptional()) { + this.label = context.runtime.newSymbol("optional"); + } else { + this.label = context.nil; } + } - private void calculateSubtype(ThreadContext context) { - FieldDescriptor.Type fdType = descriptor.getType(); - if (fdType == FieldDescriptor.Type.MESSAGE) { - RubyString messageName = context.runtime.newString(descriptor.getMessageType().getFullName()); - this.subtype = pool.lookup(context, messageName); - } else if (fdType == FieldDescriptor.Type.ENUM) { - RubyString enumName = context.runtime.newString(descriptor.getEnumType().getFullName()); - this.subtype = pool.lookup(context, enumName); - } else { - this.subtype = context.nil; - } + private void calculateSubtype(ThreadContext context) { + FieldDescriptor.Type fdType = descriptor.getType(); + if (fdType == FieldDescriptor.Type.MESSAGE) { + RubyString messageName = context.runtime.newString(descriptor.getMessageType().getFullName()); + this.subtype = pool.lookup(context, messageName); + } else if (fdType == FieldDescriptor.Type.ENUM) { + RubyString enumName = context.runtime.newString(descriptor.getEnumType().getFullName()); + this.subtype = pool.lookup(context, enumName); + } else { + this.subtype = context.nil; } + } - private static final String DOT = "."; + private static final String DOT = "."; - private FieldDescriptor descriptor; - private IRubyObject name; - private IRubyObject label; - private IRubyObject number; - private IRubyObject subtype; - private RubyDescriptorPool pool; + private FieldDescriptor descriptor; + private IRubyObject name; + private IRubyObject label; + private IRubyObject number; + private IRubyObject subtype; + private RubyDescriptorPool pool; } diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyFileDescriptor.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyFileDescriptor.java index b3e1816c76a2..972510b0223f 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyFileDescriptor.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyFileDescriptor.java @@ -32,7 +32,6 @@ package com.google.protobuf.jruby; -import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.Descriptors.FileDescriptor.Syntax.*; import com.google.protobuf.Descriptors.GenericDescriptor; @@ -46,61 +45,67 @@ @JRubyClass(name = "FileDescriptor") public class RubyFileDescriptor extends RubyObject { - public static void createRubyFileDescriptor(Ruby runtime) { - RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf"); - cFileDescriptor = mProtobuf.defineClassUnder("FileDescriptor", runtime.getObject(), new ObjectAllocator() { - @Override - public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + public static void createRubyFileDescriptor(Ruby runtime) { + RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf"); + cFileDescriptor = + mProtobuf.defineClassUnder( + "FileDescriptor", + runtime.getObject(), + new ObjectAllocator() { + @Override + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new RubyFileDescriptor(runtime, klazz); - } - }); - cFileDescriptor.defineAnnotatedMethods(RubyFileDescriptor.class); - } + } + }); + cFileDescriptor.defineAnnotatedMethods(RubyFileDescriptor.class); + } - public static RubyFileDescriptor getRubyFileDescriptor(ThreadContext context, GenericDescriptor descriptor) { - RubyFileDescriptor rfd = (RubyFileDescriptor) cFileDescriptor.newInstance(context, Block.NULL_BLOCK); - rfd.fileDescriptor = descriptor.getFile(); - return rfd; - } + public static RubyFileDescriptor getRubyFileDescriptor( + ThreadContext context, GenericDescriptor descriptor) { + RubyFileDescriptor rfd = + (RubyFileDescriptor) cFileDescriptor.newInstance(context, Block.NULL_BLOCK); + rfd.fileDescriptor = descriptor.getFile(); + return rfd; + } - public RubyFileDescriptor(Ruby runtime, RubyClass klazz) { - super(runtime, klazz); - } + public RubyFileDescriptor(Ruby runtime, RubyClass klazz) { + super(runtime, klazz); + } - /* - * call-seq: - * FileDescriptor.name => name - * - * Returns the name of the file. - */ - @JRubyMethod(name = "name") - public IRubyObject getName(ThreadContext context) { - String name = fileDescriptor.getName(); - return name == null ? context.nil : context.runtime.newString(name); - } + /* + * call-seq: + * FileDescriptor.name => name + * + * Returns the name of the file. + */ + @JRubyMethod(name = "name") + public IRubyObject getName(ThreadContext context) { + String name = fileDescriptor.getName(); + return name == null ? context.nil : context.runtime.newString(name); + } - /* - * call-seq: - * FileDescriptor.syntax => syntax - * - * Returns this file descriptors syntax. - * - * Valid syntax versions are: - * :proto2 or :proto3. - */ - @JRubyMethod(name = "syntax") - public IRubyObject getSyntax(ThreadContext context) { - switch (fileDescriptor.getSyntax()) { - case PROTO2: - return context.runtime.newSymbol("proto2"); - case PROTO3: - return context.runtime.newSymbol("proto3"); - default: - return context.nil; - } + /* + * call-seq: + * FileDescriptor.syntax => syntax + * + * Returns this file descriptors syntax. + * + * Valid syntax versions are: + * :proto2 or :proto3. + */ + @JRubyMethod(name = "syntax") + public IRubyObject getSyntax(ThreadContext context) { + switch (fileDescriptor.getSyntax()) { + case PROTO2: + return context.runtime.newSymbol("proto2"); + case PROTO3: + return context.runtime.newSymbol("proto3"); + default: + return context.nil; } + } - private static RubyClass cFileDescriptor; + private static RubyClass cFileDescriptor; - private FileDescriptor fileDescriptor; + private FileDescriptor fileDescriptor; } diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java index 7956eebe7611..8727b13cf7dc 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java @@ -34,6 +34,13 @@ import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.DynamicMessage; +import java.nio.ByteBuffer; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.jruby.*; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; @@ -43,432 +50,438 @@ import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; -import java.nio.ByteBuffer; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - @JRubyClass(name = "Map", include = "Enumerable") public class RubyMap extends RubyObject { - public static void createRubyMap(Ruby runtime) { - RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); - RubyClass cMap = protobuf.defineClassUnder("Map", runtime.getObject(), new ObjectAllocator() { - @Override - public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) { + public static void createRubyMap(Ruby runtime) { + RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); + RubyClass cMap = + protobuf.defineClassUnder( + "Map", + runtime.getObject(), + new ObjectAllocator() { + @Override + public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) { return new RubyMap(ruby, rubyClass); - } - }); - cMap.includeModule(runtime.getEnumerable()); - cMap.defineAnnotatedMethods(RubyMap.class); - } - - public RubyMap(Ruby ruby, RubyClass rubyClass) { - super(ruby, rubyClass); + } + }); + cMap.includeModule(runtime.getEnumerable()); + cMap.defineAnnotatedMethods(RubyMap.class); + } + + public RubyMap(Ruby ruby, RubyClass rubyClass) { + super(ruby, rubyClass); + } + + /* + * call-seq: + * Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {}) + * => new map + * + * Allocates a new Map container. This constructor may be called with 2, 3, or 4 + * arguments. The first two arguments are always present and are symbols (taking + * on the same values as field-type symbols in message descriptors) that + * indicate the type of the map key and value fields. + * + * The supported key types are: :int32, :int64, :uint32, :uint64, :fixed32, + * :fixed64, :sfixed32, :sfixed64, :sint32, :sint64, :bool, :string, :bytes. + * + * The supported value types are: :int32, :int64, :uint32, :uint64, :fixed32, + * :fixed64, :sfixed32, :sfixed64, :sint32, :sint64, :bool, :string, :bytes, + * :enum, :message. + * + * The third argument, value_typeclass, must be present if value_type is :enum + * or :message. As in RepeatedField#new, this argument must be a message class + * (for :message) or enum module (for :enum). + * + * The last argument, if present, provides initial content for map. Note that + * this may be an ordinary Ruby hashmap or another Map instance with identical + * key and value types. Also note that this argument may be present whether or + * not value_typeclass is present (and it is unambiguously separate from + * value_typeclass because value_typeclass's presence is strictly determined by + * value_type). The contents of this initial hashmap or Map instance are + * shallow-copied into the new Map: the original map is unmodified, but + * references to underlying objects will be shared if the value type is a + * message type. + */ + @JRubyMethod(required = 2, optional = 2) + public IRubyObject initialize(ThreadContext context, IRubyObject[] args) { + this.table = new HashMap(); + this.keyType = Utils.rubyToFieldType(args[0]); + this.valueType = Utils.rubyToFieldType(args[1]); + + switch (keyType) { + case STRING: + case BYTES: + this.keyTypeIsString = true; + break; + case INT32: + case INT64: + case SINT32: + case SINT64: + case UINT32: + case UINT64: + case FIXED32: + case FIXED64: + case SFIXED32: + case SFIXED64: + case BOOL: + // These are OK. + break; + default: + throw context.runtime.newArgumentError("Invalid key type for map."); } - /* - * call-seq: - * Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {}) - * => new map - * - * Allocates a new Map container. This constructor may be called with 2, 3, or 4 - * arguments. The first two arguments are always present and are symbols (taking - * on the same values as field-type symbols in message descriptors) that - * indicate the type of the map key and value fields. - * - * The supported key types are: :int32, :int64, :uint32, :uint64, :fixed32, - * :fixed64, :sfixed32, :sfixed64, :sint32, :sint64, :bool, :string, :bytes. - * - * The supported value types are: :int32, :int64, :uint32, :uint64, :fixed32, - * :fixed64, :sfixed32, :sfixed64, :sint32, :sint64, :bool, :string, :bytes, - * :enum, :message. - * - * The third argument, value_typeclass, must be present if value_type is :enum - * or :message. As in RepeatedField#new, this argument must be a message class - * (for :message) or enum module (for :enum). - * - * The last argument, if present, provides initial content for map. Note that - * this may be an ordinary Ruby hashmap or another Map instance with identical - * key and value types. Also note that this argument may be present whether or - * not value_typeclass is present (and it is unambiguously separate from - * value_typeclass because value_typeclass's presence is strictly determined by - * value_type). The contents of this initial hashmap or Map instance are - * shallow-copied into the new Map: the original map is unmodified, but - * references to underlying objects will be shared if the value type is a - * message type. - */ - @JRubyMethod(required = 2, optional = 2) - public IRubyObject initialize(ThreadContext context, IRubyObject[] args) { - this.table = new HashMap(); - this.keyType = Utils.rubyToFieldType(args[0]); - this.valueType = Utils.rubyToFieldType(args[1]); - - switch(keyType) { - case STRING: - case BYTES: - this.keyTypeIsString = true; - break; - case INT32: - case INT64: - case SINT32: - case SINT64: - case UINT32: - case UINT64: - case FIXED32: - case FIXED64: - case SFIXED32: - case SFIXED64: - case BOOL: - // These are OK. - break; - default: - throw context.runtime.newArgumentError("Invalid key type for map."); - } - - int initValueArg = 2; - if (needTypeclass(this.valueType) && args.length > 2) { - this.valueTypeClass = args[2]; - Utils.validateTypeClass(context, this.valueType, this.valueTypeClass); - initValueArg = 3; - } else { - this.valueTypeClass = context.runtime.getNilClass(); - } - - if (args.length > initValueArg) { - mergeIntoSelf(context, args[initValueArg]); - } - return this; + int initValueArg = 2; + if (needTypeclass(this.valueType) && args.length > 2) { + this.valueTypeClass = args[2]; + Utils.validateTypeClass(context, this.valueType, this.valueTypeClass); + initValueArg = 3; + } else { + this.valueTypeClass = context.runtime.getNilClass(); } - /* - * call-seq: - * Map.[]=(key, value) => value - * - * Inserts or overwrites the value at the given key with the given new value. - * Throws an exception if the key type is incorrect. Returns the new value that - * was just inserted. - */ - @JRubyMethod(name = "[]=") - public IRubyObject indexSet(ThreadContext context, IRubyObject key, IRubyObject value) { - checkFrozen(); - - /* - * String types for keys return a different error than - * other types for keys, so deal with them specifically first - */ - if (keyTypeIsString && !(key instanceof RubySymbol || key instanceof RubyString)) { - throw Utils.createTypeError(context, "Expected string for map key"); - } - key = Utils.checkType(context, keyType, "key", key, (RubyModule) valueTypeClass); - value = Utils.checkType(context, valueType, "value", value, (RubyModule) valueTypeClass); - IRubyObject symbol; - if (valueType == FieldDescriptor.Type.ENUM && - Utils.isRubyNum(value) && - ! (symbol = RubyEnum.lookup(context, valueTypeClass, value)).isNil()) { - value = symbol; - } - this.table.put(key, value); - return value; + if (args.length > initValueArg) { + mergeIntoSelf(context, args[initValueArg]); } + return this; + } + + /* + * call-seq: + * Map.[]=(key, value) => value + * + * Inserts or overwrites the value at the given key with the given new value. + * Throws an exception if the key type is incorrect. Returns the new value that + * was just inserted. + */ + @JRubyMethod(name = "[]=") + public IRubyObject indexSet(ThreadContext context, IRubyObject key, IRubyObject value) { + checkFrozen(); /* - * call-seq: - * Map.[](key) => value - * - * Accesses the element at the given key. Throws an exception if the key type is - * incorrect. Returns nil when the key is not present in the map. + * String types for keys return a different error than + * other types for keys, so deal with them specifically first */ - @JRubyMethod(name = "[]") - public IRubyObject index(ThreadContext context, IRubyObject key) { - key = Utils.symToString(key); - return Helpers.nullToNil(table.get(key), context.nil); + if (keyTypeIsString && !(key instanceof RubySymbol || key instanceof RubyString)) { + throw Utils.createTypeError(context, "Expected string for map key"); } - - /* - * call-seq: - * Map.==(other) => boolean - * - * Compares this map to another. Maps are equal if they have identical key sets, - * and for each key, the values in both maps compare equal. Elements are - * compared as per normal Ruby semantics, by calling their :== methods (or - * performing a more efficient comparison for primitive types). - * - * Maps with dissimilar key types or value types/typeclasses are never equal, - * even if value comparison (for example, between integers and floats) would - * have otherwise indicated that every element has equal value. - */ - @JRubyMethod(name = "==") - public IRubyObject eq(ThreadContext context, IRubyObject _other) { - if (_other instanceof RubyHash) - return singleLevelHash(context).op_equal(context, _other); - RubyMap other = (RubyMap) _other; - if (this == other) return context.runtime.getTrue(); - if (!typeCompatible(other) || this.table.size() != other.table.size()) - return context.runtime.getFalse(); - for (IRubyObject key : table.keySet()) { - if (! other.table.containsKey(key)) - return context.runtime.getFalse(); - if (! other.table.get(key).equals(table.get(key))) - return context.runtime.getFalse(); - } - return context.runtime.getTrue(); + key = Utils.checkType(context, keyType, "key", key, (RubyModule) valueTypeClass); + value = Utils.checkType(context, valueType, "value", value, (RubyModule) valueTypeClass); + IRubyObject symbol; + if (valueType == FieldDescriptor.Type.ENUM + && Utils.isRubyNum(value) + && !(symbol = RubyEnum.lookup(context, valueTypeClass, value)).isNil()) { + value = symbol; } - - /* - * call-seq: - * Map.inspect => string - * - * Returns a string representing this map's elements. It will be formatted as - * "{key => value, key => value, ...}", with each key and value string - * representation computed by its own #inspect method. - */ - @JRubyMethod - public IRubyObject inspect() { - return singleLevelHash(getRuntime().getCurrentContext()).inspect(); + this.table.put(key, value); + return value; + } + + /* + * call-seq: + * Map.[](key) => value + * + * Accesses the element at the given key. Throws an exception if the key type is + * incorrect. Returns nil when the key is not present in the map. + */ + @JRubyMethod(name = "[]") + public IRubyObject index(ThreadContext context, IRubyObject key) { + key = Utils.symToString(key); + return Helpers.nullToNil(table.get(key), context.nil); + } + + /* + * call-seq: + * Map.==(other) => boolean + * + * Compares this map to another. Maps are equal if they have identical key sets, + * and for each key, the values in both maps compare equal. Elements are + * compared as per normal Ruby semantics, by calling their :== methods (or + * performing a more efficient comparison for primitive types). + * + * Maps with dissimilar key types or value types/typeclasses are never equal, + * even if value comparison (for example, between integers and floats) would + * have otherwise indicated that every element has equal value. + */ + @JRubyMethod(name = "==") + public IRubyObject eq(ThreadContext context, IRubyObject _other) { + if (_other instanceof RubyHash) return singleLevelHash(context).op_equal(context, _other); + RubyMap other = (RubyMap) _other; + if (this == other) return context.runtime.getTrue(); + if (!typeCompatible(other) || this.table.size() != other.table.size()) + return context.runtime.getFalse(); + for (IRubyObject key : table.keySet()) { + if (!other.table.containsKey(key)) return context.runtime.getFalse(); + if (!other.table.get(key).equals(table.get(key))) return context.runtime.getFalse(); } - - /* - * call-seq: - * Map.hash => hash_value - * - * Returns a hash value based on this map's contents. - */ - @JRubyMethod - public IRubyObject hash(ThreadContext context) { - try { - MessageDigest digest = MessageDigest.getInstance("SHA-256"); - for (IRubyObject key : table.keySet()) { - digest.update((byte) key.hashCode()); - digest.update((byte) table.get(key).hashCode()); - } - return context.runtime.newFixnum(ByteBuffer.wrap(digest.digest()).getLong()); - } catch (NoSuchAlgorithmException ignore) { - return context.runtime.newFixnum(System.identityHashCode(table)); - } + return context.runtime.getTrue(); + } + + /* + * call-seq: + * Map.inspect => string + * + * Returns a string representing this map's elements. It will be formatted as + * "{key => value, key => value, ...}", with each key and value string + * representation computed by its own #inspect method. + */ + @JRubyMethod + public IRubyObject inspect() { + return singleLevelHash(getRuntime().getCurrentContext()).inspect(); + } + + /* + * call-seq: + * Map.hash => hash_value + * + * Returns a hash value based on this map's contents. + */ + @JRubyMethod + public IRubyObject hash(ThreadContext context) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + for (IRubyObject key : table.keySet()) { + digest.update((byte) key.hashCode()); + digest.update((byte) table.get(key).hashCode()); + } + return context.runtime.newFixnum(ByteBuffer.wrap(digest.digest()).getLong()); + } catch (NoSuchAlgorithmException ignore) { + return context.runtime.newFixnum(System.identityHashCode(table)); } - - /* - * call-seq: - * Map.keys => [list_of_keys] - * - * Returns the list of keys contained in the map, in unspecified order. - */ - @JRubyMethod - public IRubyObject keys(ThreadContext context) { - return RubyArray.newArray(context.runtime, table.keySet()); + } + + /* + * call-seq: + * Map.keys => [list_of_keys] + * + * Returns the list of keys contained in the map, in unspecified order. + */ + @JRubyMethod + public IRubyObject keys(ThreadContext context) { + return RubyArray.newArray(context.runtime, table.keySet()); + } + + /* + * call-seq: + * Map.values => [list_of_values] + * + * Returns the list of values contained in the map, in unspecified order. + */ + @JRubyMethod + public IRubyObject values(ThreadContext context) { + return RubyArray.newArray(context.runtime, table.values()); + } + + /* + * call-seq: + * Map.clear + * + * Removes all entries from the map. + */ + @JRubyMethod + public IRubyObject clear(ThreadContext context) { + checkFrozen(); + table.clear(); + return context.nil; + } + + /* + * call-seq: + * Map.each(&block) + * + * Invokes &block on each |key, value| pair in the map, in unspecified order. + * Note that Map also includes Enumerable; map thus acts like a normal Ruby + * sequence. + */ + @JRubyMethod + public IRubyObject each(ThreadContext context, Block block) { + for (IRubyObject key : table.keySet()) { + block.yieldSpecific(context, key, table.get(key)); } - - /* - * call-seq: - * Map.values => [list_of_values] - * - * Returns the list of values contained in the map, in unspecified order. - */ - @JRubyMethod - public IRubyObject values(ThreadContext context) { - return RubyArray.newArray(context.runtime, table.values()); + return context.nil; + } + + /* + * call-seq: + * Map.delete(key) => old_value + * + * Deletes the value at the given key, if any, returning either the old value or + * nil if none was present. Throws an exception if the key is of the wrong type. + */ + @JRubyMethod + public IRubyObject delete(ThreadContext context, IRubyObject key) { + checkFrozen(); + return table.remove(key); + } + + /* + * call-seq: + * Map.has_key?(key) => bool + * + * Returns true if the given key is present in the map. Throws an exception if + * the key has the wrong type. + */ + @JRubyMethod(name = "has_key?") + public IRubyObject hasKey(ThreadContext context, IRubyObject key) { + return this.table.containsKey(key) ? context.runtime.getTrue() : context.runtime.getFalse(); + } + + /* + * call-seq: + * Map.length + * + * Returns the number of entries (key-value pairs) in the map. + */ + @JRubyMethod(name = {"length", "size"}) + public IRubyObject length(ThreadContext context) { + return context.runtime.newFixnum(this.table.size()); + } + + /* + * call-seq: + * Map.dup => new_map + * + * Duplicates this map with a shallow copy. References to all non-primitive + * element objects (e.g., submessages) are shared. + */ + @JRubyMethod + public IRubyObject dup(ThreadContext context) { + RubyMap newMap = newThisType(context); + for (Map.Entry entry : table.entrySet()) { + newMap.table.put(entry.getKey(), entry.getValue()); } - - /* - * call-seq: - * Map.clear - * - * Removes all entries from the map. - */ - @JRubyMethod - public IRubyObject clear(ThreadContext context) { - checkFrozen(); - table.clear(); - return context.nil; - } - - /* - * call-seq: - * Map.each(&block) - * - * Invokes &block on each |key, value| pair in the map, in unspecified order. - * Note that Map also includes Enumerable; map thus acts like a normal Ruby - * sequence. - */ - @JRubyMethod - public IRubyObject each(ThreadContext context, Block block) { - for (IRubyObject key : table.keySet()) { - block.yieldSpecific(context, key, table.get(key)); - } - return context.nil; - } - - /* - * call-seq: - * Map.delete(key) => old_value - * - * Deletes the value at the given key, if any, returning either the old value or - * nil if none was present. Throws an exception if the key is of the wrong type. - */ - @JRubyMethod - public IRubyObject delete(ThreadContext context, IRubyObject key) { - checkFrozen(); - return table.remove(key); - } - - /* - * call-seq: - * Map.has_key?(key) => bool - * - * Returns true if the given key is present in the map. Throws an exception if - * the key has the wrong type. - */ - @JRubyMethod(name = "has_key?") - public IRubyObject hasKey(ThreadContext context, IRubyObject key) { - return this.table.containsKey(key) ? context.runtime.getTrue() : context.runtime.getFalse(); - } - - /* - * call-seq: - * Map.length - * - * Returns the number of entries (key-value pairs) in the map. - */ - @JRubyMethod(name = {"length", "size"}) - public IRubyObject length(ThreadContext context) { - return context.runtime.newFixnum(this.table.size()); - } - - /* - * call-seq: - * Map.dup => new_map - * - * Duplicates this map with a shallow copy. References to all non-primitive - * element objects (e.g., submessages) are shared. - */ - @JRubyMethod - public IRubyObject dup(ThreadContext context) { - RubyMap newMap = newThisType(context); - for (Map.Entry entry : table.entrySet()) { - newMap.table.put(entry.getKey(), entry.getValue()); - } - return newMap; - } - - @JRubyMethod(name = "to_h") - public RubyHash toHash(ThreadContext context) { - Map mapForHash = new HashMap(); - - table.forEach((key, value) -> { - if (!value.isNil()) { - if (value.respondsTo("to_h")) { - value = Helpers.invoke(context, value, "to_h"); - } else if (value.respondsTo("to_a")) { - value = Helpers.invoke(context, value, "to_a"); - } - mapForHash.put(key, value); + return newMap; + } + + @JRubyMethod(name = "to_h") + public RubyHash toHash(ThreadContext context) { + Map mapForHash = new HashMap(); + + table.forEach( + (key, value) -> { + if (!value.isNil()) { + if (value.respondsTo("to_h")) { + value = Helpers.invoke(context, value, "to_h"); + } else if (value.respondsTo("to_a")) { + value = Helpers.invoke(context, value, "to_a"); } + mapForHash.put(key, value); + } }); - return RubyHash.newHash(context.runtime, mapForHash, context.nil); - } + return RubyHash.newHash(context.runtime, mapForHash, context.nil); + } - // Used by Google::Protobuf.deep_copy but not exposed directly. - protected IRubyObject deepCopy(ThreadContext context) { - RubyMap newMap = newThisType(context); - switch (valueType) { - case MESSAGE: - for (IRubyObject key : table.keySet()) { - RubyMessage message = (RubyMessage) table.get(key); - newMap.table.put(key.dup(), message.deepCopy(context)); - } - break; - default: - for (IRubyObject key : table.keySet()) { - newMap.table.put(key.dup(), table.get(key).dup()); - } + // Used by Google::Protobuf.deep_copy but not exposed directly. + protected IRubyObject deepCopy(ThreadContext context) { + RubyMap newMap = newThisType(context); + switch (valueType) { + case MESSAGE: + for (IRubyObject key : table.keySet()) { + RubyMessage message = (RubyMessage) table.get(key); + newMap.table.put(key.dup(), message.deepCopy(context)); } - return newMap; - } - - protected List build(ThreadContext context, RubyDescriptor descriptor, int depth, int recursionLimit) { - List list = new ArrayList(); - RubyClass rubyClass = (RubyClass) descriptor.msgclass(context); - FieldDescriptor keyField = descriptor.getField("key"); - FieldDescriptor valueField = descriptor.getField("value"); + break; + default: for (IRubyObject key : table.keySet()) { - RubyMessage mapMessage = (RubyMessage) rubyClass.newInstance(context, Block.NULL_BLOCK); - mapMessage.setField(context, keyField, key); - mapMessage.setField(context, valueField, table.get(key)); - list.add(mapMessage.build(context, depth + 1, recursionLimit)); + newMap.table.put(key.dup(), table.get(key).dup()); } - return list; } - - protected RubyMap mergeIntoSelf(final ThreadContext context, IRubyObject hashmap) { - if (hashmap instanceof RubyHash) { - ((RubyHash) hashmap).visitAll(context, new RubyHash.Visitor() { + return newMap; + } + + protected List build( + ThreadContext context, RubyDescriptor descriptor, int depth, int recursionLimit) { + List list = new ArrayList(); + RubyClass rubyClass = (RubyClass) descriptor.msgclass(context); + FieldDescriptor keyField = descriptor.getField("key"); + FieldDescriptor valueField = descriptor.getField("value"); + for (IRubyObject key : table.keySet()) { + RubyMessage mapMessage = (RubyMessage) rubyClass.newInstance(context, Block.NULL_BLOCK); + mapMessage.setField(context, keyField, key); + mapMessage.setField(context, valueField, table.get(key)); + list.add(mapMessage.build(context, depth + 1, recursionLimit)); + } + return list; + } + + protected RubyMap mergeIntoSelf(final ThreadContext context, IRubyObject hashmap) { + if (hashmap instanceof RubyHash) { + ((RubyHash) hashmap) + .visitAll( + context, + new RubyHash.Visitor() { @Override public void visit(IRubyObject key, IRubyObject val) { - if (val instanceof RubyHash && !valueTypeClass.isNil()) { - val = ((RubyClass) valueTypeClass).newInstance(context, val, Block.NULL_BLOCK); - } - indexSet(context, key, val); + if (val instanceof RubyHash && !valueTypeClass.isNil()) { + val = ((RubyClass) valueTypeClass).newInstance(context, val, Block.NULL_BLOCK); + } + indexSet(context, key, val); } - }, null); - } else if (hashmap instanceof RubyMap) { - RubyMap other = (RubyMap) hashmap; - if (!typeCompatible(other)) { - throw Utils.createTypeError(context, "Attempt to merge Map with mismatching types"); - } - } else { - throw Utils.createTypeError(context, "Unknown type merging into Map"); - } - return this; - } - - protected boolean typeCompatible(RubyMap other) { - return this.keyType == other.keyType && - this.valueType == other.valueType && - this.valueTypeClass == other.valueTypeClass; - } - - private RubyMap newThisType(ThreadContext context) { - RubyMap newMap; - if (needTypeclass(valueType)) { - newMap = (RubyMap) metaClass.newInstance(context, - Utils.fieldTypeToRuby(context, keyType), - Utils.fieldTypeToRuby(context, valueType), - valueTypeClass, Block.NULL_BLOCK); - } else { - newMap = (RubyMap) metaClass.newInstance(context, - Utils.fieldTypeToRuby(context, keyType), - Utils.fieldTypeToRuby(context, valueType), - Block.NULL_BLOCK); - } - newMap.table = new HashMap(); - return newMap; + }, + null); + } else if (hashmap instanceof RubyMap) { + RubyMap other = (RubyMap) hashmap; + if (!typeCompatible(other)) { + throw Utils.createTypeError(context, "Attempt to merge Map with mismatching types"); + } + } else { + throw Utils.createTypeError(context, "Unknown type merging into Map"); } - - /* - * toHash calls toHash on values, for some camparisons we only need - * a hash with the original objects still as values - */ - private RubyHash singleLevelHash(ThreadContext context) { - return RubyHash.newHash(context.runtime, table, context.nil); + return this; + } + + protected boolean typeCompatible(RubyMap other) { + return this.keyType == other.keyType + && this.valueType == other.valueType + && this.valueTypeClass == other.valueTypeClass; + } + + private RubyMap newThisType(ThreadContext context) { + RubyMap newMap; + if (needTypeclass(valueType)) { + newMap = + (RubyMap) + metaClass.newInstance( + context, + Utils.fieldTypeToRuby(context, keyType), + Utils.fieldTypeToRuby(context, valueType), + valueTypeClass, + Block.NULL_BLOCK); + } else { + newMap = + (RubyMap) + metaClass.newInstance( + context, + Utils.fieldTypeToRuby(context, keyType), + Utils.fieldTypeToRuby(context, valueType), + Block.NULL_BLOCK); } - - private boolean needTypeclass(FieldDescriptor.Type type) { - switch(type) { - case MESSAGE: - case ENUM: - return true; - default: - return false; - } + newMap.table = new HashMap(); + return newMap; + } + + /* + * toHash calls toHash on values, for some camparisons we only need + * a hash with the original objects still as values + */ + private RubyHash singleLevelHash(ThreadContext context) { + return RubyHash.newHash(context.runtime, table, context.nil); + } + + private boolean needTypeclass(FieldDescriptor.Type type) { + switch (type) { + case MESSAGE: + case ENUM: + return true; + default: + return false; } + } - private FieldDescriptor.Type keyType; - private FieldDescriptor.Type valueType; - private IRubyObject valueTypeClass; - private Map table; - private boolean keyTypeIsString = false; + private FieldDescriptor.Type keyType; + private FieldDescriptor.Type valueType; + private IRubyObject valueTypeClass; + private Map table; + private boolean keyTypeIsString = false; } diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java index 2167f15dc473..301b95798215 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java @@ -32,19 +32,25 @@ package com.google.protobuf.jruby; +import com.google.protobuf.ByteString; +import com.google.protobuf.CodedInputStream; import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.EnumDescriptor; import com.google.protobuf.Descriptors.EnumValueDescriptor; import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.Descriptors.OneofDescriptor; -import com.google.protobuf.ByteString; -import com.google.protobuf.CodedInputStream; import com.google.protobuf.DynamicMessage; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; import com.google.protobuf.UnknownFieldSet; import com.google.protobuf.util.JsonFormat; +import java.nio.ByteBuffer; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.jruby.*; import org.jruby.anno.JRubyMethod; import org.jruby.exceptions.RaiseException; @@ -54,1297 +60,1405 @@ import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.ByteList; -import java.nio.ByteBuffer; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - public class RubyMessage extends RubyObject { - private final String DEFAULT_VALUE = "google.protobuf.FieldDescriptorProto.default_value"; - private final String TYPE = "type"; - - public RubyMessage(Ruby runtime, RubyClass klazz, Descriptor descriptor) { - super(runtime, klazz); - - this.descriptor = descriptor; - this.cRepeatedField = (RubyClass) runtime.getClassFromPath("Google::Protobuf::RepeatedField"); - this.cMap = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Map"); - this.builder = DynamicMessage.newBuilder(descriptor); - this.fields = new HashMap(); - this.oneofCases = new HashMap(); - this.proto3 = descriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO3; - } + private final String DEFAULT_VALUE = "google.protobuf.FieldDescriptorProto.default_value"; + private final String TYPE = "type"; + + public RubyMessage(Ruby runtime, RubyClass klazz, Descriptor descriptor) { + super(runtime, klazz); + + this.descriptor = descriptor; + this.cRepeatedField = (RubyClass) runtime.getClassFromPath("Google::Protobuf::RepeatedField"); + this.cMap = (RubyClass) runtime.getClassFromPath("Google::Protobuf::Map"); + this.builder = DynamicMessage.newBuilder(descriptor); + this.fields = new HashMap(); + this.oneofCases = new HashMap(); + this.proto3 = descriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO3; + } + + /* + * call-seq: + * Message.new(kwargs) => new_message + * + * Creates a new instance of the given message class. Keyword arguments may be + * provided with keywords corresponding to field names. + * + * Note that no literal Message class exists. Only concrete classes per message + * type exist, as provided by the #msgclass method on Descriptors after they + * have been added to a pool. The method definitions described here on the + * Message class are provided on each concrete message class. + */ + @JRubyMethod(optional = 1) + public IRubyObject initialize(final ThreadContext context, IRubyObject[] args) { + final Ruby runtime = context.runtime; + if (args.length == 1) { + if (!(args[0] instanceof RubyHash)) { + throw runtime.newArgumentError("expected Hash arguments."); + } + RubyHash hash = args[0].convertToHash(); + hash.visitAll( + context, + new RubyHash.Visitor() { + @Override + public void visit(IRubyObject key, IRubyObject value) { + if (!(key instanceof RubySymbol) && !(key instanceof RubyString)) { + throw Utils.createTypeError( + context, "Expected string or symbols as hash keys in initialization map."); + } + final FieldDescriptor fieldDescriptor = + findField(context, key, ignoreUnknownFieldsOnInit); + + if (value == null || value.isNil()) return; + + if (fieldDescriptor.isMapField()) { + if (!(value instanceof RubyHash)) + throw runtime.newArgumentError( + "Expected Hash object as initializer value for map field '" + + key.asJavaString() + + "' (given " + + value.getMetaClass() + + ")."); + + final RubyMap map = newMapForField(context, fieldDescriptor); + map.mergeIntoSelf(context, value); + fields.put(fieldDescriptor, map); + } else if (fieldDescriptor.isRepeated()) { + if (!(value instanceof RubyArray)) + throw runtime.newArgumentError( + "Expected array as initializer value for repeated field '" + + key.asJavaString() + + "' (given " + + value.getMetaClass() + + ")."); + fields.put(fieldDescriptor, rubyToRepeatedField(context, fieldDescriptor, value)); + } else { + OneofDescriptor oneof = fieldDescriptor.getContainingOneof(); + if (oneof != null) { + oneofCases.put(oneof, fieldDescriptor); + } - /* - * call-seq: - * Message.new(kwargs) => new_message - * - * Creates a new instance of the given message class. Keyword arguments may be - * provided with keywords corresponding to field names. - * - * Note that no literal Message class exists. Only concrete classes per message - * type exist, as provided by the #msgclass method on Descriptors after they - * have been added to a pool. The method definitions described here on the - * Message class are provided on each concrete message class. - */ - @JRubyMethod(optional = 1) - public IRubyObject initialize(final ThreadContext context, IRubyObject[] args) { - final Ruby runtime = context.runtime; - if (args.length == 1) { - if (!(args[0] instanceof RubyHash)) { - throw runtime.newArgumentError("expected Hash arguments."); - } - RubyHash hash = args[0].convertToHash(); - hash.visitAll(context, new RubyHash.Visitor() { - @Override - public void visit(IRubyObject key, IRubyObject value) { - if (!(key instanceof RubySymbol) && !(key instanceof RubyString)) { - throw Utils.createTypeError(context, - "Expected string or symbols as hash keys in initialization map."); - } - final FieldDescriptor fieldDescriptor = findField(context, key, ignoreUnknownFieldsOnInit); - - if (value == null || value.isNil()) return; - - if (fieldDescriptor.isMapField()) { - if (!(value instanceof RubyHash)) - throw runtime.newArgumentError("Expected Hash object as initializer value for map field '" + key.asJavaString() + "' (given " + value.getMetaClass() + ")."); - - final RubyMap map = newMapForField(context, fieldDescriptor); - map.mergeIntoSelf(context, value); - fields.put(fieldDescriptor, map); - } else if (fieldDescriptor.isRepeated()) { - if (!(value instanceof RubyArray)) - throw runtime.newArgumentError("Expected array as initializer value for repeated field '" + key.asJavaString() + "' (given " + value.getMetaClass() + ")."); - fields.put(fieldDescriptor, rubyToRepeatedField(context, fieldDescriptor, value)); - } else { - OneofDescriptor oneof = fieldDescriptor.getContainingOneof(); - if (oneof != null) { - oneofCases.put(oneof, fieldDescriptor); - } - - if (value instanceof RubyHash && fieldDescriptor.getType() == FieldDescriptor.Type.MESSAGE) { - RubyDescriptor descriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); - RubyClass typeClass = (RubyClass) descriptor.msgclass(context); - value = (IRubyObject) typeClass.newInstance(context, value, Block.NULL_BLOCK); - fields.put(fieldDescriptor, value); - } else { - indexSet(context, key, value); - } - - } + if (value instanceof RubyHash + && fieldDescriptor.getType() == FieldDescriptor.Type.MESSAGE) { + RubyDescriptor descriptor = + (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); + RubyClass typeClass = (RubyClass) descriptor.msgclass(context); + value = (IRubyObject) typeClass.newInstance(context, value, Block.NULL_BLOCK); + fields.put(fieldDescriptor, value); + } else { + indexSet(context, key, value); } - }, null); - } - return this; + } + } + }, + null); } + return this; + } + + /* + * call-seq: + * Message.[]=(index, value) + * + * Sets a field's value by field name. The provided field name should be a + * string. + */ + @JRubyMethod(name = "[]=") + public IRubyObject indexSet(ThreadContext context, IRubyObject fieldName, IRubyObject value) { + FieldDescriptor fieldDescriptor = findField(context, fieldName); + return setFieldInternal(context, fieldDescriptor, value); + } + + /* + * call-seq: + * Message.[](index) => value + * + * Accesses a field's value by field name. The provided field name should be a + * string. + */ + @JRubyMethod(name = "[]") + public IRubyObject index(ThreadContext context, IRubyObject fieldName) { + FieldDescriptor fieldDescriptor = findField(context, fieldName); + return getFieldInternal(context, fieldDescriptor); + } + + /* + * call-seq: + * Message.inspect => string + * + * Returns a human-readable string representing this message. It will be + * formatted as "". Each + * field's value is represented according to its own #inspect method. + */ + @JRubyMethod(name = {"inspect", "to_s"}) + public IRubyObject inspect() { + ThreadContext context = getRuntime().getCurrentContext(); + String cname = metaClass.getName(); + String colon = ": "; + String comma = ", "; + StringBuilder sb = new StringBuilder("<"); + boolean addComma = false; + + sb.append(cname).append(colon); + + for (FieldDescriptor fd : descriptor.getFields()) { + if (fd.hasPresence() && !fields.containsKey(fd)) { + continue; + } + if (addComma) { + sb.append(comma); + } else { + addComma = true; + } - /* - * call-seq: - * Message.[]=(index, value) - * - * Sets a field's value by field name. The provided field name should be a - * string. - */ - @JRubyMethod(name = "[]=") - public IRubyObject indexSet(ThreadContext context, IRubyObject fieldName, IRubyObject value) { - FieldDescriptor fieldDescriptor = findField(context, fieldName); - return setFieldInternal(context, fieldDescriptor, value); - } + sb.append(fd.getName()).append(colon); - /* - * call-seq: - * Message.[](index) => value - * - * Accesses a field's value by field name. The provided field name should be a - * string. - */ - @JRubyMethod(name = "[]") - public IRubyObject index(ThreadContext context, IRubyObject fieldName) { - FieldDescriptor fieldDescriptor = findField(context, fieldName); - return getFieldInternal(context, fieldDescriptor); + IRubyObject value = getFieldInternal(context, fd); + if (value instanceof RubyBoolean) { + // Booleans don't implement internal "inspect" methods so have to call handle them manually + sb.append(value.isTrue() ? "true" : "false"); + } else { + sb.append(value.inspect()); + } + } + sb.append(">"); + + return context.runtime.newString(sb.toString()); + } + + /* + * call-seq: + * Message.hash => hash_value + * + * Returns a hash value that represents this message's field values. + */ + @JRubyMethod + public IRubyObject hash(ThreadContext context) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + for (FieldDescriptor fd : descriptor.getFields()) { + digest.update((byte) getFieldInternal(context, fd).hashCode()); + } + return context.runtime.newFixnum(ByteBuffer.wrap(digest.digest()).getLong()); + } catch (NoSuchAlgorithmException ignore) { + return context.runtime.newFixnum(System.identityHashCode(this)); + } + } + + /* + * call-seq: + * Message.==(other) => boolean + * + * Performs a deep comparison of this message with another. Messages are equal + * if they have the same type and if each field is equal according to the :== + * method's semantics (a more efficient comparison may actually be done if the + * field is of a primitive type). + */ + @JRubyMethod(name = {"==", "eql?"}) + public IRubyObject eq(ThreadContext context, IRubyObject other) { + Ruby runtime = context.runtime; + if (!(other instanceof RubyMessage)) return runtime.getFalse(); + RubyMessage message = (RubyMessage) other; + if (descriptor != message.descriptor) { + return runtime.getFalse(); } - /* - * call-seq: - * Message.inspect => string - * - * Returns a human-readable string representing this message. It will be - * formatted as "". Each - * field's value is represented according to its own #inspect method. - */ - @JRubyMethod(name = {"inspect", "to_s"}) - public IRubyObject inspect() { - ThreadContext context = getRuntime().getCurrentContext(); - String cname = metaClass.getName(); - String colon = ": "; - String comma = ", "; - StringBuilder sb = new StringBuilder("<"); - boolean addComma = false; - - sb.append(cname).append(colon); - - for (FieldDescriptor fd : descriptor.getFields()) { - if (fd.hasPresence() && !fields.containsKey(fd)) { - continue; - } - if (addComma) { - sb.append(comma); - } else { - addComma = true; - } - - sb.append(fd.getName()).append(colon); + for (FieldDescriptor fdef : descriptor.getFields()) { + IRubyObject thisVal = getFieldInternal(context, fdef); + IRubyObject thatVal = message.getFieldInternal(context, fdef); + IRubyObject ret = thisVal.callMethod(context, "==", thatVal); + if (!ret.isTrue()) { + return runtime.getFalse(); + } + } + return runtime.getTrue(); + } + + /* + * call-seq: + * Message.respond_to?(method_name, search_private_and_protected) => boolean + * + * Parallels method_missing, returning true when this object implements a method with the given + * method_name. + */ + @JRubyMethod(name = "respond_to?", required = 1, optional = 1) + public IRubyObject respondTo(ThreadContext context, IRubyObject[] args) { + String methodName = args[0].asJavaString(); + if (descriptor.findFieldByName(methodName) != null) { + return context.runtime.getTrue(); + } + RubyDescriptor rubyDescriptor = (RubyDescriptor) getDescriptor(context, metaClass); + IRubyObject oneofDescriptor = rubyDescriptor.lookupOneof(context, args[0]); + if (!oneofDescriptor.isNil()) { + return context.runtime.getTrue(); + } + if (methodName.startsWith(CLEAR_PREFIX)) { + String strippedMethodName = methodName.substring(6); + oneofDescriptor = + rubyDescriptor.lookupOneof(context, context.runtime.newSymbol(strippedMethodName)); + if (!oneofDescriptor.isNil()) { + return context.runtime.getTrue(); + } - IRubyObject value = getFieldInternal(context, fd); - if (value instanceof RubyBoolean) { - // Booleans don't implement internal "inspect" methods so have to call handle them manually - sb.append(value.isTrue() ? "true" : "false"); - } else { - sb.append(value.inspect()); - } + if (descriptor.findFieldByName(strippedMethodName) != null) { + return context.runtime.getTrue(); + } + } + if (methodName.startsWith(HAS_PREFIX) && methodName.endsWith(QUESTION_MARK)) { + String strippedMethodName = methodName.substring(4, methodName.length() - 1); + FieldDescriptor fieldDescriptor = descriptor.findFieldByName(strippedMethodName); + if (fieldDescriptor != null + && (!proto3 + || fieldDescriptor.getContainingOneof() == null + || fieldDescriptor.getContainingOneof().isSynthetic()) + && fieldDescriptor.hasPresence()) { + return context.runtime.getTrue(); + } + oneofDescriptor = + rubyDescriptor.lookupOneof( + context, RubyString.newString(context.runtime, strippedMethodName)); + if (!oneofDescriptor.isNil()) { + return context.runtime.getTrue(); + } + } + if (methodName.endsWith(AS_VALUE_SUFFIX)) { + FieldDescriptor fieldDescriptor = + descriptor.findFieldByName(methodName.substring(0, methodName.length() - 9)); + if (fieldDescriptor != null && isWrappable(fieldDescriptor)) { + return context.runtime.getTrue(); + } + } + if (methodName.endsWith(CONST_SUFFIX)) { + FieldDescriptor fieldDescriptor = + descriptor.findFieldByName(methodName.substring(0, methodName.length() - 6)); + if (fieldDescriptor != null) { + if (fieldDescriptor.getType() == FieldDescriptor.Type.ENUM) { + return context.runtime.getTrue(); } - sb.append(">"); - - return context.runtime.newString(sb.toString()); + } } - - /* - * call-seq: - * Message.hash => hash_value - * - * Returns a hash value that represents this message's field values. - */ - @JRubyMethod - public IRubyObject hash(ThreadContext context) { - try { - MessageDigest digest = MessageDigest.getInstance("SHA-256"); - for (FieldDescriptor fd : descriptor.getFields()) { - digest.update((byte) getFieldInternal(context, fd).hashCode()); - } - return context.runtime.newFixnum(ByteBuffer.wrap(digest.digest()).getLong()); - } catch (NoSuchAlgorithmException ignore) { - return context.runtime.newFixnum(System.identityHashCode(this)); + if (methodName.endsWith(Utils.EQUAL_SIGN)) { + String strippedMethodName = methodName.substring(0, methodName.length() - 1); + FieldDescriptor fieldDescriptor = descriptor.findFieldByName(strippedMethodName); + if (fieldDescriptor != null) { + return context.runtime.getTrue(); + } + if (strippedMethodName.endsWith(AS_VALUE_SUFFIX)) { + strippedMethodName = methodName.substring(0, strippedMethodName.length() - 9); + fieldDescriptor = descriptor.findFieldByName(strippedMethodName); + if (fieldDescriptor != null && isWrappable(fieldDescriptor)) { + return context.runtime.getTrue(); } + } } - - /* - * call-seq: - * Message.==(other) => boolean - * - * Performs a deep comparison of this message with another. Messages are equal - * if they have the same type and if each field is equal according to the :== - * method's semantics (a more efficient comparison may actually be done if the - * field is of a primitive type). - */ - @JRubyMethod(name = {"==", "eql?"}) - public IRubyObject eq(ThreadContext context, IRubyObject other) { - Ruby runtime = context.runtime; - if (!(other instanceof RubyMessage)) - return runtime.getFalse(); - RubyMessage message = (RubyMessage) other; - if (descriptor != message.descriptor) { - return runtime.getFalse(); + boolean includePrivate = false; + if (args.length == 2) { + includePrivate = context.runtime.getTrue().equals(args[1]); + } + return metaClass.respondsToMethod(methodName, includePrivate) + ? context.runtime.getTrue() + : context.runtime.getFalse(); + } + + /* + * call-seq: + * Message.method_missing(*args) + * + * Provides accessors and setters and methods to clear and check for presence of + * message fields according to their field names. + * + * For any field whose name does not conflict with a built-in method, an + * accessor is provided with the same name as the field, and a setter is + * provided with the name of the field plus the '=' suffix. Thus, given a + * message instance 'msg' with field 'foo', the following code is valid: + * + * msg.foo = 42 + * puts msg.foo + * + * This method also provides read-only accessors for oneofs. If a oneof exists + * with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to + * the name of the field in that oneof that is currently set, or nil if none. + * + * It also provides methods of the form 'clear_fieldname' to clear the value + * of the field 'fieldname'. For basic data types, this will set the default + * value of the field. + * + * Additionally, it provides methods of the form 'has_fieldname?', which returns + * true if the field 'fieldname' is set in the message object, else false. For + * 'proto3' syntax, calling this for a basic type field will result in an error. + */ + @JRubyMethod(name = "method_missing", rest = true) + public IRubyObject methodMissing(ThreadContext context, IRubyObject[] args) { + Ruby runtime = context.runtime; + String methodName = args[0].asJavaString(); + RubyDescriptor rubyDescriptor = (RubyDescriptor) getDescriptor(context, metaClass); + + if (args.length == 1) { + // If we find a Oneof return it's name (use lookupOneof because it has an index) + IRubyObject oneofDescriptor = rubyDescriptor.lookupOneof(context, args[0]); + + if (!oneofDescriptor.isNil()) { + RubyOneofDescriptor rubyOneofDescriptor = (RubyOneofDescriptor) oneofDescriptor; + OneofDescriptor ood = rubyOneofDescriptor.getDescriptor(); + + // Check to see if we set this through ruby + FieldDescriptor fieldDescriptor = oneofCases.get(ood); + + if (fieldDescriptor == null) { + // See if we set this from decoding a message + fieldDescriptor = builder.getOneofFieldDescriptor(ood); + + if (fieldDescriptor == null) { + return context.nil; + } else { + // Cache it so we don't need to do multiple checks next time + oneofCases.put(ood, fieldDescriptor); + return runtime.newSymbol(fieldDescriptor.getName()); + } + } else { + return runtime.newSymbol(fieldDescriptor.getName()); } + } - for (FieldDescriptor fdef : descriptor.getFields()) { - IRubyObject thisVal = getFieldInternal(context, fdef); - IRubyObject thatVal = message.getFieldInternal(context, fdef); - IRubyObject ret = thisVal.callMethod(context, "==", thatVal); - if (!ret.isTrue()) { - return runtime.getFalse(); - } - } - return runtime.getTrue(); - } + // If we find a field return its value + FieldDescriptor fieldDescriptor = descriptor.findFieldByName(methodName); - /* - * call-seq: - * Message.respond_to?(method_name, search_private_and_protected) => boolean - * - * Parallels method_missing, returning true when this object implements a method with the given - * method_name. - */ - @JRubyMethod(name="respond_to?", required = 1, optional = 1) - public IRubyObject respondTo(ThreadContext context, IRubyObject [] args) { - String methodName = args[0].asJavaString(); - if (descriptor.findFieldByName(methodName) != null) { - return context.runtime.getTrue(); - } - RubyDescriptor rubyDescriptor = (RubyDescriptor) getDescriptor(context, metaClass); - IRubyObject oneofDescriptor = rubyDescriptor.lookupOneof(context, args[0]); + if (fieldDescriptor != null) { + return getFieldInternal(context, fieldDescriptor); + } + + if (methodName.startsWith(CLEAR_PREFIX)) { + methodName = methodName.substring(6); + oneofDescriptor = rubyDescriptor.lookupOneof(context, runtime.newSymbol(methodName)); if (!oneofDescriptor.isNil()) { - return context.runtime.getTrue(); + fieldDescriptor = oneofCases.get(((RubyOneofDescriptor) oneofDescriptor).getDescriptor()); + if (fieldDescriptor == null) { + // Clearing an already cleared oneof; return here to avoid NoMethodError. + return context.nil; + } } - if (methodName.startsWith(CLEAR_PREFIX)) { - String strippedMethodName = methodName.substring(6); - oneofDescriptor = rubyDescriptor.lookupOneof(context, context.runtime.newSymbol(strippedMethodName)); - if (!oneofDescriptor.isNil()) { - return context.runtime.getTrue(); - } - if (descriptor.findFieldByName(strippedMethodName) != null) { - return context.runtime.getTrue(); - } - } - if (methodName.startsWith(HAS_PREFIX) && methodName.endsWith(QUESTION_MARK)) { - String strippedMethodName = methodName.substring(4, methodName.length() - 1); - FieldDescriptor fieldDescriptor = descriptor.findFieldByName(strippedMethodName); - if (fieldDescriptor != null && - (!proto3 || fieldDescriptor.getContainingOneof() == null || fieldDescriptor - .getContainingOneof().isSynthetic()) && - fieldDescriptor.hasPresence()) { - return context.runtime.getTrue(); - } - oneofDescriptor = rubyDescriptor.lookupOneof(context, RubyString.newString(context.runtime, strippedMethodName)); - if (!oneofDescriptor.isNil()) { - return context.runtime.getTrue(); - } - } - if (methodName.endsWith(AS_VALUE_SUFFIX)) { - FieldDescriptor fieldDescriptor = descriptor.findFieldByName( - methodName.substring(0, methodName.length() - 9)); - if (fieldDescriptor != null && isWrappable(fieldDescriptor)) { - return context.runtime.getTrue(); - } + if (fieldDescriptor == null) { + fieldDescriptor = descriptor.findFieldByName(methodName); } - if (methodName.endsWith(CONST_SUFFIX)) { - FieldDescriptor fieldDescriptor = descriptor.findFieldByName( - methodName.substring(0, methodName.length() - 6)); - if (fieldDescriptor != null) { - if (fieldDescriptor.getType() == FieldDescriptor.Type.ENUM) { - return context.runtime.getTrue(); - } - } - } - if (methodName.endsWith(Utils.EQUAL_SIGN)) { - String strippedMethodName = methodName.substring(0, methodName.length() - 1); - FieldDescriptor fieldDescriptor = descriptor.findFieldByName(strippedMethodName); - if (fieldDescriptor != null) { - return context.runtime.getTrue(); - } - if (strippedMethodName.endsWith(AS_VALUE_SUFFIX)) { - strippedMethodName = methodName.substring(0, strippedMethodName.length() - 9); - fieldDescriptor = descriptor.findFieldByName(strippedMethodName); - if (fieldDescriptor != null && isWrappable(fieldDescriptor)) { - return context.runtime.getTrue(); - } - } - } - boolean includePrivate = false; - if (args.length == 2) { - includePrivate = context.runtime.getTrue().equals(args[1]); - } - return metaClass.respondsToMethod(methodName, includePrivate) ? context.runtime.getTrue() : context.runtime.getFalse(); - } - /* - * call-seq: - * Message.method_missing(*args) - * - * Provides accessors and setters and methods to clear and check for presence of - * message fields according to their field names. - * - * For any field whose name does not conflict with a built-in method, an - * accessor is provided with the same name as the field, and a setter is - * provided with the name of the field plus the '=' suffix. Thus, given a - * message instance 'msg' with field 'foo', the following code is valid: - * - * msg.foo = 42 - * puts msg.foo - * - * This method also provides read-only accessors for oneofs. If a oneof exists - * with name 'my_oneof', then msg.my_oneof will return a Ruby symbol equal to - * the name of the field in that oneof that is currently set, or nil if none. - * - * It also provides methods of the form 'clear_fieldname' to clear the value - * of the field 'fieldname'. For basic data types, this will set the default - * value of the field. - * - * Additionally, it provides methods of the form 'has_fieldname?', which returns - * true if the field 'fieldname' is set in the message object, else false. For - * 'proto3' syntax, calling this for a basic type field will result in an error. - */ - @JRubyMethod(name = "method_missing", rest = true) - public IRubyObject methodMissing(ThreadContext context, IRubyObject[] args) { - Ruby runtime = context.runtime; - String methodName = args[0].asJavaString(); - RubyDescriptor rubyDescriptor = (RubyDescriptor) getDescriptor(context, metaClass); - - if (args.length == 1) { - // If we find a Oneof return it's name (use lookupOneof because it has an index) - IRubyObject oneofDescriptor = rubyDescriptor.lookupOneof(context, args[0]); - - if (!oneofDescriptor.isNil()) { - RubyOneofDescriptor rubyOneofDescriptor = (RubyOneofDescriptor) oneofDescriptor; - OneofDescriptor ood = rubyOneofDescriptor.getDescriptor(); - - // Check to see if we set this through ruby - FieldDescriptor fieldDescriptor = oneofCases.get(ood); - - if (fieldDescriptor == null) { - // See if we set this from decoding a message - fieldDescriptor = builder.getOneofFieldDescriptor(ood); - - if (fieldDescriptor == null) { - return context.nil; - } else { - // Cache it so we don't need to do multiple checks next time - oneofCases.put(ood, fieldDescriptor); - return runtime.newSymbol(fieldDescriptor.getName()); - } - } else { - return runtime.newSymbol(fieldDescriptor.getName()); - } - } - - // If we find a field return its value - FieldDescriptor fieldDescriptor = descriptor.findFieldByName(methodName); - - if (fieldDescriptor != null) { - return getFieldInternal(context, fieldDescriptor); - } - - if (methodName.startsWith(CLEAR_PREFIX)) { - methodName = methodName.substring(6); - oneofDescriptor = rubyDescriptor.lookupOneof(context, runtime.newSymbol(methodName)); - if (!oneofDescriptor.isNil()) { - fieldDescriptor = oneofCases.get(((RubyOneofDescriptor) oneofDescriptor).getDescriptor()); - if (fieldDescriptor == null) { - // Clearing an already cleared oneof; return here to avoid NoMethodError. - return context.nil; - } - } - - if (fieldDescriptor == null) { - fieldDescriptor = descriptor.findFieldByName(methodName); - } - - if (fieldDescriptor != null) { - return clearFieldInternal(context, fieldDescriptor); - } + if (fieldDescriptor != null) { + return clearFieldInternal(context, fieldDescriptor); + } - } else if (methodName.startsWith(HAS_PREFIX) && methodName.endsWith(QUESTION_MARK)) { - methodName = methodName.substring(4, methodName.length() - 1); // Trim "has_" and "?" off the field name - oneofDescriptor = rubyDescriptor.lookupOneof(context, runtime.newSymbol(methodName)); - if (!oneofDescriptor.isNil()) { - RubyOneofDescriptor rubyOneofDescriptor = (RubyOneofDescriptor) oneofDescriptor; - return oneofCases.containsKey(rubyOneofDescriptor.getDescriptor()) ? runtime.getTrue() : runtime.getFalse(); - } + } else if (methodName.startsWith(HAS_PREFIX) && methodName.endsWith(QUESTION_MARK)) { + methodName = + methodName.substring( + 4, methodName.length() - 1); // Trim "has_" and "?" off the field name + oneofDescriptor = rubyDescriptor.lookupOneof(context, runtime.newSymbol(methodName)); + if (!oneofDescriptor.isNil()) { + RubyOneofDescriptor rubyOneofDescriptor = (RubyOneofDescriptor) oneofDescriptor; + return oneofCases.containsKey(rubyOneofDescriptor.getDescriptor()) + ? runtime.getTrue() + : runtime.getFalse(); + } - fieldDescriptor = descriptor.findFieldByName(methodName); + fieldDescriptor = descriptor.findFieldByName(methodName); - if (fieldDescriptor != null && - (!proto3 || fieldDescriptor.getContainingOneof() == null || fieldDescriptor - .getContainingOneof().isSynthetic()) && - fieldDescriptor.hasPresence()) { - return fields.containsKey(fieldDescriptor) ? runtime.getTrue() - : runtime.getFalse(); - } + if (fieldDescriptor != null + && (!proto3 + || fieldDescriptor.getContainingOneof() == null + || fieldDescriptor.getContainingOneof().isSynthetic()) + && fieldDescriptor.hasPresence()) { + return fields.containsKey(fieldDescriptor) ? runtime.getTrue() : runtime.getFalse(); + } - } else if (methodName.endsWith(AS_VALUE_SUFFIX)) { - methodName = methodName.substring(0, methodName.length() - 9); - fieldDescriptor = descriptor.findFieldByName(methodName); + } else if (methodName.endsWith(AS_VALUE_SUFFIX)) { + methodName = methodName.substring(0, methodName.length() - 9); + fieldDescriptor = descriptor.findFieldByName(methodName); - if (fieldDescriptor != null && isWrappable(fieldDescriptor)) { - IRubyObject value = getFieldInternal(context, fieldDescriptor); + if (fieldDescriptor != null && isWrappable(fieldDescriptor)) { + IRubyObject value = getFieldInternal(context, fieldDescriptor); - if (!value.isNil() && value instanceof RubyMessage) { - return ((RubyMessage) value).index(context, runtime.newString("value")); - } + if (!value.isNil() && value instanceof RubyMessage) { + return ((RubyMessage) value).index(context, runtime.newString("value")); + } - return value; - } + return value; + } - } else if (methodName.endsWith(CONST_SUFFIX)) { - methodName = methodName.substring(0, methodName.length() - 6); - fieldDescriptor = descriptor.findFieldByName(methodName); - if (fieldDescriptor != null && fieldDescriptor.getType() == FieldDescriptor.Type.ENUM) { - IRubyObject enumValue = getFieldInternal(context, fieldDescriptor); - - if (!enumValue.isNil()) { - EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType(); - if (enumValue instanceof RubyRepeatedField) { - RubyArray values = (RubyArray) ((RubyRepeatedField) enumValue).toArray(context); - RubyArray retValues = runtime.newArray(values.getLength()); - for (int i = 0; i < values.getLength(); i++) { - String val = values.eltInternal(i).toString(); - retValues.store((long) i, runtime.newFixnum(enumDescriptor.findValueByName(val).getNumber())); - } - return retValues; - } - - return runtime.newFixnum(enumDescriptor.findValueByName(enumValue.asJavaString()).getNumber()); - } - } + } else if (methodName.endsWith(CONST_SUFFIX)) { + methodName = methodName.substring(0, methodName.length() - 6); + fieldDescriptor = descriptor.findFieldByName(methodName); + if (fieldDescriptor != null && fieldDescriptor.getType() == FieldDescriptor.Type.ENUM) { + IRubyObject enumValue = getFieldInternal(context, fieldDescriptor); + + if (!enumValue.isNil()) { + EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType(); + if (enumValue instanceof RubyRepeatedField) { + RubyArray values = (RubyArray) ((RubyRepeatedField) enumValue).toArray(context); + RubyArray retValues = runtime.newArray(values.getLength()); + for (int i = 0; i < values.getLength(); i++) { + String val = values.eltInternal(i).toString(); + retValues.store( + (long) i, runtime.newFixnum(enumDescriptor.findValueByName(val).getNumber())); + } + return retValues; } - } else if (args.length == 2 && methodName.endsWith(Utils.EQUAL_SIGN)) { + return runtime.newFixnum( + enumDescriptor.findValueByName(enumValue.asJavaString()).getNumber()); + } + } + } - methodName = methodName.substring(0, methodName.length() - 1); // Trim equals sign - FieldDescriptor fieldDescriptor = descriptor.findFieldByName(methodName); - if (fieldDescriptor != null) { - return setFieldInternal(context, fieldDescriptor, args[1]); - } + } else if (args.length == 2 && methodName.endsWith(Utils.EQUAL_SIGN)) { - IRubyObject oneofDescriptor = rubyDescriptor.lookupOneof(context, RubyString.newString(context.runtime, methodName)); - if (!oneofDescriptor.isNil()) { - throw runtime.newRuntimeError("Oneof accessors are read-only."); - } + methodName = methodName.substring(0, methodName.length() - 1); // Trim equals sign + FieldDescriptor fieldDescriptor = descriptor.findFieldByName(methodName); + if (fieldDescriptor != null) { + return setFieldInternal(context, fieldDescriptor, args[1]); + } - if (methodName.endsWith(AS_VALUE_SUFFIX)) { - methodName = methodName.substring(0, methodName.length() - 9); + IRubyObject oneofDescriptor = + rubyDescriptor.lookupOneof(context, RubyString.newString(context.runtime, methodName)); + if (!oneofDescriptor.isNil()) { + throw runtime.newRuntimeError("Oneof accessors are read-only."); + } - fieldDescriptor = descriptor.findFieldByName(methodName); + if (methodName.endsWith(AS_VALUE_SUFFIX)) { + methodName = methodName.substring(0, methodName.length() - 9); - if (fieldDescriptor != null && isWrappable(fieldDescriptor)) { - if (args[1].isNil()) { - return setFieldInternal(context, fieldDescriptor, args[1]); - } + fieldDescriptor = descriptor.findFieldByName(methodName); - RubyClass typeClass = (RubyClass) ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context); - RubyMessage msg = (RubyMessage) typeClass.newInstance(context, Block.NULL_BLOCK); - msg.indexSet(context, runtime.newString("value"), args[1]); - return setFieldInternal(context, fieldDescriptor, msg); - } - } + if (fieldDescriptor != null && isWrappable(fieldDescriptor)) { + if (args[1].isNil()) { + return setFieldInternal(context, fieldDescriptor, args[1]); + } + RubyClass typeClass = + (RubyClass) + ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)) + .msgclass(context); + RubyMessage msg = (RubyMessage) typeClass.newInstance(context, Block.NULL_BLOCK); + msg.indexSet(context, runtime.newString("value"), args[1]); + return setFieldInternal(context, fieldDescriptor, msg); } - - return Helpers.invokeSuper(context, this, metaClass, "method_missing", args, Block.NULL_BLOCK); + } } - /** - * call-seq: - * Message.dup => new_message - * Performs a shallow copy of this message and returns the new copy. - */ - @JRubyMethod - public IRubyObject dup(ThreadContext context) { - RubyMessage dup = (RubyMessage) metaClass.newInstance(context, Block.NULL_BLOCK); - for (FieldDescriptor fieldDescriptor : this.descriptor.getFields()) { - if (fieldDescriptor.isRepeated()) { - dup.fields.put(fieldDescriptor, this.getRepeatedField(context, fieldDescriptor)); - } else if (fields.containsKey(fieldDescriptor)) { - dup.setFieldInternal(context, fieldDescriptor, fields.get(fieldDescriptor)); - } else if (this.builder.hasField(fieldDescriptor)) { - dup.fields.put(fieldDescriptor, wrapField(context, fieldDescriptor, this.builder.getField(fieldDescriptor))); - } - } - return dup; + return Helpers.invokeSuper(context, this, metaClass, "method_missing", args, Block.NULL_BLOCK); + } + + /** + * call-seq: Message.dup => new_message Performs a shallow copy of this message and returns the + * new copy. + */ + @JRubyMethod + public IRubyObject dup(ThreadContext context) { + RubyMessage dup = (RubyMessage) metaClass.newInstance(context, Block.NULL_BLOCK); + for (FieldDescriptor fieldDescriptor : this.descriptor.getFields()) { + if (fieldDescriptor.isRepeated()) { + dup.fields.put(fieldDescriptor, this.getRepeatedField(context, fieldDescriptor)); + } else if (fields.containsKey(fieldDescriptor)) { + dup.setFieldInternal(context, fieldDescriptor, fields.get(fieldDescriptor)); + } else if (this.builder.hasField(fieldDescriptor)) { + dup.fields.put( + fieldDescriptor, + wrapField(context, fieldDescriptor, this.builder.getField(fieldDescriptor))); + } } - - /* - * call-seq: - * Message.descriptor => descriptor - * - * Class method that returns the Descriptor instance corresponding to this - * message class's type. - */ - @JRubyMethod(name = "descriptor", meta = true) - public static IRubyObject getDescriptor(ThreadContext context, IRubyObject recv) { - return ((RubyClass) recv).getInstanceVariable(Utils.DESCRIPTOR_INSTANCE_VAR); + return dup; + } + + /* + * call-seq: + * Message.descriptor => descriptor + * + * Class method that returns the Descriptor instance corresponding to this + * message class's type. + */ + @JRubyMethod(name = "descriptor", meta = true) + public static IRubyObject getDescriptor(ThreadContext context, IRubyObject recv) { + return ((RubyClass) recv).getInstanceVariable(Utils.DESCRIPTOR_INSTANCE_VAR); + } + + /* + * call-seq: + * MessageClass.encode(msg, options = {}) => bytes + * + * Encodes the given message object to its serialized form in protocol buffers + * wire format. + * @param options [Hash] options for the encoder + * recursion_limit: set to maximum encoding depth for message (default is 64) + */ + @JRubyMethod(required = 1, optional = 1, meta = true) + public static IRubyObject encode(ThreadContext context, IRubyObject recv, IRubyObject[] args) { + if (recv != args[0].getMetaClass()) { + throw context.runtime.newArgumentError( + "Tried to encode a " + args[0].getMetaClass() + " message with " + recv); } + RubyMessage message = (RubyMessage) args[0]; + int recursionLimitInt = SINK_MAXIMUM_NESTING; - /* - * call-seq: - * MessageClass.encode(msg, options = {}) => bytes - * - * Encodes the given message object to its serialized form in protocol buffers - * wire format. - * @param options [Hash] options for the encoder - * recursion_limit: set to maximum encoding depth for message (default is 64) - */ - @JRubyMethod(required = 1, optional = 1, meta = true) - public static IRubyObject encode(ThreadContext context, IRubyObject recv, IRubyObject[] args) { - if (recv != args[0].getMetaClass()) { - throw context.runtime.newArgumentError("Tried to encode a " + args[0].getMetaClass() + " message with " + recv); - } - RubyMessage message = (RubyMessage) args[0]; - int recursionLimitInt = SINK_MAXIMUM_NESTING; - - if (args.length > 1) { - RubyHash options = (RubyHash) args[1]; - IRubyObject recursionLimit = options.fastARef(context.runtime.newSymbol("recursion_limit")); + if (args.length > 1) { + RubyHash options = (RubyHash) args[1]; + IRubyObject recursionLimit = options.fastARef(context.runtime.newSymbol("recursion_limit")); - if (recursionLimit != null) { - recursionLimitInt = ((RubyNumeric) recursionLimit).getIntValue(); - } - } - return context.runtime.newString(new ByteList(message.build(context, 0, recursionLimitInt).toByteArray())); + if (recursionLimit != null) { + recursionLimitInt = ((RubyNumeric) recursionLimit).getIntValue(); + } } + return context.runtime.newString( + new ByteList(message.build(context, 0, recursionLimitInt).toByteArray())); + } + + /* + * call-seq: + * MessageClass.decode(data, options = {}) => message + * + * Decodes the given data (as a string containing bytes in protocol buffers wire + * format) under the interpretation given by this message class's definition + * and returns a message object with the corresponding field values. + * @param options [Hash] options for the decoder + * recursion_limit: set to maximum decoding depth for message (default is 100) + */ + @JRubyMethod(required = 1, optional = 1, meta = true) + public static IRubyObject decode(ThreadContext context, IRubyObject recv, IRubyObject[] args) { + IRubyObject data = args[0]; + byte[] bin = data.convertToString().getBytes(); + CodedInputStream input = CodedInputStream.newInstance(bin); + RubyMessage ret = (RubyMessage) ((RubyClass) recv).newInstance(context, Block.NULL_BLOCK); + + if (args.length == 2) { + if (!(args[1] instanceof RubyHash)) { + throw context.runtime.newArgumentError("Expected hash arguments."); + } - /* - * call-seq: - * MessageClass.decode(data, options = {}) => message - * - * Decodes the given data (as a string containing bytes in protocol buffers wire - * format) under the interpretation given by this message class's definition - * and returns a message object with the corresponding field values. - * @param options [Hash] options for the decoder - * recursion_limit: set to maximum decoding depth for message (default is 100) - */ - @JRubyMethod(required = 1, optional = 1, meta = true) - public static IRubyObject decode(ThreadContext context, IRubyObject recv, IRubyObject[] args) { - IRubyObject data = args[0]; - byte[] bin = data.convertToString().getBytes(); - CodedInputStream input = CodedInputStream.newInstance(bin); - RubyMessage ret = (RubyMessage) ((RubyClass) recv).newInstance(context, Block.NULL_BLOCK); - - if (args.length == 2) { - if (!(args[1] instanceof RubyHash)) { - throw context.runtime.newArgumentError("Expected hash arguments."); - } - - IRubyObject recursionLimit = ((RubyHash) args[1]).fastARef(context.runtime.newSymbol("recursion_limit")); - if (recursionLimit != null) { - input.setRecursionLimit(((RubyNumeric) recursionLimit).getIntValue()); - } - } + IRubyObject recursionLimit = + ((RubyHash) args[1]).fastARef(context.runtime.newSymbol("recursion_limit")); + if (recursionLimit != null) { + input.setRecursionLimit(((RubyNumeric) recursionLimit).getIntValue()); + } + } - try { - ret.builder.mergeFrom(input); - } catch (Exception e) { - throw RaiseException.from(context.runtime, (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::ParseError"), e.getMessage()); - } + try { + ret.builder.mergeFrom(input); + } catch (Exception e) { + throw RaiseException.from( + context.runtime, + (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::ParseError"), + e.getMessage()); + } - if (!ret.proto3) { - // Need to reset unknown values in repeated enum fields - ret.builder.getUnknownFields().asMap().forEach((i, values) -> { + if (!ret.proto3) { + // Need to reset unknown values in repeated enum fields + ret.builder + .getUnknownFields() + .asMap() + .forEach( + (i, values) -> { FieldDescriptor fd = ret.builder.getDescriptorForType().findFieldByNumber(i); if (fd != null && fd.isRepeated() && fd.getType() == FieldDescriptor.Type.ENUM) { - EnumDescriptor ed = fd.getEnumType(); - values.getVarintList().forEach(value -> { - ret.builder.addRepeatedField(fd, ed.findValueByNumberCreatingIfUnknown(value.intValue())); - }); + EnumDescriptor ed = fd.getEnumType(); + values + .getVarintList() + .forEach( + value -> { + ret.builder.addRepeatedField( + fd, ed.findValueByNumberCreatingIfUnknown(value.intValue())); + }); } - }); - } - - return ret; + }); } - /* - * call-seq: - * MessageClass.encode_json(msg, options = {}) => json_string - * - * Encodes the given message object into its serialized JSON representation. - * @param options [Hash] options for the decoder - * preserve_proto_fieldnames: set true to use original fieldnames (default is to camelCase) - * emit_defaults: set true to emit 0/false values (default is to omit them) - */ - @JRubyMethod(name = "encode_json", required = 1, optional = 1, meta = true) - public static IRubyObject encodeJson(ThreadContext context, IRubyObject recv, IRubyObject[] args) { - Ruby runtime = context.runtime; - RubyMessage message = (RubyMessage) args[0]; - JsonFormat.Printer printer = JsonFormat.printer().omittingInsignificantWhitespace(); - String result; - - if (args.length > 1) { - RubyHash options; - if (args[1] instanceof RubyHash) { - options = (RubyHash) args[1]; - } else if (args[1].respondsTo("to_h")) { - options = (RubyHash) args[1].callMethod(context, "to_h"); - } else { - throw runtime.newArgumentError("Expected hash arguments."); - } - - IRubyObject emitDefaults = options.fastARef(runtime.newSymbol("emit_defaults")); - IRubyObject preserveNames = options.fastARef(runtime.newSymbol("preserve_proto_fieldnames")); + return ret; + } + + /* + * call-seq: + * MessageClass.encode_json(msg, options = {}) => json_string + * + * Encodes the given message object into its serialized JSON representation. + * @param options [Hash] options for the decoder + * preserve_proto_fieldnames: set true to use original fieldnames (default is to camelCase) + * emit_defaults: set true to emit 0/false values (default is to omit them) + */ + @JRubyMethod(name = "encode_json", required = 1, optional = 1, meta = true) + public static IRubyObject encodeJson( + ThreadContext context, IRubyObject recv, IRubyObject[] args) { + Ruby runtime = context.runtime; + RubyMessage message = (RubyMessage) args[0]; + JsonFormat.Printer printer = JsonFormat.printer().omittingInsignificantWhitespace(); + String result; + + if (args.length > 1) { + RubyHash options; + if (args[1] instanceof RubyHash) { + options = (RubyHash) args[1]; + } else if (args[1].respondsTo("to_h")) { + options = (RubyHash) args[1].callMethod(context, "to_h"); + } else { + throw runtime.newArgumentError("Expected hash arguments."); + } - if (emitDefaults != null && emitDefaults.isTrue()) { - printer = printer.includingDefaultValueFields(); - } + IRubyObject emitDefaults = options.fastARef(runtime.newSymbol("emit_defaults")); + IRubyObject preserveNames = options.fastARef(runtime.newSymbol("preserve_proto_fieldnames")); - if (preserveNames != null && preserveNames.isTrue()) { - printer = printer.preservingProtoFieldNames(); - } - } - printer = printer.usingTypeRegistry(JsonFormat.TypeRegistry.newBuilder().add(message.descriptor).build()); - - try { - result = printer.print(message.build(context, 0, SINK_MAXIMUM_NESTING)); - } catch (InvalidProtocolBufferException e) { - throw runtime.newRuntimeError(e.getMessage()); - } catch (IllegalArgumentException e) { - throw createParseError(context, e.getMessage()); - } + if (emitDefaults != null && emitDefaults.isTrue()) { + printer = printer.includingDefaultValueFields(); + } - return runtime.newString(result); + if (preserveNames != null && preserveNames.isTrue()) { + printer = printer.preservingProtoFieldNames(); + } + } + printer = + printer.usingTypeRegistry( + JsonFormat.TypeRegistry.newBuilder().add(message.descriptor).build()); + + try { + result = printer.print(message.build(context, 0, SINK_MAXIMUM_NESTING)); + } catch (InvalidProtocolBufferException e) { + throw runtime.newRuntimeError(e.getMessage()); + } catch (IllegalArgumentException e) { + throw createParseError(context, e.getMessage()); } - /* - * call-seq: - * MessageClass.decode_json(data, options = {}) => message - * - * Decodes the given data (as a string containing bytes in protocol buffers wire - * format) under the interpretation given by this message class's definition - * and returns a message object with the corresponding field values. - * - * @param options [Hash] options for the decoder - * ignore_unknown_fields: set true to ignore unknown fields (default is to - * raise an error) - */ - @JRubyMethod(name = "decode_json", required = 1, optional = 1, meta = true) - public static IRubyObject decodeJson(ThreadContext context, IRubyObject recv, IRubyObject[] args) { - Ruby runtime = context.runtime; - boolean ignoreUnknownFields = false; - IRubyObject data = args[0]; - JsonFormat.Parser parser = JsonFormat.parser(); - - if (args.length == 2) { - if (!(args[1] instanceof RubyHash)) { - throw runtime.newArgumentError("Expected hash arguments."); - } - - IRubyObject ignoreSetting = ((RubyHash) args[1]).fastARef(runtime.newSymbol("ignore_unknown_fields")); - if (ignoreSetting != null && ignoreSetting.isTrue()) { - parser = parser.ignoringUnknownFields(); - } - } + return runtime.newString(result); + } + + /* + * call-seq: + * MessageClass.decode_json(data, options = {}) => message + * + * Decodes the given data (as a string containing bytes in protocol buffers wire + * format) under the interpretation given by this message class's definition + * and returns a message object with the corresponding field values. + * + * @param options [Hash] options for the decoder + * ignore_unknown_fields: set true to ignore unknown fields (default is to + * raise an error) + */ + @JRubyMethod(name = "decode_json", required = 1, optional = 1, meta = true) + public static IRubyObject decodeJson( + ThreadContext context, IRubyObject recv, IRubyObject[] args) { + Ruby runtime = context.runtime; + boolean ignoreUnknownFields = false; + IRubyObject data = args[0]; + JsonFormat.Parser parser = JsonFormat.parser(); + + if (args.length == 2) { + if (!(args[1] instanceof RubyHash)) { + throw runtime.newArgumentError("Expected hash arguments."); + } - if (!(data instanceof RubyString)) { - throw runtime.newArgumentError("Expected string for JSON data."); - } + IRubyObject ignoreSetting = + ((RubyHash) args[1]).fastARef(runtime.newSymbol("ignore_unknown_fields")); + if (ignoreSetting != null && ignoreSetting.isTrue()) { + parser = parser.ignoringUnknownFields(); + } + } - RubyMessage ret = (RubyMessage) ((RubyClass) recv).newInstance(context, Block.NULL_BLOCK); - parser = parser.usingTypeRegistry(JsonFormat.TypeRegistry.newBuilder().add(ret.descriptor).build()); + if (!(data instanceof RubyString)) { + throw runtime.newArgumentError("Expected string for JSON data."); + } - try { - parser.merge(data.asJavaString(), ret.builder); - } catch(InvalidProtocolBufferException e) { - throw createParseError(context, e.getMessage().replace("Cannot find", "No such")); - } + RubyMessage ret = (RubyMessage) ((RubyClass) recv).newInstance(context, Block.NULL_BLOCK); + parser = + parser.usingTypeRegistry(JsonFormat.TypeRegistry.newBuilder().add(ret.descriptor).build()); - if (isWrapper(ret.descriptor)) { - throw runtime.newRuntimeError("Parsing a wrapper type from JSON at the top level does not work."); - } + try { + parser.merge(data.asJavaString(), ret.builder); + } catch (InvalidProtocolBufferException e) { + throw createParseError(context, e.getMessage().replace("Cannot find", "No such")); + } - return ret; + if (isWrapper(ret.descriptor)) { + throw runtime.newRuntimeError( + "Parsing a wrapper type from JSON at the top level does not work."); } - @JRubyMethod(name = "to_h") - public IRubyObject toHash(ThreadContext context) { - Ruby runtime = context.runtime; - RubyHash ret = RubyHash.newHash(runtime); - for (FieldDescriptor fdef : this.descriptor.getFields()) { - IRubyObject value = getFieldInternal(context, fdef, proto3); - - if (!value.isNil()) { - if (fdef.isRepeated() && !fdef.isMapField()) { - if (!proto3 && ((RubyRepeatedField) value).size() == 0) continue; // Don't output empty repeated fields for proto2 - if (fdef.getType() != FieldDescriptor.Type.MESSAGE) { - value = Helpers.invoke(context, value, "to_a"); - } else { - RubyArray ary = value.convertToArray(); - for (int i = 0; i < ary.size(); i++) { - IRubyObject submsg = Helpers.invoke(context, ary.eltInternal(i), "to_h"); - ary.eltInternalSet(i, submsg); - } - - value = ary.to_ary(); - } - } else if (value.respondsTo("to_h")) { - value = Helpers.invoke(context, value, "to_h"); - } else if (value.respondsTo("to_a")) { - value = Helpers.invoke(context, value, "to_a"); - } - } - if (proto3 || !value.isNil()) { - ret.fastASet(runtime.newSymbol(fdef.getName()), value); + return ret; + } + + @JRubyMethod(name = "to_h") + public IRubyObject toHash(ThreadContext context) { + Ruby runtime = context.runtime; + RubyHash ret = RubyHash.newHash(runtime); + for (FieldDescriptor fdef : this.descriptor.getFields()) { + IRubyObject value = getFieldInternal(context, fdef, proto3); + + if (!value.isNil()) { + if (fdef.isRepeated() && !fdef.isMapField()) { + if (!proto3 && ((RubyRepeatedField) value).size() == 0) + continue; // Don't output empty repeated fields for proto2 + if (fdef.getType() != FieldDescriptor.Type.MESSAGE) { + value = Helpers.invoke(context, value, "to_a"); + } else { + RubyArray ary = value.convertToArray(); + for (int i = 0; i < ary.size(); i++) { + IRubyObject submsg = Helpers.invoke(context, ary.eltInternal(i), "to_h"); + ary.eltInternalSet(i, submsg); } - } - return ret; - } - protected DynamicMessage build(ThreadContext context, int depth, int recursionLimit) { - if (depth >= recursionLimit) { - throw context.runtime.newRuntimeError("Recursion limit exceeded during encoding."); + value = ary.to_ary(); + } + } else if (value.respondsTo("to_h")) { + value = Helpers.invoke(context, value, "to_h"); + } else if (value.respondsTo("to_a")) { + value = Helpers.invoke(context, value, "to_a"); } + } + if (proto3 || !value.isNil()) { + ret.fastASet(runtime.newSymbol(fdef.getName()), value); + } + } + return ret; + } - RubySymbol typeBytesSymbol = RubySymbol.newSymbol(context.runtime, "TYPE_BYTES"); - - // Handle the typical case where the fields.keySet contain the fieldDescriptors - for (FieldDescriptor fieldDescriptor : fields.keySet()) { - IRubyObject value = fields.get(fieldDescriptor); - - if (value instanceof RubyMap) { - builder.clearField(fieldDescriptor); - RubyDescriptor mapDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); - for (DynamicMessage kv : ((RubyMap) value).build(context, mapDescriptor, depth, recursionLimit)) { - builder.addRepeatedField(fieldDescriptor, kv); - } + protected DynamicMessage build(ThreadContext context, int depth, int recursionLimit) { + if (depth >= recursionLimit) { + throw context.runtime.newRuntimeError("Recursion limit exceeded during encoding."); + } - } else if (value instanceof RubyRepeatedField) { - RubyRepeatedField repeatedField = (RubyRepeatedField) value; + RubySymbol typeBytesSymbol = RubySymbol.newSymbol(context.runtime, "TYPE_BYTES"); - builder.clearField(fieldDescriptor); - for (int i = 0; i < repeatedField.size(); i++) { - Object item = convert(context, fieldDescriptor, repeatedField.get(i), depth, recursionLimit, - /*isDefaultValueForBytes*/ false); - builder.addRepeatedField(fieldDescriptor, item); - } + // Handle the typical case where the fields.keySet contain the fieldDescriptors + for (FieldDescriptor fieldDescriptor : fields.keySet()) { + IRubyObject value = fields.get(fieldDescriptor); - } else if (!value.isNil()) { - /** - * Detect the special case where default_value strings are provided for byte fields. - * If so, disable normal string encoding behavior within convert. - * For a more detailed explanation of other possible workarounds, see the comments - * above {@code com.google.protobuf.Internal#stringDefaultValue() - * stringDefaultValue}. - */ - boolean isDefaultStringForBytes = false; - if (DEFAULT_VALUE.equals(fieldDescriptor.getFullName())) { - FieldDescriptor enumFieldDescriptorForType = - this.builder.getDescriptorForType().findFieldByName(TYPE); - if (typeBytesSymbol.equals(fields.get(enumFieldDescriptorForType))) { - isDefaultStringForBytes = true; - } - } - builder.setField(fieldDescriptor, convert(context, fieldDescriptor, value, depth, recursionLimit, isDefaultStringForBytes)); - } + if (value instanceof RubyMap) { + builder.clearField(fieldDescriptor); + RubyDescriptor mapDescriptor = + (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); + for (DynamicMessage kv : + ((RubyMap) value).build(context, mapDescriptor, depth, recursionLimit)) { + builder.addRepeatedField(fieldDescriptor, kv); } - // Handle cases where {@code fields} doesn't contain the value until after getFieldInternal - // is called - typical of a deserialized message. Skip non-maps and descriptors that already - // have an entry in {@code fields}. - for (FieldDescriptor fieldDescriptor : descriptor.getFields()) { - if (!fieldDescriptor.isMapField()) { - continue; - } - IRubyObject value = fields.get(fieldDescriptor); - if (value!=null) { - continue; - } - value = getFieldInternal(context, fieldDescriptor); - if (value instanceof RubyMap) { - builder.clearField(fieldDescriptor); - RubyDescriptor mapDescriptor = (RubyDescriptor) getDescriptorForField(context, - fieldDescriptor); - for (DynamicMessage kv : ((RubyMap) value).build(context, mapDescriptor, depth, recursionLimit)) { - builder.addRepeatedField(fieldDescriptor, kv); - } - } - } - return builder.build(); - } + } else if (value instanceof RubyRepeatedField) { + RubyRepeatedField repeatedField = (RubyRepeatedField) value; - // Internal use only, called by Google::Protobuf.deep_copy - protected IRubyObject deepCopy(ThreadContext context) { - RubyMessage copy = (RubyMessage) metaClass.newInstance(context, Block.NULL_BLOCK); - for (FieldDescriptor fdef : descriptor.getFields()) { - if (fdef.isRepeated()) { - copy.fields.put(fdef, this.getRepeatedField(context, fdef).deepCopy(context)); - } else if (fields.containsKey(fdef)) { - copy.setFieldInternal(context, fdef, fields.get(fdef)); - } else if (builder.hasField(fdef)) { - copy.fields.put(fdef, wrapField(context, fdef, builder.getField(fdef))); - } + builder.clearField(fieldDescriptor); + for (int i = 0; i < repeatedField.size(); i++) { + Object item = + convert( + context, + fieldDescriptor, + repeatedField.get(i), + depth, + recursionLimit, + /*isDefaultValueForBytes*/ false); + builder.addRepeatedField(fieldDescriptor, item); } - return copy; - } - - protected IRubyObject clearField(ThreadContext context, FieldDescriptor fieldDescriptor) { - validateMessageType(context, fieldDescriptor, "clear"); - return clearFieldInternal(context, fieldDescriptor); - } - protected void discardUnknownFields(ThreadContext context) { - discardUnknownFields(context, builder); - } - - protected IRubyObject getField(ThreadContext context, FieldDescriptor fieldDescriptor) { - validateMessageType(context, fieldDescriptor, "get"); - return getFieldInternal(context, fieldDescriptor); + } else if (!value.isNil()) { + /** + * Detect the special case where default_value strings are provided for byte fields. If so, + * disable normal string encoding behavior within convert. For a more detailed explanation + * of other possible workarounds, see the comments above {@code + * com.google.protobuf.Internal#stringDefaultValue() stringDefaultValue}. + */ + boolean isDefaultStringForBytes = false; + if (DEFAULT_VALUE.equals(fieldDescriptor.getFullName())) { + FieldDescriptor enumFieldDescriptorForType = + this.builder.getDescriptorForType().findFieldByName(TYPE); + if (typeBytesSymbol.equals(fields.get(enumFieldDescriptorForType))) { + isDefaultStringForBytes = true; + } + } + builder.setField( + fieldDescriptor, + convert( + context, fieldDescriptor, value, depth, recursionLimit, isDefaultStringForBytes)); + } } - protected IRubyObject hasField(ThreadContext context, FieldDescriptor fieldDescriptor) { - validateMessageType(context, fieldDescriptor, "has?"); - if (!fieldDescriptor.hasPresence()) { - throw context.runtime.newArgumentError("does not track presence"); + // Handle cases where {@code fields} doesn't contain the value until after getFieldInternal + // is called - typical of a deserialized message. Skip non-maps and descriptors that already + // have an entry in {@code fields}. + for (FieldDescriptor fieldDescriptor : descriptor.getFields()) { + if (!fieldDescriptor.isMapField()) { + continue; + } + IRubyObject value = fields.get(fieldDescriptor); + if (value != null) { + continue; + } + value = getFieldInternal(context, fieldDescriptor); + if (value instanceof RubyMap) { + builder.clearField(fieldDescriptor); + RubyDescriptor mapDescriptor = + (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); + for (DynamicMessage kv : + ((RubyMap) value).build(context, mapDescriptor, depth, recursionLimit)) { + builder.addRepeatedField(fieldDescriptor, kv); } - return fields.containsKey(fieldDescriptor) ? context.runtime.getTrue() : context.runtime.getFalse(); + } } - - protected IRubyObject setField(ThreadContext context, FieldDescriptor fieldDescriptor, IRubyObject value) { - validateMessageType(context, fieldDescriptor, "set"); - return setFieldInternal(context, fieldDescriptor, value); + return builder.build(); + } + + // Internal use only, called by Google::Protobuf.deep_copy + protected IRubyObject deepCopy(ThreadContext context) { + RubyMessage copy = (RubyMessage) metaClass.newInstance(context, Block.NULL_BLOCK); + for (FieldDescriptor fdef : descriptor.getFields()) { + if (fdef.isRepeated()) { + copy.fields.put(fdef, this.getRepeatedField(context, fdef).deepCopy(context)); + } else if (fields.containsKey(fdef)) { + copy.setFieldInternal(context, fdef, fields.get(fdef)); + } else if (builder.hasField(fdef)) { + copy.fields.put(fdef, wrapField(context, fdef, builder.getField(fdef))); + } } - - private RubyRepeatedField getRepeatedField(ThreadContext context, FieldDescriptor fieldDescriptor) { - if (fields.containsKey(fieldDescriptor)) { - return (RubyRepeatedField) fields.get(fieldDescriptor); - } - int count = this.builder.getRepeatedFieldCount(fieldDescriptor); - RubyRepeatedField ret = repeatedFieldForFieldDescriptor(context, fieldDescriptor); - for (int i = 0; i < count; i++) { - ret.push(context, new IRubyObject[] {wrapField(context, fieldDescriptor, this.builder.getRepeatedField(fieldDescriptor, i))}); - } - fields.put(fieldDescriptor, ret); - return ret; + return copy; + } + + protected IRubyObject clearField(ThreadContext context, FieldDescriptor fieldDescriptor) { + validateMessageType(context, fieldDescriptor, "clear"); + return clearFieldInternal(context, fieldDescriptor); + } + + protected void discardUnknownFields(ThreadContext context) { + discardUnknownFields(context, builder); + } + + protected IRubyObject getField(ThreadContext context, FieldDescriptor fieldDescriptor) { + validateMessageType(context, fieldDescriptor, "get"); + return getFieldInternal(context, fieldDescriptor); + } + + protected IRubyObject hasField(ThreadContext context, FieldDescriptor fieldDescriptor) { + validateMessageType(context, fieldDescriptor, "has?"); + if (!fieldDescriptor.hasPresence()) { + throw context.runtime.newArgumentError("does not track presence"); } - - private IRubyObject buildFrom(ThreadContext context, DynamicMessage dynamicMessage) { - this.builder.mergeFrom(dynamicMessage); - return this; + return fields.containsKey(fieldDescriptor) + ? context.runtime.getTrue() + : context.runtime.getFalse(); + } + + protected IRubyObject setField( + ThreadContext context, FieldDescriptor fieldDescriptor, IRubyObject value) { + validateMessageType(context, fieldDescriptor, "set"); + return setFieldInternal(context, fieldDescriptor, value); + } + + private RubyRepeatedField getRepeatedField( + ThreadContext context, FieldDescriptor fieldDescriptor) { + if (fields.containsKey(fieldDescriptor)) { + return (RubyRepeatedField) fields.get(fieldDescriptor); } - - private IRubyObject clearFieldInternal(ThreadContext context, FieldDescriptor fieldDescriptor) { - OneofDescriptor ood = fieldDescriptor.getContainingOneof(); - if (ood != null) oneofCases.remove(ood); - fields.remove(fieldDescriptor); - builder.clearField(fieldDescriptor); - return context.nil; + int count = this.builder.getRepeatedFieldCount(fieldDescriptor); + RubyRepeatedField ret = repeatedFieldForFieldDescriptor(context, fieldDescriptor); + for (int i = 0; i < count; i++) { + ret.push( + context, + new IRubyObject[] { + wrapField(context, fieldDescriptor, this.builder.getRepeatedField(fieldDescriptor, i)) + }); } - - private void discardUnknownFields(ThreadContext context, Message.Builder messageBuilder) { - messageBuilder.setUnknownFields(UnknownFieldSet.getDefaultInstance()); - messageBuilder.getAllFields().forEach((fd, value) -> { - if (fd.getType() == FieldDescriptor.Type.MESSAGE) { + fields.put(fieldDescriptor, ret); + return ret; + } + + private IRubyObject buildFrom(ThreadContext context, DynamicMessage dynamicMessage) { + this.builder.mergeFrom(dynamicMessage); + return this; + } + + private IRubyObject clearFieldInternal(ThreadContext context, FieldDescriptor fieldDescriptor) { + OneofDescriptor ood = fieldDescriptor.getContainingOneof(); + if (ood != null) oneofCases.remove(ood); + fields.remove(fieldDescriptor); + builder.clearField(fieldDescriptor); + return context.nil; + } + + private void discardUnknownFields(ThreadContext context, Message.Builder messageBuilder) { + messageBuilder.setUnknownFields(UnknownFieldSet.getDefaultInstance()); + messageBuilder + .getAllFields() + .forEach( + (fd, value) -> { + if (fd.getType() == FieldDescriptor.Type.MESSAGE) { if (fd.isRepeated()) { - messageBuilder.clearField(fd); - ((List) value).forEach((val) -> { - Message.Builder submessageBuilder = ((DynamicMessage) val).toBuilder(); - discardUnknownFields(context, submessageBuilder); - messageBuilder.addRepeatedField(fd, submessageBuilder.build()); - }); + messageBuilder.clearField(fd); + ((List) value) + .forEach( + (val) -> { + Message.Builder submessageBuilder = ((DynamicMessage) val).toBuilder(); + discardUnknownFields(context, submessageBuilder); + messageBuilder.addRepeatedField(fd, submessageBuilder.build()); + }); } else { - Message.Builder submessageBuilder = ((DynamicMessage) value).toBuilder(); - discardUnknownFields(context, submessageBuilder); - messageBuilder.setField(fd, submessageBuilder.build()); + Message.Builder submessageBuilder = ((DynamicMessage) value).toBuilder(); + discardUnknownFields(context, submessageBuilder); + messageBuilder.setField(fd, submessageBuilder.build()); } - } - }); - } - - private FieldDescriptor findField(ThreadContext context, IRubyObject fieldName) { - return findField(context, fieldName, false); + } + }); + } + + private FieldDescriptor findField(ThreadContext context, IRubyObject fieldName) { + return findField(context, fieldName, false); + } + + private FieldDescriptor findField( + ThreadContext context, IRubyObject fieldName, boolean ignoreUnknownField) { + String nameStr = fieldName.asJavaString(); + FieldDescriptor ret = this.descriptor.findFieldByName(nameStr); + if (ret == null && !ignoreUnknownField) { + throw context.runtime.newArgumentError("field " + fieldName.asJavaString() + " is not found"); } - - private FieldDescriptor findField(ThreadContext context, IRubyObject fieldName, boolean ignoreUnknownField) { - String nameStr = fieldName.asJavaString(); - FieldDescriptor ret = this.descriptor.findFieldByName(nameStr); - if (ret == null && !ignoreUnknownField) { - throw context.runtime.newArgumentError("field " + fieldName.asJavaString() + " is not found"); + return ret; + } + + // convert a ruby object to protobuf type, skip type check since it is checked on the way in + private Object convert( + ThreadContext context, + FieldDescriptor fieldDescriptor, + IRubyObject value, + int depth, + int recursionLimit, + boolean isDefaultStringForBytes) { + Object val = null; + switch (fieldDescriptor.getType()) { + case INT32: + case SFIXED32: + case SINT32: + val = RubyNumeric.num2int(value); + break; + case INT64: + case SFIXED64: + case SINT64: + val = RubyNumeric.num2long(value); + break; + case FIXED32: + case UINT32: + val = Utils.num2uint(value); + break; + case FIXED64: + case UINT64: + val = Utils.num2ulong(context.runtime, value); + break; + case FLOAT: + val = (float) RubyNumeric.num2dbl(value); + break; + case DOUBLE: + val = (double) RubyNumeric.num2dbl(value); + break; + case BOOL: + val = value.isTrue(); + break; + case BYTES: + val = ByteString.copyFrom(((RubyString) value).getBytes()); + break; + case STRING: + if (isDefaultStringForBytes) { + val = ((RubyString) value).getByteList().toString(); + } else { + val = value.asJavaString(); } - return ret; - } - - // convert a ruby object to protobuf type, skip type check since it is checked on the way in - private Object convert(ThreadContext context, - FieldDescriptor fieldDescriptor, - IRubyObject value, int depth, int recursionLimit, - boolean isDefaultStringForBytes) { - Object val = null; - switch (fieldDescriptor.getType()) { - case INT32: - case SFIXED32: - case SINT32: - val = RubyNumeric.num2int(value); - break; - case INT64: - case SFIXED64: - case SINT64: - val = RubyNumeric.num2long(value); - break; - case FIXED32: - case UINT32: - val = Utils.num2uint(value); - break; - case FIXED64: - case UINT64: - val = Utils.num2ulong(context.runtime, value); - break; - case FLOAT: - val = (float) RubyNumeric.num2dbl(value); - break; - case DOUBLE: - val = (double) RubyNumeric.num2dbl(value); - break; - case BOOL: - val = value.isTrue(); - break; - case BYTES: - val = ByteString.copyFrom(((RubyString) value).getBytes()); - break; - case STRING: - if (isDefaultStringForBytes) { - val = ((RubyString) value).getByteList().toString(); - } else { - val = value.asJavaString(); - } - break; - case MESSAGE: - val = ((RubyMessage) value).build(context, depth + 1, recursionLimit); - break; - case ENUM: - EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType(); - if (Utils.isRubyNum(value)) { - val = enumDescriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value)); - } else { - val = enumDescriptor.findValueByName(value.asJavaString()); - } - break; - default: - break; + break; + case MESSAGE: + val = ((RubyMessage) value).build(context, depth + 1, recursionLimit); + break; + case ENUM: + EnumDescriptor enumDescriptor = fieldDescriptor.getEnumType(); + if (Utils.isRubyNum(value)) { + val = enumDescriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value)); + } else { + val = enumDescriptor.findValueByName(value.asJavaString()); } - - return val; + break; + default: + break; } - private static RaiseException createParseError(ThreadContext context, String message) { - if (parseErrorClass == null) { - parseErrorClass = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::ParseError"); - } - return RaiseException.from(context.runtime, parseErrorClass, message); - } + return val; + } - private IRubyObject wrapField(ThreadContext context, FieldDescriptor fieldDescriptor, Object value) { - return wrapField(context, fieldDescriptor, value, false); + private static RaiseException createParseError(ThreadContext context, String message) { + if (parseErrorClass == null) { + parseErrorClass = + (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::ParseError"); } - - private IRubyObject wrapField(ThreadContext context, FieldDescriptor fieldDescriptor, Object value, boolean encodeBytes) { - if (value == null) { - return context.runtime.getNil(); - } - Ruby runtime = context.runtime; - - switch (fieldDescriptor.getType()) { - case INT32: - case INT64: - case FIXED32: - case SINT32: - case FIXED64: - case SINT64: - case SFIXED64: - case SFIXED32: - case UINT32: - case UINT64: - case FLOAT: - case DOUBLE: - case BOOL: - case BYTES: - case STRING: - return Utils.wrapPrimaryValue(context, fieldDescriptor.getType(), value, encodeBytes); - case MESSAGE: - RubyClass typeClass = (RubyClass) ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context); - RubyMessage msg = (RubyMessage) typeClass.newInstance(context, Block.NULL_BLOCK); - return msg.buildFrom(context, (DynamicMessage) value); - case ENUM: - EnumValueDescriptor enumValueDescriptor = (EnumValueDescriptor) value; - if (enumValueDescriptor.getIndex() == -1) { // UNKNOWN ENUM VALUE - return runtime.newFixnum(enumValueDescriptor.getNumber()); - } - return runtime.newSymbol(enumValueDescriptor.getName()); - default: - return runtime.newString(value.toString()); + return RaiseException.from(context.runtime, parseErrorClass, message); + } + + private IRubyObject wrapField( + ThreadContext context, FieldDescriptor fieldDescriptor, Object value) { + return wrapField(context, fieldDescriptor, value, false); + } + + private IRubyObject wrapField( + ThreadContext context, FieldDescriptor fieldDescriptor, Object value, boolean encodeBytes) { + if (value == null) { + return context.runtime.getNil(); + } + Ruby runtime = context.runtime; + + switch (fieldDescriptor.getType()) { + case INT32: + case INT64: + case FIXED32: + case SINT32: + case FIXED64: + case SINT64: + case SFIXED64: + case SFIXED32: + case UINT32: + case UINT64: + case FLOAT: + case DOUBLE: + case BOOL: + case BYTES: + case STRING: + return Utils.wrapPrimaryValue(context, fieldDescriptor.getType(), value, encodeBytes); + case MESSAGE: + RubyClass typeClass = + (RubyClass) + ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)) + .msgclass(context); + RubyMessage msg = (RubyMessage) typeClass.newInstance(context, Block.NULL_BLOCK); + return msg.buildFrom(context, (DynamicMessage) value); + case ENUM: + EnumValueDescriptor enumValueDescriptor = (EnumValueDescriptor) value; + if (enumValueDescriptor.getIndex() == -1) { // UNKNOWN ENUM VALUE + return runtime.newFixnum(enumValueDescriptor.getNumber()); } + return runtime.newSymbol(enumValueDescriptor.getName()); + default: + return runtime.newString(value.toString()); } + } - private RubyRepeatedField repeatedFieldForFieldDescriptor(ThreadContext context, FieldDescriptor fieldDescriptor) { - IRubyObject typeClass = context.runtime.getNilClass(); - IRubyObject descriptor = getDescriptorForField(context, fieldDescriptor); - FieldDescriptor.Type type = fieldDescriptor.getType(); + private RubyRepeatedField repeatedFieldForFieldDescriptor( + ThreadContext context, FieldDescriptor fieldDescriptor) { + IRubyObject typeClass = context.runtime.getNilClass(); + IRubyObject descriptor = getDescriptorForField(context, fieldDescriptor); + FieldDescriptor.Type type = fieldDescriptor.getType(); - if (type == FieldDescriptor.Type.MESSAGE) { - typeClass = ((RubyDescriptor) descriptor).msgclass(context); - - } else if (type == FieldDescriptor.Type.ENUM) { - typeClass = ((RubyEnumDescriptor) descriptor).enummodule(context); - } + if (type == FieldDescriptor.Type.MESSAGE) { + typeClass = ((RubyDescriptor) descriptor).msgclass(context); - RubyRepeatedField field = new RubyRepeatedField(context.runtime, cRepeatedField, type, typeClass); - field.setName(fieldDescriptor.getName()); - - return field; + } else if (type == FieldDescriptor.Type.ENUM) { + typeClass = ((RubyEnumDescriptor) descriptor).enummodule(context); } - private IRubyObject getFieldInternal(ThreadContext context, FieldDescriptor fieldDescriptor) { - return getFieldInternal(context, fieldDescriptor, true); - } + RubyRepeatedField field = + new RubyRepeatedField(context.runtime, cRepeatedField, type, typeClass); + field.setName(fieldDescriptor.getName()); - private IRubyObject getFieldInternal(ThreadContext context, FieldDescriptor fieldDescriptor, - boolean returnDefaults) { - OneofDescriptor oneofDescriptor = fieldDescriptor.getContainingOneof(); - if (oneofDescriptor != null) { - if (oneofCases.get(oneofDescriptor) == fieldDescriptor) { - IRubyObject value = fields.get(fieldDescriptor); - if (value == null) { - FieldDescriptor oneofCase = builder.getOneofFieldDescriptor(oneofDescriptor); - if (oneofCase != null) { - Object builderValue = builder.getField(oneofCase); - if (builderValue != null) { - boolean encodeBytes = oneofCase.hasDefaultValue() && builderValue.equals(oneofCase.getDefaultValue()); - value = wrapField(context, oneofCase, builderValue, encodeBytes); - } - } - if (value == null) { - return context.nil; - } else { - return value; - } - } else { - return value; - } - } else { - FieldDescriptor oneofCase = builder.getOneofFieldDescriptor(oneofDescriptor); - if (oneofCase != fieldDescriptor) { - if (fieldDescriptor.getType() == FieldDescriptor.Type.MESSAGE - || !returnDefaults) { - return context.nil; - } else { - return wrapField(context, fieldDescriptor, - fieldDescriptor.getDefaultValue(), true); - } - } - if (returnDefaults || builder.hasField(fieldDescriptor)) { - Object rawValue = builder.getField(oneofCase); - boolean encodeBytes = oneofCase.hasDefaultValue() && rawValue.equals(oneofCase.getDefaultValue()); - IRubyObject value = wrapField(context, oneofCase, rawValue, encodeBytes); - fields.put(fieldDescriptor, value); - return value; - } else { - return context.nil; - } - } - } + return field; + } - if (fieldDescriptor.isMapField()) { - RubyMap map = (RubyMap) fields.get(fieldDescriptor); - if (map == null) { - map = newMapForField(context, fieldDescriptor); - int mapSize = this.builder.getRepeatedFieldCount(fieldDescriptor); - FieldDescriptor keyField = fieldDescriptor.getMessageType().findFieldByNumber(1); - FieldDescriptor valueField = fieldDescriptor.getMessageType().findFieldByNumber(2); - RubyDescriptor kvDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); - RubyClass kvClass = (RubyClass) kvDescriptor.msgclass(context); - for (int i = 0; i < mapSize; i++) { - RubyMessage kvMessage = (RubyMessage) kvClass.newInstance(context, Block.NULL_BLOCK); - DynamicMessage message = (DynamicMessage) this.builder.getRepeatedField(fieldDescriptor, i); - kvMessage.buildFrom(context, message); - map.indexSet(context, kvMessage.getField(context, keyField), kvMessage.getField(context, valueField)); - } - fields.put(fieldDescriptor, map); + private IRubyObject getFieldInternal(ThreadContext context, FieldDescriptor fieldDescriptor) { + return getFieldInternal(context, fieldDescriptor, true); + } + + private IRubyObject getFieldInternal( + ThreadContext context, FieldDescriptor fieldDescriptor, boolean returnDefaults) { + OneofDescriptor oneofDescriptor = fieldDescriptor.getContainingOneof(); + if (oneofDescriptor != null) { + if (oneofCases.get(oneofDescriptor) == fieldDescriptor) { + IRubyObject value = fields.get(fieldDescriptor); + if (value == null) { + FieldDescriptor oneofCase = builder.getOneofFieldDescriptor(oneofDescriptor); + if (oneofCase != null) { + Object builderValue = builder.getField(oneofCase); + if (builderValue != null) { + boolean encodeBytes = + oneofCase.hasDefaultValue() && builderValue.equals(oneofCase.getDefaultValue()); + value = wrapField(context, oneofCase, builderValue, encodeBytes); } - return map; + } + if (value == null) { + return context.nil; + } else { + return value; + } + } else { + return value; } - - if (fieldDescriptor.isRepeated()) { - return getRepeatedField(context, fieldDescriptor); + } else { + FieldDescriptor oneofCase = builder.getOneofFieldDescriptor(oneofDescriptor); + if (oneofCase != fieldDescriptor) { + if (fieldDescriptor.getType() == FieldDescriptor.Type.MESSAGE || !returnDefaults) { + return context.nil; + } else { + return wrapField(context, fieldDescriptor, fieldDescriptor.getDefaultValue(), true); + } } - - if (fieldDescriptor.getType() != FieldDescriptor.Type.MESSAGE || - builder.hasField(fieldDescriptor) || fields.containsKey(fieldDescriptor)) { - if (fields.containsKey(fieldDescriptor)) { - return fields.get(fieldDescriptor); - } else if (returnDefaults || builder.hasField(fieldDescriptor)) { - Object rawValue = builder.getField(fieldDescriptor); - boolean encodeBytes = fieldDescriptor.hasDefaultValue() && rawValue.equals(fieldDescriptor.getDefaultValue()); - IRubyObject value = wrapField(context, fieldDescriptor, rawValue, encodeBytes); - if (builder.hasField(fieldDescriptor)) { - fields.put(fieldDescriptor, value); - } - return value; - } + if (returnDefaults || builder.hasField(fieldDescriptor)) { + Object rawValue = builder.getField(oneofCase); + boolean encodeBytes = + oneofCase.hasDefaultValue() && rawValue.equals(oneofCase.getDefaultValue()); + IRubyObject value = wrapField(context, oneofCase, rawValue, encodeBytes); + fields.put(fieldDescriptor, value); + return value; + } else { + return context.nil; } - return context.nil; + } } - private IRubyObject setFieldInternal(ThreadContext context, FieldDescriptor fieldDescriptor, IRubyObject value) { - testFrozen("can't modify frozen " + getMetaClass()); - - if (fieldDescriptor.isMapField()) { - if (!(value instanceof RubyMap)) { - throw Utils.createTypeError(context, "Expected Map instance"); - } - RubyMap thisMap = (RubyMap) getFieldInternal(context, fieldDescriptor); - thisMap.mergeIntoSelf(context, value); - - } else if (fieldDescriptor.isRepeated()) { - if (value instanceof RubyRepeatedField) { - fields.put(fieldDescriptor, value); - } else { - throw Utils.createTypeError(context, "Expected repeated field array"); - } - - } else { - boolean addValue = true; - FieldDescriptor.Type fieldType = fieldDescriptor.getType(); - OneofDescriptor oneofDescriptor = fieldDescriptor.getContainingOneof(); - - // Determine the typeclass, if any - IRubyObject typeClass = context.runtime.getObject(); - if (fieldType == FieldDescriptor.Type.MESSAGE) { - typeClass = ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context); - if (value.isNil()){ - addValue = false; - } - } else if (fieldType == FieldDescriptor.Type.ENUM) { - typeClass = ((RubyEnumDescriptor) getDescriptorForField(context, fieldDescriptor)).enummodule(context); - value = enumToSymbol(context, fieldDescriptor.getEnumType(), value); - } - - if (oneofDescriptor != null) { - FieldDescriptor oneofCase = oneofCases.get(oneofDescriptor); - - // Remove the existing field if we are setting a different field in the Oneof - if (oneofCase != null && oneofCase != fieldDescriptor) { - fields.remove(oneofCase); - } - - // Keep track of what Oneofs are set - if (value.isNil()) { - oneofCases.remove(oneofDescriptor); - if (!oneofDescriptor.isSynthetic()) { - addValue = false; - } - } else { - oneofCases.put(oneofDescriptor, fieldDescriptor); - } - } - - if (addValue) { - value = Utils.checkType(context, fieldType, fieldDescriptor.getName(), value, (RubyModule) typeClass); - fields.put(fieldDescriptor, value); - } else { - fields.remove(fieldDescriptor); - } + if (fieldDescriptor.isMapField()) { + RubyMap map = (RubyMap) fields.get(fieldDescriptor); + if (map == null) { + map = newMapForField(context, fieldDescriptor); + int mapSize = this.builder.getRepeatedFieldCount(fieldDescriptor); + FieldDescriptor keyField = fieldDescriptor.getMessageType().findFieldByNumber(1); + FieldDescriptor valueField = fieldDescriptor.getMessageType().findFieldByNumber(2); + RubyDescriptor kvDescriptor = + (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); + RubyClass kvClass = (RubyClass) kvDescriptor.msgclass(context); + for (int i = 0; i < mapSize; i++) { + RubyMessage kvMessage = (RubyMessage) kvClass.newInstance(context, Block.NULL_BLOCK); + DynamicMessage message = + (DynamicMessage) this.builder.getRepeatedField(fieldDescriptor, i); + kvMessage.buildFrom(context, message); + map.indexSet( + context, + kvMessage.getField(context, keyField), + kvMessage.getField(context, valueField)); } - return context.nil; + fields.put(fieldDescriptor, map); + } + return map; } - private IRubyObject getDescriptorForField(ThreadContext context, FieldDescriptor fieldDescriptor) { - RubyDescriptor thisRbDescriptor = (RubyDescriptor) getDescriptor(context, metaClass); - RubyFieldDescriptor fd = (RubyFieldDescriptor) thisRbDescriptor.lookup(context, context.runtime.newString(fieldDescriptor.getName())); - return fd.getSubtype(context); + if (fieldDescriptor.isRepeated()) { + return getRepeatedField(context, fieldDescriptor); } - private IRubyObject enumToSymbol(ThreadContext context, EnumDescriptor enumDescriptor, IRubyObject value) { - if (value instanceof RubySymbol) { - return (RubySymbol) value; - } else if (Utils.isRubyNum(value)) { - EnumValueDescriptor enumValue = enumDescriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value)); - if (enumValue.getIndex() != -1) { - return context.runtime.newSymbol(enumValue.getName()); - } else { - return value; - } - } else if (value instanceof RubyString) { - return ((RubyString) value).intern(); + if (fieldDescriptor.getType() != FieldDescriptor.Type.MESSAGE + || builder.hasField(fieldDescriptor) + || fields.containsKey(fieldDescriptor)) { + if (fields.containsKey(fieldDescriptor)) { + return fields.get(fieldDescriptor); + } else if (returnDefaults || builder.hasField(fieldDescriptor)) { + Object rawValue = builder.getField(fieldDescriptor); + boolean encodeBytes = + fieldDescriptor.hasDefaultValue() && rawValue.equals(fieldDescriptor.getDefaultValue()); + IRubyObject value = wrapField(context, fieldDescriptor, rawValue, encodeBytes); + if (builder.hasField(fieldDescriptor)) { + fields.put(fieldDescriptor, value); } - - return context.runtime.newSymbol("UNKNOWN"); + return value; + } } + return context.nil; + } - private RubyRepeatedField rubyToRepeatedField(ThreadContext context, - FieldDescriptor fieldDescriptor, IRubyObject value) { - RubyArray arr = value.convertToArray(); - RubyRepeatedField repeatedField = repeatedFieldForFieldDescriptor(context, fieldDescriptor); - IRubyObject[] values = new IRubyObject[arr.size()]; - FieldDescriptor.Type fieldType = fieldDescriptor.getType(); - - RubyModule typeClass = null; - if (fieldType == FieldDescriptor.Type.MESSAGE) { - RubyDescriptor descriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); - typeClass = (RubyModule) descriptor.msgclass(context); - } else if (fieldType == FieldDescriptor.Type.ENUM) { - RubyEnumDescriptor enumDescriptor = (RubyEnumDescriptor) getDescriptorForField(context, fieldDescriptor); - typeClass = (RubyModule) enumDescriptor.enummodule(context); - } + private IRubyObject setFieldInternal( + ThreadContext context, FieldDescriptor fieldDescriptor, IRubyObject value) { + testFrozen("can't modify frozen " + getMetaClass()); - for (int i = 0; i < arr.size(); i++) { - IRubyObject item = arr.eltInternal(i); - if (item.isNil()) { - throw Utils.createTypeError(context, "nil message not allowed here."); - } - if (item instanceof RubyHash && typeClass != null) { - values[i] = ((RubyClass) typeClass).newInstance(context, item, Block.NULL_BLOCK); - } else { - if (fieldType == FieldDescriptor.Type.ENUM) { - item = enumToSymbol(context, fieldDescriptor.getEnumType(), item); - } + if (fieldDescriptor.isMapField()) { + if (!(value instanceof RubyMap)) { + throw Utils.createTypeError(context, "Expected Map instance"); + } + RubyMap thisMap = (RubyMap) getFieldInternal(context, fieldDescriptor); + thisMap.mergeIntoSelf(context, value); + + } else if (fieldDescriptor.isRepeated()) { + if (value instanceof RubyRepeatedField) { + fields.put(fieldDescriptor, value); + } else { + throw Utils.createTypeError(context, "Expected repeated field array"); + } - values[i] = item; - } + } else { + boolean addValue = true; + FieldDescriptor.Type fieldType = fieldDescriptor.getType(); + OneofDescriptor oneofDescriptor = fieldDescriptor.getContainingOneof(); + + // Determine the typeclass, if any + IRubyObject typeClass = context.runtime.getObject(); + if (fieldType == FieldDescriptor.Type.MESSAGE) { + typeClass = + ((RubyDescriptor) getDescriptorForField(context, fieldDescriptor)).msgclass(context); + if (value.isNil()) { + addValue = false; } - repeatedField.push(context, values); + } else if (fieldType == FieldDescriptor.Type.ENUM) { + typeClass = + ((RubyEnumDescriptor) getDescriptorForField(context, fieldDescriptor)) + .enummodule(context); + value = enumToSymbol(context, fieldDescriptor.getEnumType(), value); + } - return repeatedField; - } + if (oneofDescriptor != null) { + FieldDescriptor oneofCase = oneofCases.get(oneofDescriptor); - private RubyMap newMapForField(ThreadContext context, FieldDescriptor fieldDescriptor) { - RubyDescriptor mapDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); - FieldDescriptor keyField = fieldDescriptor.getMessageType().findFieldByNumber(1); - FieldDescriptor valueField = fieldDescriptor.getMessageType().findFieldByNumber(2); - IRubyObject keyType = RubySymbol.newSymbol(context.runtime, keyField.getType().name()); - IRubyObject valueType = RubySymbol.newSymbol(context.runtime, valueField.getType().name()); - - if (valueField.getType() == FieldDescriptor.Type.MESSAGE) { - RubyFieldDescriptor rubyFieldDescriptor = (RubyFieldDescriptor) mapDescriptor.lookup(context, - context.runtime.newString("value")); - RubyDescriptor rubyDescriptor = (RubyDescriptor) rubyFieldDescriptor.getSubtype(context); - return (RubyMap) cMap.newInstance(context, keyType, valueType, - rubyDescriptor.msgclass(context), Block.NULL_BLOCK); - - } else if (valueField.getType() == FieldDescriptor.Type.ENUM) { - RubyFieldDescriptor rubyFieldDescriptor = (RubyFieldDescriptor) mapDescriptor.lookup(context, - context.runtime.newString("value")); - RubyEnumDescriptor rubyEnumDescriptor = (RubyEnumDescriptor) rubyFieldDescriptor.getSubtype(context); - return (RubyMap) cMap.newInstance(context, keyType, valueType, - rubyEnumDescriptor.enummodule(context), Block.NULL_BLOCK); + // Remove the existing field if we are setting a different field in the Oneof + if (oneofCase != null && oneofCase != fieldDescriptor) { + fields.remove(oneofCase); + } + // Keep track of what Oneofs are set + if (value.isNil()) { + oneofCases.remove(oneofDescriptor); + if (!oneofDescriptor.isSynthetic()) { + addValue = false; + } } else { - return (RubyMap) cMap.newInstance(context, keyType, valueType, Block.NULL_BLOCK); + oneofCases.put(oneofDescriptor, fieldDescriptor); } - } - - private boolean isWrappable(FieldDescriptor fieldDescriptor) { - if (fieldDescriptor.getType() != FieldDescriptor.Type.MESSAGE) return false; + } - return isWrapper(fieldDescriptor.getMessageType()); + if (addValue) { + value = + Utils.checkType( + context, fieldType, fieldDescriptor.getName(), value, (RubyModule) typeClass); + fields.put(fieldDescriptor, value); + } else { + fields.remove(fieldDescriptor); + } } - - private static boolean isWrapper(Descriptor messageDescriptor) { - switch(messageDescriptor.getFullName()) { - case "google.protobuf.DoubleValue": - case "google.protobuf.FloatValue": - case "google.protobuf.Int64Value": - case "google.protobuf.UInt64Value": - case "google.protobuf.Int32Value": - case "google.protobuf.UInt32Value": - case "google.protobuf.BoolValue": - case "google.protobuf.StringValue": - case "google.protobuf.BytesValue": - return true; - default: - return false; + return context.nil; + } + + private IRubyObject getDescriptorForField( + ThreadContext context, FieldDescriptor fieldDescriptor) { + RubyDescriptor thisRbDescriptor = (RubyDescriptor) getDescriptor(context, metaClass); + RubyFieldDescriptor fd = + (RubyFieldDescriptor) + thisRbDescriptor.lookup(context, context.runtime.newString(fieldDescriptor.getName())); + return fd.getSubtype(context); + } + + private IRubyObject enumToSymbol( + ThreadContext context, EnumDescriptor enumDescriptor, IRubyObject value) { + if (value instanceof RubySymbol) { + return (RubySymbol) value; + } else if (Utils.isRubyNum(value)) { + EnumValueDescriptor enumValue = + enumDescriptor.findValueByNumberCreatingIfUnknown(RubyNumeric.num2int(value)); + if (enumValue.getIndex() != -1) { + return context.runtime.newSymbol(enumValue.getName()); + } else { + return value; } + } else if (value instanceof RubyString) { + return ((RubyString) value).intern(); + } + + return context.runtime.newSymbol("UNKNOWN"); + } + + private RubyRepeatedField rubyToRepeatedField( + ThreadContext context, FieldDescriptor fieldDescriptor, IRubyObject value) { + RubyArray arr = value.convertToArray(); + RubyRepeatedField repeatedField = repeatedFieldForFieldDescriptor(context, fieldDescriptor); + IRubyObject[] values = new IRubyObject[arr.size()]; + FieldDescriptor.Type fieldType = fieldDescriptor.getType(); + + RubyModule typeClass = null; + if (fieldType == FieldDescriptor.Type.MESSAGE) { + RubyDescriptor descriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); + typeClass = (RubyModule) descriptor.msgclass(context); + } else if (fieldType == FieldDescriptor.Type.ENUM) { + RubyEnumDescriptor enumDescriptor = + (RubyEnumDescriptor) getDescriptorForField(context, fieldDescriptor); + typeClass = (RubyModule) enumDescriptor.enummodule(context); } - private void validateMessageType(ThreadContext context, FieldDescriptor fieldDescriptor, String methodName) { - if (descriptor != fieldDescriptor.getContainingType()) { - throw Utils.createTypeError(context, methodName + " method called on wrong message type"); + for (int i = 0; i < arr.size(); i++) { + IRubyObject item = arr.eltInternal(i); + if (item.isNil()) { + throw Utils.createTypeError(context, "nil message not allowed here."); + } + if (item instanceof RubyHash && typeClass != null) { + values[i] = ((RubyClass) typeClass).newInstance(context, item, Block.NULL_BLOCK); + } else { + if (fieldType == FieldDescriptor.Type.ENUM) { + item = enumToSymbol(context, fieldDescriptor.getEnumType(), item); } + + values[i] = item; + } + } + repeatedField.push(context, values); + + return repeatedField; + } + + private RubyMap newMapForField(ThreadContext context, FieldDescriptor fieldDescriptor) { + RubyDescriptor mapDescriptor = (RubyDescriptor) getDescriptorForField(context, fieldDescriptor); + FieldDescriptor keyField = fieldDescriptor.getMessageType().findFieldByNumber(1); + FieldDescriptor valueField = fieldDescriptor.getMessageType().findFieldByNumber(2); + IRubyObject keyType = RubySymbol.newSymbol(context.runtime, keyField.getType().name()); + IRubyObject valueType = RubySymbol.newSymbol(context.runtime, valueField.getType().name()); + + if (valueField.getType() == FieldDescriptor.Type.MESSAGE) { + RubyFieldDescriptor rubyFieldDescriptor = + (RubyFieldDescriptor) mapDescriptor.lookup(context, context.runtime.newString("value")); + RubyDescriptor rubyDescriptor = (RubyDescriptor) rubyFieldDescriptor.getSubtype(context); + return (RubyMap) + cMap.newInstance( + context, keyType, valueType, rubyDescriptor.msgclass(context), Block.NULL_BLOCK); + + } else if (valueField.getType() == FieldDescriptor.Type.ENUM) { + RubyFieldDescriptor rubyFieldDescriptor = + (RubyFieldDescriptor) mapDescriptor.lookup(context, context.runtime.newString("value")); + RubyEnumDescriptor rubyEnumDescriptor = + (RubyEnumDescriptor) rubyFieldDescriptor.getSubtype(context); + return (RubyMap) + cMap.newInstance( + context, + keyType, + valueType, + rubyEnumDescriptor.enummodule(context), + Block.NULL_BLOCK); + + } else { + return (RubyMap) cMap.newInstance(context, keyType, valueType, Block.NULL_BLOCK); } + } + + private boolean isWrappable(FieldDescriptor fieldDescriptor) { + if (fieldDescriptor.getType() != FieldDescriptor.Type.MESSAGE) return false; + + return isWrapper(fieldDescriptor.getMessageType()); + } + + private static boolean isWrapper(Descriptor messageDescriptor) { + switch (messageDescriptor.getFullName()) { + case "google.protobuf.DoubleValue": + case "google.protobuf.FloatValue": + case "google.protobuf.Int64Value": + case "google.protobuf.UInt64Value": + case "google.protobuf.Int32Value": + case "google.protobuf.UInt32Value": + case "google.protobuf.BoolValue": + case "google.protobuf.StringValue": + case "google.protobuf.BytesValue": + return true; + default: + return false; + } + } - private static RubyClass parseErrorClass; - - private static final String AS_VALUE_SUFFIX = "_as_value"; - private static final String CLEAR_PREFIX = "clear_"; - private static final String CONST_SUFFIX = "_const"; - private static final String HAS_PREFIX = "has_"; - private static final String QUESTION_MARK = "?"; - private static final int SINK_MAXIMUM_NESTING = 64; - - private Descriptor descriptor; - private DynamicMessage.Builder builder; - private Map fields; - private Map oneofCases; - private RubyClass cRepeatedField; - private RubyClass cMap; - private boolean ignoreUnknownFieldsOnInit = false; - private boolean proto3; + private void validateMessageType( + ThreadContext context, FieldDescriptor fieldDescriptor, String methodName) { + if (descriptor != fieldDescriptor.getContainingType()) { + throw Utils.createTypeError(context, methodName + " method called on wrong message type"); + } + } + + private static RubyClass parseErrorClass; + + private static final String AS_VALUE_SUFFIX = "_as_value"; + private static final String CLEAR_PREFIX = "clear_"; + private static final String CONST_SUFFIX = "_const"; + private static final String HAS_PREFIX = "has_"; + private static final String QUESTION_MARK = "?"; + private static final int SINK_MAXIMUM_NESTING = 64; + + private Descriptor descriptor; + private DynamicMessage.Builder builder; + private Map fields; + private Map oneofCases; + private RubyClass cRepeatedField; + private RubyClass cMap; + private boolean ignoreUnknownFieldsOnInit = false; + private boolean proto3; } diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java index 6f2ebdb45f27..5ade98b7f32b 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyOneofDescriptor.java @@ -2,6 +2,10 @@ import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Descriptors.OneofDescriptor; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyModule; @@ -13,74 +17,76 @@ import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - @JRubyClass(name = "OneofDescriptor", include = "Enumerable") public class RubyOneofDescriptor extends RubyObject { - public static void createRubyOneofDescriptor(Ruby runtime) { - RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); - RubyClass cRubyOneofDescriptor = protobuf.defineClassUnder("OneofDescriptor", runtime.getObject(), new ObjectAllocator() { - @Override - public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) { + public static void createRubyOneofDescriptor(Ruby runtime) { + RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); + RubyClass cRubyOneofDescriptor = + protobuf.defineClassUnder( + "OneofDescriptor", + runtime.getObject(), + new ObjectAllocator() { + @Override + public IRubyObject allocate(Ruby ruby, RubyClass rubyClass) { return new RubyOneofDescriptor(ruby, rubyClass); - } - }); - cRubyOneofDescriptor.defineAnnotatedMethods(RubyOneofDescriptor.class); - cRubyOneofDescriptor.includeModule(runtime.getEnumerable()); - } + } + }); + cRubyOneofDescriptor.defineAnnotatedMethods(RubyOneofDescriptor.class); + cRubyOneofDescriptor.includeModule(runtime.getEnumerable()); + } - public RubyOneofDescriptor(Ruby ruby, RubyClass rubyClass) { - super(ruby, rubyClass); - fields = new ArrayList(); - } + public RubyOneofDescriptor(Ruby ruby, RubyClass rubyClass) { + super(ruby, rubyClass); + fields = new ArrayList(); + } - /* - * call-seq: - * OneofDescriptor.name => name - * - * Returns the name of this oneof. - */ - @JRubyMethod(name = "name") - public IRubyObject getName(ThreadContext context) { - return name; - } + /* + * call-seq: + * OneofDescriptor.name => name + * + * Returns the name of this oneof. + */ + @JRubyMethod(name = "name") + public IRubyObject getName(ThreadContext context) { + return name; + } - /* - * call-seq: - * OneofDescriptor.each(&block) => nil - * - * Iterates through fields in this oneof, yielding to the block on each one. - */ - @JRubyMethod - public IRubyObject each(ThreadContext context, Block block) { - for (RubyFieldDescriptor field : fields) { - block.yieldSpecific(context, field); - } - return context.nil; + /* + * call-seq: + * OneofDescriptor.each(&block) => nil + * + * Iterates through fields in this oneof, yielding to the block on each one. + */ + @JRubyMethod + public IRubyObject each(ThreadContext context, Block block) { + for (RubyFieldDescriptor field : fields) { + block.yieldSpecific(context, field); } + return context.nil; + } - protected Collection getFields() { - return fields; - } + protected Collection getFields() { + return fields; + } - protected OneofDescriptor getDescriptor() { - return descriptor; - } + protected OneofDescriptor getDescriptor() { + return descriptor; + } - protected void setDescriptor(ThreadContext context, OneofDescriptor descriptor, Map fieldCache) { - this.descriptor = descriptor; - this.name = context.runtime.newString(descriptor.getName()); + protected void setDescriptor( + ThreadContext context, + OneofDescriptor descriptor, + Map fieldCache) { + this.descriptor = descriptor; + this.name = context.runtime.newString(descriptor.getName()); - for (FieldDescriptor fd : descriptor.getFields()) { - fields.add(fieldCache.get(fd)); - } + for (FieldDescriptor fd : descriptor.getFields()) { + fields.add(fieldCache.get(fd)); } + } - private IRubyObject name; - private List fields; - private OneofDescriptor descriptor; + private IRubyObject name; + private List fields; + private OneofDescriptor descriptor; } diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java index 582c675b2b2e..8d132be348ff 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyProtobuf.java @@ -42,41 +42,42 @@ @JRubyModule(name = "Protobuf") public class RubyProtobuf { - public static void createProtobuf(Ruby runtime) { - RubyModule mGoogle = runtime.getModule("Google"); - RubyModule mProtobuf = mGoogle.defineModuleUnder("Protobuf"); - mProtobuf.defineAnnotatedMethods(RubyProtobuf.class); - RubyModule mInternal = mProtobuf.defineModuleUnder("Internal"); - } + public static void createProtobuf(Ruby runtime) { + RubyModule mGoogle = runtime.getModule("Google"); + RubyModule mProtobuf = mGoogle.defineModuleUnder("Protobuf"); + mProtobuf.defineAnnotatedMethods(RubyProtobuf.class); + RubyModule mInternal = mProtobuf.defineModuleUnder("Internal"); + } - /* - * call-seq: - * Google::Protobuf.deep_copy(obj) => copy_of_obj - * - * Performs a deep copy of either a RepeatedField instance or a message object, - * recursively copying its members. - */ - @JRubyMethod(name = "deep_copy", meta = true) - public static IRubyObject deepCopy(ThreadContext context, IRubyObject self, IRubyObject message) { - if (message instanceof RubyMessage) { - return ((RubyMessage) message).deepCopy(context); - } else if (message instanceof RubyRepeatedField) { - return ((RubyRepeatedField) message).deepCopy(context); - } else { - return ((RubyMap) message).deepCopy(context); - } + /* + * call-seq: + * Google::Protobuf.deep_copy(obj) => copy_of_obj + * + * Performs a deep copy of either a RepeatedField instance or a message object, + * recursively copying its members. + */ + @JRubyMethod(name = "deep_copy", meta = true) + public static IRubyObject deepCopy(ThreadContext context, IRubyObject self, IRubyObject message) { + if (message instanceof RubyMessage) { + return ((RubyMessage) message).deepCopy(context); + } else if (message instanceof RubyRepeatedField) { + return ((RubyRepeatedField) message).deepCopy(context); + } else { + return ((RubyMap) message).deepCopy(context); } + } - /* - * call-seq: - * Google::Protobuf.discard_unknown(msg) - * - * Discard unknown fields in the given message object and recursively discard - * unknown fields in submessages. - */ - @JRubyMethod(name = "discard_unknown", meta = true) - public static IRubyObject discardUnknown(ThreadContext context, IRubyObject self, IRubyObject message) { - ((RubyMessage) message).discardUnknownFields(context); - return context.nil; - } + /* + * call-seq: + * Google::Protobuf.discard_unknown(msg) + * + * Discard unknown fields in the given message object and recursively discard + * unknown fields in submessages. + */ + @JRubyMethod(name = "discard_unknown", meta = true) + public static IRubyObject discardUnknown( + ThreadContext context, IRubyObject self, IRubyObject message) { + ((RubyMessage) message).discardUnknownFields(context); + return context.nil; + } } diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java index 995171fc7b2e..883d480c67c0 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java @@ -40,384 +40,391 @@ import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; -import java.util.Arrays; @JRubyClass(name = "RepeatedClass", include = "Enumerable") public class RubyRepeatedField extends RubyObject { - public static void createRubyRepeatedField(Ruby runtime) { - RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf"); - RubyClass cRepeatedField = mProtobuf.defineClassUnder("RepeatedField", runtime.getObject(), - new ObjectAllocator() { - @Override - public IRubyObject allocate(Ruby runtime, RubyClass klazz) { - return new RubyRepeatedField(runtime, klazz); - } - }); - cRepeatedField.defineAnnotatedMethods(RubyRepeatedField.class); - cRepeatedField.includeModule(runtime.getEnumerable()); + public static void createRubyRepeatedField(Ruby runtime) { + RubyModule mProtobuf = runtime.getClassFromPath("Google::Protobuf"); + RubyClass cRepeatedField = + mProtobuf.defineClassUnder( + "RepeatedField", + runtime.getObject(), + new ObjectAllocator() { + @Override + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new RubyRepeatedField(runtime, klazz); + } + }); + cRepeatedField.defineAnnotatedMethods(RubyRepeatedField.class); + cRepeatedField.includeModule(runtime.getEnumerable()); + } + + public RubyRepeatedField(Ruby runtime, RubyClass klazz) { + super(runtime, klazz); + } + + public RubyRepeatedField( + Ruby runtime, RubyClass klazz, FieldDescriptor.Type fieldType, IRubyObject typeClass) { + this(runtime, klazz); + this.fieldType = fieldType; + this.storage = runtime.newArray(); + this.typeClass = typeClass; + } + + @JRubyMethod(required = 1, optional = 2) + public IRubyObject initialize(ThreadContext context, IRubyObject[] args) { + Ruby runtime = context.runtime; + this.storage = runtime.newArray(); + IRubyObject ary = null; + if (!(args[0] instanceof RubySymbol)) { + throw runtime.newArgumentError("Expected Symbol for type name"); } - - public RubyRepeatedField(Ruby runtime, RubyClass klazz) { - super(runtime, klazz); - } - - public RubyRepeatedField(Ruby runtime, RubyClass klazz, FieldDescriptor.Type fieldType, IRubyObject typeClass) { - this(runtime, klazz); - this.fieldType = fieldType; - this.storage = runtime.newArray(); - this.typeClass = typeClass; - } - - @JRubyMethod(required = 1, optional = 2) - public IRubyObject initialize(ThreadContext context, IRubyObject[] args) { - Ruby runtime = context.runtime; - this.storage = runtime.newArray(); - IRubyObject ary = null; - if (!(args[0] instanceof RubySymbol)) { - throw runtime.newArgumentError("Expected Symbol for type name"); - } - this.fieldType = Utils.rubyToFieldType(args[0]); - if (fieldType == FieldDescriptor.Type.MESSAGE - || fieldType == FieldDescriptor.Type.ENUM) { - if (args.length < 2) - throw runtime.newArgumentError("Expected at least 2 arguments for message/enum"); - typeClass = args[1]; - if (args.length > 2) - ary = args[2]; - Utils.validateTypeClass(context, fieldType, typeClass); - } else { - if (args.length > 2) - throw runtime.newArgumentError("Too many arguments: expected 1 or 2"); - if (args.length > 1) - ary = args[1]; - } - if (ary != null) { - RubyArray arr = ary.convertToArray(); - for (int i = 0; i < arr.size(); i++) { - this.storage.add(arr.eltInternal(i)); - } - } - return this; - } - - /* - * call-seq: - * RepeatedField.[]=(index, value) - * - * Sets the element at the given index. On out-of-bounds assignments, extends - * the array and fills the hole (if any) with default values. - */ - @JRubyMethod(name = "[]=") - public IRubyObject indexSet(ThreadContext context, IRubyObject index, IRubyObject value) { - int arrIndex = normalizeArrayIndex(index); - value = Utils.checkType(context, fieldType, name, value, (RubyModule) typeClass); - IRubyObject defaultValue = defaultValue(context); - for (int i = this.storage.size(); i < arrIndex; i++) { - this.storage.set(i, defaultValue); - } - this.storage.set(arrIndex, value); - return context.runtime.getNil(); - } - - /* - * call-seq: - * RepeatedField.[](index) => value - * - * Accesses the element at the given index. Returns nil on out-of-bounds - */ - @JRubyMethod(required=1, optional=1, name = {"at", "[]"}) - public IRubyObject index(ThreadContext context, IRubyObject[] args) { - if (args.length == 1){ - IRubyObject arg = args[0]; - if (Utils.isRubyNum(arg)) { - /* standard case */ - int arrIndex = normalizeArrayIndex(arg); - if (arrIndex < 0 || arrIndex >= this.storage.size()) { - return context.runtime.getNil(); - } - return this.storage.eltInternal(arrIndex); - } else if (arg instanceof RubyRange) { - RubyRange range = ((RubyRange) arg); - - int beg = RubyNumeric.num2int(range.first(context)); - int len = RubyNumeric.num2int(range.size(context)); - - if (len == 0) return context.runtime.newEmptyArray(); - - return this.storage.subseq(beg, len); - } - } - /* assume 2 arguments */ - int beg = RubyNumeric.num2int(args[0]); - int len = RubyNumeric.num2int(args[1]); - if (beg < 0) { - beg += this.storage.size(); - } - if (beg >= this.storage.size()) { - return context.runtime.getNil(); - } - return this.storage.subseq(beg, len); - } - - /* - * call-seq: - * RepeatedField.push(value) - * - * Adds a new element to the repeated field. - */ - @JRubyMethod(name = {"push", "<<"}, required = 1, rest = true) - public IRubyObject push(ThreadContext context, IRubyObject[] args) { - for (int i = 0; i < args.length; i++) { - IRubyObject val = args[i]; - if (fieldType != FieldDescriptor.Type.MESSAGE || !val.isNil()) { - val = Utils.checkType(context, fieldType, name, val, (RubyModule) typeClass); - } - storage.add(val); - } - - return this; - } - - /* - * private Ruby method used by RepeatedField.pop - */ - @JRubyMethod(visibility = org.jruby.runtime.Visibility.PRIVATE) - public IRubyObject pop_one(ThreadContext context) { - IRubyObject ret = this.storage.last(); - this.storage.remove(ret); - return ret; - } - - /* - * call-seq: - * RepeatedField.replace(list) - * - * Replaces the contents of the repeated field with the given list of elements. - */ - @JRubyMethod - public IRubyObject replace(ThreadContext context, IRubyObject list) { - RubyArray arr = (RubyArray) list; - checkArrayElementType(context, arr); - this.storage = arr; - return this; + this.fieldType = Utils.rubyToFieldType(args[0]); + if (fieldType == FieldDescriptor.Type.MESSAGE || fieldType == FieldDescriptor.Type.ENUM) { + if (args.length < 2) + throw runtime.newArgumentError("Expected at least 2 arguments for message/enum"); + typeClass = args[1]; + if (args.length > 2) ary = args[2]; + Utils.validateTypeClass(context, fieldType, typeClass); + } else { + if (args.length > 2) throw runtime.newArgumentError("Too many arguments: expected 1 or 2"); + if (args.length > 1) ary = args[1]; } - - /* - * call-seq: - * RepeatedField.clear - * - * Clears (removes all elements from) this repeated field. - */ - @JRubyMethod - public IRubyObject clear(ThreadContext context) { - this.storage.clear(); - return this; + if (ary != null) { + RubyArray arr = ary.convertToArray(); + for (int i = 0; i < arr.size(); i++) { + this.storage.add(arr.eltInternal(i)); + } } - - /* - * call-seq: - * RepeatedField.length - * - * Returns the length of this repeated field. - */ - @JRubyMethod(name = {"length", "size"}) - public IRubyObject length(ThreadContext context) { - return context.runtime.newFixnum(this.storage.size()); + return this; + } + + /* + * call-seq: + * RepeatedField.[]=(index, value) + * + * Sets the element at the given index. On out-of-bounds assignments, extends + * the array and fills the hole (if any) with default values. + */ + @JRubyMethod(name = "[]=") + public IRubyObject indexSet(ThreadContext context, IRubyObject index, IRubyObject value) { + int arrIndex = normalizeArrayIndex(index); + value = Utils.checkType(context, fieldType, name, value, (RubyModule) typeClass); + IRubyObject defaultValue = defaultValue(context); + for (int i = this.storage.size(); i < arrIndex; i++) { + this.storage.set(i, defaultValue); } - - /* - * call-seq: - * RepeatedField.+(other) => repeated field - * - * Returns a new repeated field that contains the concatenated list of this - * repeated field's elements and other's elements. The other (second) list may - * be either another repeated field or a Ruby array. - */ - @JRubyMethod(name = {"+"}) - public IRubyObject plus(ThreadContext context, IRubyObject list) { - RubyRepeatedField dup = (RubyRepeatedField) dup(context); - if (list instanceof RubyArray) { - checkArrayElementType(context, (RubyArray) list); - dup.storage.addAll((RubyArray) list); - } else { - RubyRepeatedField repeatedField = (RubyRepeatedField) list; - if (! fieldType.equals(repeatedField.fieldType) || (typeClass != null && ! - typeClass.equals(repeatedField.typeClass))) - throw context.runtime.newArgumentError("Attempt to append RepeatedField with different element type."); - dup.storage.addAll((RubyArray) repeatedField.toArray(context)); + this.storage.set(arrIndex, value); + return context.runtime.getNil(); + } + + /* + * call-seq: + * RepeatedField.[](index) => value + * + * Accesses the element at the given index. Returns nil on out-of-bounds + */ + @JRubyMethod( + required = 1, + optional = 1, + name = {"at", "[]"}) + public IRubyObject index(ThreadContext context, IRubyObject[] args) { + if (args.length == 1) { + IRubyObject arg = args[0]; + if (Utils.isRubyNum(arg)) { + /* standard case */ + int arrIndex = normalizeArrayIndex(arg); + if (arrIndex < 0 || arrIndex >= this.storage.size()) { + return context.runtime.getNil(); } - return dup; - } + return this.storage.eltInternal(arrIndex); + } else if (arg instanceof RubyRange) { + RubyRange range = ((RubyRange) arg); - /* - * call-seq: - * RepeatedField.concat(other) => self - * - * concats the passed in array to self. Returns a Ruby array. - */ - @JRubyMethod - public IRubyObject concat(ThreadContext context, IRubyObject list) { - if (list instanceof RubyArray) { - checkArrayElementType(context, (RubyArray) list); - this.storage.addAll((RubyArray) list); - } else { - RubyRepeatedField repeatedField = (RubyRepeatedField) list; - if (! fieldType.equals(repeatedField.fieldType) || (typeClass != null && ! - typeClass.equals(repeatedField.typeClass))) - throw context.runtime.newArgumentError("Attempt to append RepeatedField with different element type."); - this.storage.addAll((RubyArray) repeatedField.toArray(context)); - } - return this; - } - - /* - * call-seq: - * RepeatedField.hash => hash_value - * - * Returns a hash value computed from this repeated field's elements. - */ - @JRubyMethod - public IRubyObject hash(ThreadContext context) { - int hashCode = this.storage.hashCode(); - return context.runtime.newFixnum(hashCode); - } - - /* - * call-seq: - * RepeatedField.==(other) => boolean - * - * Compares this repeated field to another. Repeated fields are equal if their - * element types are equal, their lengths are equal, and each element is equal. - * Elements are compared as per normal Ruby semantics, by calling their :== - * methods (or performing a more efficient comparison for primitive types). - */ - @JRubyMethod(name = "==") - public IRubyObject eq(ThreadContext context, IRubyObject other) { - return this.toArray(context).op_equal(context, other); - } - - /* - * call-seq: - * RepeatedField.each(&block) - * - * Invokes the block once for each element of the repeated field. RepeatedField - * also includes Enumerable; combined with this method, the repeated field thus - * acts like an ordinary Ruby sequence. - */ - @JRubyMethod - public IRubyObject each(ThreadContext context, Block block) { - this.storage.each(context, block); - return this; - } + int beg = RubyNumeric.num2int(range.first(context)); + int len = RubyNumeric.num2int(range.size(context)); + if (len == 0) return context.runtime.newEmptyArray(); - @JRubyMethod(name = {"to_ary", "to_a"}) - public IRubyObject toArray(ThreadContext context) { - return this.storage; + return this.storage.subseq(beg, len); + } } - - /* - * call-seq: - * RepeatedField.dup => repeated_field - * - * Duplicates this repeated field with a shallow copy. References to all - * non-primitive element objects (e.g., submessages) are shared. - */ - @JRubyMethod - public IRubyObject dup(ThreadContext context) { - RubyRepeatedField dup = new RubyRepeatedField(context.runtime, metaClass, fieldType, typeClass); - dup.push(context, storage.toJavaArray()); - return dup; + /* assume 2 arguments */ + int beg = RubyNumeric.num2int(args[0]); + int len = RubyNumeric.num2int(args[1]); + if (beg < 0) { + beg += this.storage.size(); } - - @JRubyMethod - public IRubyObject inspect() { - return storage.inspect(); + if (beg >= this.storage.size()) { + return context.runtime.getNil(); } - - // Java API - protected IRubyObject get(int index) { - return this.storage.eltInternal(index); + return this.storage.subseq(beg, len); + } + + /* + * call-seq: + * RepeatedField.push(value) + * + * Adds a new element to the repeated field. + */ + @JRubyMethod( + name = {"push", "<<"}, + required = 1, + rest = true) + public IRubyObject push(ThreadContext context, IRubyObject[] args) { + for (int i = 0; i < args.length; i++) { + IRubyObject val = args[i]; + if (fieldType != FieldDescriptor.Type.MESSAGE || !val.isNil()) { + val = Utils.checkType(context, fieldType, name, val, (RubyModule) typeClass); + } + storage.add(val); } - protected RubyRepeatedField deepCopy(ThreadContext context) { - RubyRepeatedField copy = new RubyRepeatedField(context.runtime, metaClass, fieldType, typeClass); - for (int i = 0; i < size(); i++) { - IRubyObject value = storage.eltInternal(i); - if (fieldType == FieldDescriptor.Type.MESSAGE) { - copy.storage.add(((RubyMessage) value).deepCopy(context)); - } else { - copy.storage.add(value); - } - } - return copy; + return this; + } + + /* + * private Ruby method used by RepeatedField.pop + */ + @JRubyMethod(visibility = org.jruby.runtime.Visibility.PRIVATE) + public IRubyObject pop_one(ThreadContext context) { + IRubyObject ret = this.storage.last(); + this.storage.remove(ret); + return ret; + } + + /* + * call-seq: + * RepeatedField.replace(list) + * + * Replaces the contents of the repeated field with the given list of elements. + */ + @JRubyMethod + public IRubyObject replace(ThreadContext context, IRubyObject list) { + RubyArray arr = (RubyArray) list; + checkArrayElementType(context, arr); + this.storage = arr; + return this; + } + + /* + * call-seq: + * RepeatedField.clear + * + * Clears (removes all elements from) this repeated field. + */ + @JRubyMethod + public IRubyObject clear(ThreadContext context) { + this.storage.clear(); + return this; + } + + /* + * call-seq: + * RepeatedField.length + * + * Returns the length of this repeated field. + */ + @JRubyMethod(name = {"length", "size"}) + public IRubyObject length(ThreadContext context) { + return context.runtime.newFixnum(this.storage.size()); + } + + /* + * call-seq: + * RepeatedField.+(other) => repeated field + * + * Returns a new repeated field that contains the concatenated list of this + * repeated field's elements and other's elements. The other (second) list may + * be either another repeated field or a Ruby array. + */ + @JRubyMethod(name = {"+"}) + public IRubyObject plus(ThreadContext context, IRubyObject list) { + RubyRepeatedField dup = (RubyRepeatedField) dup(context); + if (list instanceof RubyArray) { + checkArrayElementType(context, (RubyArray) list); + dup.storage.addAll((RubyArray) list); + } else { + RubyRepeatedField repeatedField = (RubyRepeatedField) list; + if (!fieldType.equals(repeatedField.fieldType) + || (typeClass != null && !typeClass.equals(repeatedField.typeClass))) + throw context.runtime.newArgumentError( + "Attempt to append RepeatedField with different element type."); + dup.storage.addAll((RubyArray) repeatedField.toArray(context)); } - - protected void setName(String name) { - this.name = name; + return dup; + } + + /* + * call-seq: + * RepeatedField.concat(other) => self + * + * concats the passed in array to self. Returns a Ruby array. + */ + @JRubyMethod + public IRubyObject concat(ThreadContext context, IRubyObject list) { + if (list instanceof RubyArray) { + checkArrayElementType(context, (RubyArray) list); + this.storage.addAll((RubyArray) list); + } else { + RubyRepeatedField repeatedField = (RubyRepeatedField) list; + if (!fieldType.equals(repeatedField.fieldType) + || (typeClass != null && !typeClass.equals(repeatedField.typeClass))) + throw context.runtime.newArgumentError( + "Attempt to append RepeatedField with different element type."); + this.storage.addAll((RubyArray) repeatedField.toArray(context)); } - - protected int size() { - return this.storage.size(); + return this; + } + + /* + * call-seq: + * RepeatedField.hash => hash_value + * + * Returns a hash value computed from this repeated field's elements. + */ + @JRubyMethod + public IRubyObject hash(ThreadContext context) { + int hashCode = this.storage.hashCode(); + return context.runtime.newFixnum(hashCode); + } + + /* + * call-seq: + * RepeatedField.==(other) => boolean + * + * Compares this repeated field to another. Repeated fields are equal if their + * element types are equal, their lengths are equal, and each element is equal. + * Elements are compared as per normal Ruby semantics, by calling their :== + * methods (or performing a more efficient comparison for primitive types). + */ + @JRubyMethod(name = "==") + public IRubyObject eq(ThreadContext context, IRubyObject other) { + return this.toArray(context).op_equal(context, other); + } + + /* + * call-seq: + * RepeatedField.each(&block) + * + * Invokes the block once for each element of the repeated field. RepeatedField + * also includes Enumerable; combined with this method, the repeated field thus + * acts like an ordinary Ruby sequence. + */ + @JRubyMethod + public IRubyObject each(ThreadContext context, Block block) { + this.storage.each(context, block); + return this; + } + + @JRubyMethod(name = {"to_ary", "to_a"}) + public IRubyObject toArray(ThreadContext context) { + return this.storage; + } + + /* + * call-seq: + * RepeatedField.dup => repeated_field + * + * Duplicates this repeated field with a shallow copy. References to all + * non-primitive element objects (e.g., submessages) are shared. + */ + @JRubyMethod + public IRubyObject dup(ThreadContext context) { + RubyRepeatedField dup = new RubyRepeatedField(context.runtime, metaClass, fieldType, typeClass); + dup.push(context, storage.toJavaArray()); + return dup; + } + + @JRubyMethod + public IRubyObject inspect() { + return storage.inspect(); + } + + // Java API + protected IRubyObject get(int index) { + return this.storage.eltInternal(index); + } + + protected RubyRepeatedField deepCopy(ThreadContext context) { + RubyRepeatedField copy = + new RubyRepeatedField(context.runtime, metaClass, fieldType, typeClass); + for (int i = 0; i < size(); i++) { + IRubyObject value = storage.eltInternal(i); + if (fieldType == FieldDescriptor.Type.MESSAGE) { + copy.storage.add(((RubyMessage) value).deepCopy(context)); + } else { + copy.storage.add(value); + } } - - private IRubyObject defaultValue(ThreadContext context) { - SentinelOuterClass.Sentinel sentinel = SentinelOuterClass.Sentinel.getDefaultInstance(); - Object value; - switch (fieldType) { - case INT32: - value = sentinel.getDefaultInt32(); - break; - case INT64: - value = sentinel.getDefaultInt64(); - break; - case UINT32: - value = sentinel.getDefaultUnit32(); - break; - case UINT64: - value = sentinel.getDefaultUint64(); - break; - case FLOAT: - value = sentinel.getDefaultFloat(); - break; - case DOUBLE: - value = sentinel.getDefaultDouble(); - break; - case BOOL: - value = sentinel.getDefaultBool(); - break; - case BYTES: - value = sentinel.getDefaultBytes(); - break; - case STRING: - value = sentinel.getDefaultString(); - break; - case ENUM: - IRubyObject defaultEnumLoc = context.runtime.newFixnum(0); - return RubyEnum.lookup(context, typeClass, defaultEnumLoc); - default: - return context.runtime.getNil(); - } - return Utils.wrapPrimaryValue(context, fieldType, value); + return copy; + } + + protected void setName(String name) { + this.name = name; + } + + protected int size() { + return this.storage.size(); + } + + private IRubyObject defaultValue(ThreadContext context) { + SentinelOuterClass.Sentinel sentinel = SentinelOuterClass.Sentinel.getDefaultInstance(); + Object value; + switch (fieldType) { + case INT32: + value = sentinel.getDefaultInt32(); + break; + case INT64: + value = sentinel.getDefaultInt64(); + break; + case UINT32: + value = sentinel.getDefaultUnit32(); + break; + case UINT64: + value = sentinel.getDefaultUint64(); + break; + case FLOAT: + value = sentinel.getDefaultFloat(); + break; + case DOUBLE: + value = sentinel.getDefaultDouble(); + break; + case BOOL: + value = sentinel.getDefaultBool(); + break; + case BYTES: + value = sentinel.getDefaultBytes(); + break; + case STRING: + value = sentinel.getDefaultString(); + break; + case ENUM: + IRubyObject defaultEnumLoc = context.runtime.newFixnum(0); + return RubyEnum.lookup(context, typeClass, defaultEnumLoc); + default: + return context.runtime.getNil(); } + return Utils.wrapPrimaryValue(context, fieldType, value); + } - private void checkArrayElementType(ThreadContext context, RubyArray arr) { - for (int i = 0; i < arr.getLength(); i++) { - Utils.checkType(context, fieldType, name, arr.eltInternal(i), (RubyModule) typeClass); - } + private void checkArrayElementType(ThreadContext context, RubyArray arr) { + for (int i = 0; i < arr.getLength(); i++) { + Utils.checkType(context, fieldType, name, arr.eltInternal(i), (RubyModule) typeClass); } + } - private int normalizeArrayIndex(IRubyObject index) { - int arrIndex = RubyNumeric.num2int(index); - int arrSize = this.storage.size(); - if (arrIndex < 0 && arrSize > 0) { - arrIndex = arrSize + arrIndex; - } - return arrIndex; + private int normalizeArrayIndex(IRubyObject index) { + int arrIndex = RubyNumeric.num2int(index); + int arrSize = this.storage.size(); + if (arrIndex < 0 && arrSize > 0) { + arrIndex = arrSize + arrIndex; } + return arrIndex; + } - private FieldDescriptor.Type fieldType; - private IRubyObject typeClass; - private RubyArray storage; - private String name; + private FieldDescriptor.Type fieldType; + private IRubyObject typeClass; + private RubyArray storage; + private String name; } diff --git a/ruby/src/main/java/com/google/protobuf/jruby/SentinelOuterClass.java b/ruby/src/main/java/com/google/protobuf/jruby/SentinelOuterClass.java index b3f23c5d3588..3c56cf86a834 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/SentinelOuterClass.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/SentinelOuterClass.java @@ -37,74 +37,53 @@ public final class SentinelOuterClass { private SentinelOuterClass() {} - public static void registerAllExtensions( - com.google.protobuf.ExtensionRegistry registry) { - } - public interface SentinelOrBuilder extends + + public static void registerAllExtensions(com.google.protobuf.ExtensionRegistry registry) {} + + public interface SentinelOrBuilder + extends // @@protoc_insertion_point(interface_extends:com.google.protobuf.jruby.Sentinel) com.google.protobuf.MessageOrBuilder { - /** - * optional int32 default_int32 = 1; - */ + /** optional int32 default_int32 = 1; */ int getDefaultInt32(); - /** - * optional int64 default_int64 = 2; - */ + /** optional int64 default_int64 = 2; */ long getDefaultInt64(); - /** - * optional uint32 default_unit32 = 3; - */ + /** optional uint32 default_unit32 = 3; */ int getDefaultUnit32(); - /** - * optional uint64 default_uint64 = 4; - */ + /** optional uint64 default_uint64 = 4; */ long getDefaultUint64(); - /** - * optional string default_string = 5; - */ + /** optional string default_string = 5; */ java.lang.String getDefaultString(); - /** - * optional string default_string = 5; - */ - com.google.protobuf.ByteString - getDefaultStringBytes(); - - /** - * optional bool default_bool = 6; - */ + /** optional string default_string = 5; */ + com.google.protobuf.ByteString getDefaultStringBytes(); + + /** optional bool default_bool = 6; */ boolean getDefaultBool(); - /** - * optional float default_float = 7; - */ + /** optional float default_float = 7; */ float getDefaultFloat(); - /** - * optional double default_double = 8; - */ + /** optional double default_double = 8; */ double getDefaultDouble(); - /** - * optional bytes default_bytes = 9; - */ + /** optional bytes default_bytes = 9; */ com.google.protobuf.ByteString getDefaultBytes(); } - /** - * Protobuf type {@code com.google.protobuf.jruby.Sentinel} - */ - public static final class Sentinel extends - com.google.protobuf.GeneratedMessage implements + /** Protobuf type {@code com.google.protobuf.jruby.Sentinel} */ + public static final class Sentinel extends com.google.protobuf.GeneratedMessage + implements // @@protoc_insertion_point(message_implements:com.google.protobuf.jruby.Sentinel) SentinelOrBuilder { // Use Sentinel.newBuilder() to construct. private Sentinel(com.google.protobuf.GeneratedMessage.Builder builder) { super(builder); } + private Sentinel() { defaultInt32_ = 0; defaultInt64_ = 0L; @@ -118,40 +97,42 @@ private Sentinel() { } @java.lang.Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { + public final com.google.protobuf.UnknownFieldSet getUnknownFields() { return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_descriptor; + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.protobuf.jruby.SentinelOuterClass + .internal_static_com_google_protobuf_jruby_Sentinel_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { - return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable + return com.google.protobuf.jruby.SentinelOuterClass + .internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable .ensureFieldAccessorsInitialized( - com.google.protobuf.jruby.SentinelOuterClass.Sentinel.class, com.google.protobuf.jruby.SentinelOuterClass.Sentinel.Builder.class); + com.google.protobuf.jruby.SentinelOuterClass.Sentinel.class, + com.google.protobuf.jruby.SentinelOuterClass.Sentinel.Builder.class); } public static final com.google.protobuf.Parser PARSER = new com.google.protobuf.AbstractParser() { - public Sentinel parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - Builder builder = newBuilder(); - try { - builder.mergeFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(builder.buildPartial()); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e.getMessage()).setUnfinishedMessage(builder.buildPartial()); - } - return builder.buildPartial(); - } - }; + public Sentinel parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e.getMessage()) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; @java.lang.Override public com.google.protobuf.Parser getParserForType() { @@ -160,52 +141,41 @@ public com.google.protobuf.Parser getParserForType() { public static final int DEFAULT_INT32_FIELD_NUMBER = 1; private int defaultInt32_; - /** - * optional int32 default_int32 = 1; - */ + /** optional int32 default_int32 = 1; */ public int getDefaultInt32() { return defaultInt32_; } public static final int DEFAULT_INT64_FIELD_NUMBER = 2; private long defaultInt64_; - /** - * optional int64 default_int64 = 2; - */ + /** optional int64 default_int64 = 2; */ public long getDefaultInt64() { return defaultInt64_; } public static final int DEFAULT_UNIT32_FIELD_NUMBER = 3; private int defaultUnit32_; - /** - * optional uint32 default_unit32 = 3; - */ + /** optional uint32 default_unit32 = 3; */ public int getDefaultUnit32() { return defaultUnit32_; } public static final int DEFAULT_UINT64_FIELD_NUMBER = 4; private long defaultUint64_; - /** - * optional uint64 default_uint64 = 4; - */ + /** optional uint64 default_uint64 = 4; */ public long getDefaultUint64() { return defaultUint64_; } public static final int DEFAULT_STRING_FIELD_NUMBER = 5; private java.lang.Object defaultString_; - /** - * optional string default_string = 5; - */ + /** optional string default_string = 5; */ public java.lang.String getDefaultString() { java.lang.Object ref = defaultString_; if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { defaultString_ = s; @@ -213,16 +183,12 @@ public java.lang.String getDefaultString() { return s; } } - /** - * optional string default_string = 5; - */ - public com.google.protobuf.ByteString - getDefaultStringBytes() { + /** optional string default_string = 5; */ + public com.google.protobuf.ByteString getDefaultStringBytes() { java.lang.Object ref = defaultString_; if (ref instanceof java.lang.String) { com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); + com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref); defaultString_ = b; return b; } else { @@ -232,36 +198,28 @@ public java.lang.String getDefaultString() { public static final int DEFAULT_BOOL_FIELD_NUMBER = 6; private boolean defaultBool_; - /** - * optional bool default_bool = 6; - */ + /** optional bool default_bool = 6; */ public boolean getDefaultBool() { return defaultBool_; } public static final int DEFAULT_FLOAT_FIELD_NUMBER = 7; private float defaultFloat_; - /** - * optional float default_float = 7; - */ + /** optional float default_float = 7; */ public float getDefaultFloat() { return defaultFloat_; } public static final int DEFAULT_DOUBLE_FIELD_NUMBER = 8; private double defaultDouble_; - /** - * optional double default_double = 8; - */ + /** optional double default_double = 8; */ public double getDefaultDouble() { return defaultDouble_; } public static final int DEFAULT_BYTES_FIELD_NUMBER = 9; private com.google.protobuf.ByteString defaultBytes_; - /** - * optional bytes default_bytes = 9; - */ + /** optional bytes default_bytes = 9; */ public com.google.protobuf.ByteString getDefaultBytes() { return defaultBytes_; } @@ -271,47 +229,52 @@ public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom( throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } + public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } + public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } + public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) + byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } - public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom(java.io.InputStream input) - throws java.io.IOException { + + public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom( + java.io.InputStream input) throws java.io.IOException { return PARSER.parseFrom(input); } + public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return PARSER.parseFrom(input, extensionRegistry); } - public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { + + public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseDelimitedFrom( + java.io.InputStream input) throws java.io.IOException { return PARSER.parseDelimitedFrom(input); } + public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return PARSER.parseDelimitedFrom(input, extensionRegistry); } + public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { + com.google.protobuf.CodedInputStream input) throws java.io.IOException { return PARSER.parseFrom(input); } + public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) @@ -319,36 +282,45 @@ public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel parseFrom( return PARSER.parseFrom(input, extensionRegistry); } - public static Builder newBuilder() { return new Builder(); } - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(com.google.protobuf.jruby.SentinelOuterClass.Sentinel prototype) { + public static Builder newBuilder() { + return new Builder(); + } + + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder( + com.google.protobuf.jruby.SentinelOuterClass.Sentinel prototype) { return newBuilder().mergeFrom(prototype); } - public Builder toBuilder() { return newBuilder(this); } + + public Builder toBuilder() { + return newBuilder(this); + } @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { + protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) { Builder builder = new Builder(parent); return builder; } - /** - * Protobuf type {@code com.google.protobuf.jruby.Sentinel} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder implements + /** Protobuf type {@code com.google.protobuf.jruby.Sentinel} */ + public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder + implements // @@protoc_insertion_point(builder_implements:com.google.protobuf.jruby.Sentinel) com.google.protobuf.jruby.SentinelOuterClass.SentinelOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_descriptor; + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.protobuf.jruby.SentinelOuterClass + .internal_static_com_google_protobuf_jruby_Sentinel_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { - return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable + return com.google.protobuf.jruby.SentinelOuterClass + .internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable .ensureFieldAccessorsInitialized( - com.google.protobuf.jruby.SentinelOuterClass.Sentinel.class, com.google.protobuf.jruby.SentinelOuterClass.Sentinel.Builder.class); + com.google.protobuf.jruby.SentinelOuterClass.Sentinel.class, + com.google.protobuf.jruby.SentinelOuterClass.Sentinel.Builder.class); } // Construct using com.google.protobuf.jruby.SentinelOuterClass.Sentinel.newBuilder() @@ -356,15 +328,15 @@ private Builder() { maybeForceBuilderInitialization(); } - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { super(parent); maybeForceBuilderInitialization(); } + private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { - } + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {} } + public Builder clear() { super.clear(); defaultInt32_ = 0; @@ -388,9 +360,9 @@ public Builder clear() { return this; } - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return com.google.protobuf.jruby.SentinelOuterClass.internal_static_com_google_protobuf_jruby_Sentinel_descriptor; + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return com.google.protobuf.jruby.SentinelOuterClass + .internal_static_com_google_protobuf_jruby_Sentinel_descriptor; } public com.google.protobuf.jruby.SentinelOuterClass.Sentinel getDefaultInstanceForType() { @@ -406,7 +378,8 @@ public com.google.protobuf.jruby.SentinelOuterClass.Sentinel build() { } public com.google.protobuf.jruby.SentinelOuterClass.Sentinel buildPartial() { - com.google.protobuf.jruby.SentinelOuterClass.Sentinel result = new com.google.protobuf.jruby.SentinelOuterClass.Sentinel(this); + com.google.protobuf.jruby.SentinelOuterClass.Sentinel result = + new com.google.protobuf.jruby.SentinelOuterClass.Sentinel(this); result.defaultInt32_ = defaultInt32_; result.defaultInt64_ = defaultInt64_; result.defaultUnit32_ = defaultUnit32_; @@ -420,26 +393,19 @@ public com.google.protobuf.jruby.SentinelOuterClass.Sentinel buildPartial() { return result; } - - private int defaultInt32_ ; - /** - * optional int32 default_int32 = 1; - */ + private int defaultInt32_; + /** optional int32 default_int32 = 1; */ public int getDefaultInt32() { return defaultInt32_; } - /** - * optional int32 default_int32 = 1; - */ + /** optional int32 default_int32 = 1; */ public Builder setDefaultInt32(int value) { defaultInt32_ = value; onChanged(); return this; } - /** - * optional int32 default_int32 = 1; - */ + /** optional int32 default_int32 = 1; */ public Builder clearDefaultInt32() { defaultInt32_ = 0; @@ -447,25 +413,19 @@ public Builder clearDefaultInt32() { return this; } - private long defaultInt64_ ; - /** - * optional int64 default_int64 = 2; - */ + private long defaultInt64_; + /** optional int64 default_int64 = 2; */ public long getDefaultInt64() { return defaultInt64_; } - /** - * optional int64 default_int64 = 2; - */ + /** optional int64 default_int64 = 2; */ public Builder setDefaultInt64(long value) { defaultInt64_ = value; onChanged(); return this; } - /** - * optional int64 default_int64 = 2; - */ + /** optional int64 default_int64 = 2; */ public Builder clearDefaultInt64() { defaultInt64_ = 0L; @@ -473,25 +433,19 @@ public Builder clearDefaultInt64() { return this; } - private int defaultUnit32_ ; - /** - * optional uint32 default_unit32 = 3; - */ + private int defaultUnit32_; + /** optional uint32 default_unit32 = 3; */ public int getDefaultUnit32() { return defaultUnit32_; } - /** - * optional uint32 default_unit32 = 3; - */ + /** optional uint32 default_unit32 = 3; */ public Builder setDefaultUnit32(int value) { defaultUnit32_ = value; onChanged(); return this; } - /** - * optional uint32 default_unit32 = 3; - */ + /** optional uint32 default_unit32 = 3; */ public Builder clearDefaultUnit32() { defaultUnit32_ = 0; @@ -499,25 +453,19 @@ public Builder clearDefaultUnit32() { return this; } - private long defaultUint64_ ; - /** - * optional uint64 default_uint64 = 4; - */ + private long defaultUint64_; + /** optional uint64 default_uint64 = 4; */ public long getDefaultUint64() { return defaultUint64_; } - /** - * optional uint64 default_uint64 = 4; - */ + /** optional uint64 default_uint64 = 4; */ public Builder setDefaultUint64(long value) { defaultUint64_ = value; onChanged(); return this; } - /** - * optional uint64 default_uint64 = 4; - */ + /** optional uint64 default_uint64 = 4; */ public Builder clearDefaultUint64() { defaultUint64_ = 0L; @@ -526,14 +474,11 @@ public Builder clearDefaultUint64() { } private java.lang.Object defaultString_ = ""; - /** - * optional string default_string = 5; - */ + /** optional string default_string = 5; */ public java.lang.String getDefaultString() { java.lang.Object ref = defaultString_; if (!(ref instanceof java.lang.String)) { - com.google.protobuf.ByteString bs = - (com.google.protobuf.ByteString) ref; + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { defaultString_ = s; @@ -543,77 +488,59 @@ public java.lang.String getDefaultString() { return (java.lang.String) ref; } } - /** - * optional string default_string = 5; - */ - public com.google.protobuf.ByteString - getDefaultStringBytes() { + /** optional string default_string = 5; */ + public com.google.protobuf.ByteString getDefaultStringBytes() { java.lang.Object ref = defaultString_; if (ref instanceof String) { com.google.protobuf.ByteString b = - com.google.protobuf.ByteString.copyFromUtf8( - (java.lang.String) ref); + com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref); defaultString_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } - /** - * optional string default_string = 5; - */ - public Builder setDefaultString( - java.lang.String value) { + /** optional string default_string = 5; */ + public Builder setDefaultString(java.lang.String value) { if (value == null) { - throw new NullPointerException(); - } + throw new NullPointerException(); + } defaultString_ = value; onChanged(); return this; } - /** - * optional string default_string = 5; - */ + /** optional string default_string = 5; */ public Builder clearDefaultString() { defaultString_ = getDefaultInstance().getDefaultString(); onChanged(); return this; } - /** - * optional string default_string = 5; - */ - public Builder setDefaultStringBytes( - com.google.protobuf.ByteString value) { + /** optional string default_string = 5; */ + public Builder setDefaultStringBytes(com.google.protobuf.ByteString value) { if (value == null) { - throw new NullPointerException(); - } + throw new NullPointerException(); + } defaultString_ = value; onChanged(); return this; } - private boolean defaultBool_ ; - /** - * optional bool default_bool = 6; - */ + private boolean defaultBool_; + /** optional bool default_bool = 6; */ public boolean getDefaultBool() { return defaultBool_; } - /** - * optional bool default_bool = 6; - */ + /** optional bool default_bool = 6; */ public Builder setDefaultBool(boolean value) { defaultBool_ = value; onChanged(); return this; } - /** - * optional bool default_bool = 6; - */ + /** optional bool default_bool = 6; */ public Builder clearDefaultBool() { defaultBool_ = false; @@ -621,25 +548,19 @@ public Builder clearDefaultBool() { return this; } - private float defaultFloat_ ; - /** - * optional float default_float = 7; - */ + private float defaultFloat_; + /** optional float default_float = 7; */ public float getDefaultFloat() { return defaultFloat_; } - /** - * optional float default_float = 7; - */ + /** optional float default_float = 7; */ public Builder setDefaultFloat(float value) { defaultFloat_ = value; onChanged(); return this; } - /** - * optional float default_float = 7; - */ + /** optional float default_float = 7; */ public Builder clearDefaultFloat() { defaultFloat_ = 0F; @@ -647,25 +568,19 @@ public Builder clearDefaultFloat() { return this; } - private double defaultDouble_ ; - /** - * optional double default_double = 8; - */ + private double defaultDouble_; + /** optional double default_double = 8; */ public double getDefaultDouble() { return defaultDouble_; } - /** - * optional double default_double = 8; - */ + /** optional double default_double = 8; */ public Builder setDefaultDouble(double value) { defaultDouble_ = value; onChanged(); return this; } - /** - * optional double default_double = 8; - */ + /** optional double default_double = 8; */ public Builder clearDefaultDouble() { defaultDouble_ = 0D; @@ -674,33 +589,28 @@ public Builder clearDefaultDouble() { } private com.google.protobuf.ByteString defaultBytes_ = com.google.protobuf.ByteString.EMPTY; - /** - * optional bytes default_bytes = 9; - */ + /** optional bytes default_bytes = 9; */ public com.google.protobuf.ByteString getDefaultBytes() { return defaultBytes_; } - /** - * optional bytes default_bytes = 9; - */ + /** optional bytes default_bytes = 9; */ public Builder setDefaultBytes(com.google.protobuf.ByteString value) { if (value == null) { - throw new NullPointerException(); - } + throw new NullPointerException(); + } defaultBytes_ = value; onChanged(); return this; } - /** - * optional bytes default_bytes = 9; - */ + /** optional bytes default_bytes = 9; */ public Builder clearDefaultBytes() { defaultBytes_ = getDefaultInstance().getDefaultBytes(); onChanged(); return this; } + public final Builder setUnknownFields( final com.google.protobuf.UnknownFieldSet unknownFields) { return this; @@ -711,12 +621,13 @@ public final Builder mergeUnknownFields( return this; } - // @@protoc_insertion_point(builder_scope:com.google.protobuf.jruby.Sentinel) } // @@protoc_insertion_point(class_scope:com.google.protobuf.jruby.Sentinel) - private static final com.google.protobuf.jruby.SentinelOuterClass.Sentinel defaultInstance;static { + private static final com.google.protobuf.jruby.SentinelOuterClass.Sentinel defaultInstance; + + static { defaultInstance = new com.google.protobuf.jruby.SentinelOuterClass.Sentinel(); } @@ -727,49 +638,55 @@ public static com.google.protobuf.jruby.SentinelOuterClass.Sentinel getDefaultIn public com.google.protobuf.jruby.SentinelOuterClass.Sentinel getDefaultInstanceForType() { return defaultInstance; } - } private static final com.google.protobuf.Descriptors.Descriptor - internal_static_com_google_protobuf_jruby_Sentinel_descriptor; - private static - com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_com_google_protobuf_jruby_Sentinel_descriptor; + private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable; - public static com.google.protobuf.Descriptors.FileDescriptor - getDescriptor() { + public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { return descriptor; } - private static com.google.protobuf.Descriptors.FileDescriptor - descriptor; + + private static com.google.protobuf.Descriptors.FileDescriptor descriptor; + static { java.lang.String[] descriptorData = { - "\n\016sentinel.proto\022\031com.google.protobuf.jr" + - "uby\"\334\001\n\010Sentinel\022\025\n\rdefault_int32\030\001 \001(\005\022" + - "\025\n\rdefault_int64\030\002 \001(\003\022\026\n\016default_unit32" + - "\030\003 \001(\r\022\026\n\016default_uint64\030\004 \001(\004\022\026\n\016defaul" + - "t_string\030\005 \001(\t\022\024\n\014default_bool\030\006 \001(\010\022\025\n\r" + - "default_float\030\007 \001(\002\022\026\n\016default_double\030\010 " + - "\001(\001\022\025\n\rdefault_bytes\030\t \001(\014B\002H\002b\006proto3" + "\n\016sentinel.proto\022\031com.google.protobuf.jr" + + "uby\"\334\001\n\010Sentinel\022\025\n\rdefault_int32\030\001 \001(\005\022" + + "\025\n\rdefault_int64\030\002 \001(\003\022\026\n\016default_unit32" + + "\030\003 \001(\r\022\026\n\016default_uint64\030\004 \001(\004\022\026\n\016defaul" + + "t_string\030\005 \001(\t\022\024\n\014default_bool\030\006 \001(\010\022\025\n\r" + + "default_float\030\007 \001(\002\022\026\n\016default_double\030\010 " + + "\001(\001\022\025\n\rdefault_bytes\030\t \001(\014B\002H\002b\006proto3" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = - new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { + new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { public com.google.protobuf.ExtensionRegistry assignDescriptors( com.google.protobuf.Descriptors.FileDescriptor root) { descriptor = root; return null; } }; - com.google.protobuf.Descriptors.FileDescriptor - .internalBuildGeneratedFileFrom(descriptorData, - new com.google.protobuf.Descriptors.FileDescriptor[] { - }, assigner); + com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( + descriptorData, new com.google.protobuf.Descriptors.FileDescriptor[] {}, assigner); internal_static_com_google_protobuf_jruby_Sentinel_descriptor = - getDescriptor().getMessageTypes().get(0); - internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_com_google_protobuf_jruby_Sentinel_descriptor, - new java.lang.String[] { "DefaultInt32", "DefaultInt64", "DefaultUnit32", "DefaultUint64", "DefaultString", "DefaultBool", "DefaultFloat", "DefaultDouble", "DefaultBytes", }); + getDescriptor().getMessageTypes().get(0); + internal_static_com_google_protobuf_jruby_Sentinel_fieldAccessorTable = + new com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_com_google_protobuf_jruby_Sentinel_descriptor, + new java.lang.String[] { + "DefaultInt32", + "DefaultInt64", + "DefaultUnit32", + "DefaultUint64", + "DefaultString", + "DefaultBool", + "DefaultFloat", + "DefaultDouble", + "DefaultBytes", + }); } // @@protoc_insertion_point(outer_class_scope) diff --git a/ruby/src/main/java/com/google/protobuf/jruby/Utils.java b/ruby/src/main/java/com/google/protobuf/jruby/Utils.java index cd2758962eb6..65de683b0226 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/Utils.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/Utils.java @@ -35,6 +35,7 @@ import com.google.protobuf.ByteString; import com.google.protobuf.DescriptorProtos.FieldDescriptorProto; import com.google.protobuf.Descriptors.FieldDescriptor; +import java.math.BigInteger; import org.jcodings.specific.ASCIIEncoding; import org.jruby.*; import org.jruby.exceptions.RaiseException; @@ -44,302 +45,363 @@ import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; -import java.math.BigInteger; - public class Utils { - public static FieldDescriptor.Type rubyToFieldType(IRubyObject typeClass) { - return FieldDescriptor.Type.valueOf(typeClass.asJavaString().toUpperCase()); - } - - public static IRubyObject fieldTypeToRuby(ThreadContext context, FieldDescriptor.Type type) { - return fieldTypeToRuby(context, type.name()); - } - - public static IRubyObject fieldTypeToRuby(ThreadContext context, FieldDescriptorProto.Type type) { - return fieldTypeToRuby(context, type.name()); - } - - private static IRubyObject fieldTypeToRuby(ThreadContext context, String typeName) { - - return context.runtime.newSymbol(typeName.replace("TYPE_", "").toLowerCase()); - } + public static FieldDescriptor.Type rubyToFieldType(IRubyObject typeClass) { + return FieldDescriptor.Type.valueOf(typeClass.asJavaString().toUpperCase()); + } + + public static IRubyObject fieldTypeToRuby(ThreadContext context, FieldDescriptor.Type type) { + return fieldTypeToRuby(context, type.name()); + } + + public static IRubyObject fieldTypeToRuby(ThreadContext context, FieldDescriptorProto.Type type) { + return fieldTypeToRuby(context, type.name()); + } + + private static IRubyObject fieldTypeToRuby(ThreadContext context, String typeName) { + + return context.runtime.newSymbol(typeName.replace("TYPE_", "").toLowerCase()); + } + + public static IRubyObject checkType( + ThreadContext context, + FieldDescriptor.Type fieldType, + String fieldName, + IRubyObject value, + RubyModule typeClass) { + Ruby runtime = context.runtime; + + switch (fieldType) { + case SFIXED32: + case SFIXED64: + case FIXED64: + case SINT64: + case SINT32: + case FIXED32: + case INT32: + case INT64: + case UINT32: + case UINT64: + if (!isRubyNum(value)) + throw createExpectedTypeError(context, "number", "integral", fieldName, value); - public static IRubyObject checkType(ThreadContext context, FieldDescriptor.Type fieldType, - String fieldName, IRubyObject value, RubyModule typeClass) { - Ruby runtime = context.runtime; - - switch(fieldType) { - case SFIXED32: - case SFIXED64: - case FIXED64: - case SINT64: - case SINT32: - case FIXED32: - case INT32: - case INT64: - case UINT32: - case UINT64: - if (!isRubyNum(value)) - throw createExpectedTypeError(context, "number", "integral", fieldName, value); - - if (value instanceof RubyFloat) { - double doubleVal = RubyNumeric.num2dbl(value); - if (Math.floor(doubleVal) != doubleVal) { - throw runtime.newRangeError("Non-integral floating point value assigned to integer field '" + fieldName + "' (given " + value.getMetaClass() + ")."); - } - } - if (fieldType == FieldDescriptor.Type.UINT32 || fieldType == FieldDescriptor.Type.UINT64 || - fieldType == FieldDescriptor.Type.FIXED32 || fieldType == FieldDescriptor.Type.FIXED64) { - if (((RubyNumeric) value).isNegative()) { - throw runtime.newRangeError("Assigning negative value to unsigned integer field '" + fieldName + "' (given " + value.getMetaClass() + ")."); - } - } - - switch(fieldType) { - case INT32: - RubyNumeric.num2int(value); - break; - case UINT32: - case FIXED32: - num2uint(value); - break; - case UINT64: - case FIXED64: - num2ulong(context.runtime, value); - break; - default: - RubyNumeric.num2long(value); - break; - } - break; - case FLOAT: - if (!isRubyNum(value)) - throw createExpectedTypeError(context, "number", "float", fieldName, value); - break; - case DOUBLE: - if (!isRubyNum(value)) - throw createExpectedTypeError(context, "number", "double", fieldName, value); - break; - case BOOL: - if (!(value instanceof RubyBoolean)) - throw createInvalidTypeError(context, "boolean", fieldName, value); - break; - case BYTES: - value = validateAndEncodeString(context, "bytes", fieldName, value, "Encoding::ASCII_8BIT"); - break; - case STRING: - value = validateAndEncodeString(context, "string", fieldName, symToString(value), "Encoding::UTF_8"); - break; - case MESSAGE: - if (value.getMetaClass() != typeClass) { - // See if we can convert the value before flagging it as invalid - String className = typeClass.getName(); - - if (className.equals("Google::Protobuf::Timestamp") && value instanceof RubyTime) { - RubyTime rt = (RubyTime) value; - RubyHash timestampArgs = - Helpers.constructHash(runtime, - runtime.newString("nanos"), rt.nsec(), false, - runtime.newString("seconds"), rt.to_i(), false); - return ((RubyClass) typeClass).newInstance(context, timestampArgs, Block.NULL_BLOCK); - - } else if (className.equals("Google::Protobuf::Duration") && value instanceof RubyNumeric) { - IRubyObject seconds; - if (value instanceof RubyFloat) { - seconds = ((RubyFloat) value).truncate(context); - } else if (value instanceof RubyRational) { - seconds = ((RubyRational) value).to_i(context); - } else if (value instanceof RubyBigDecimal) { - seconds = ((RubyBigDecimal) value).to_int(context); - } else { - seconds = ((RubyInteger) value).to_i(); - } - - IRubyObject nanos = ((RubyNumeric) value).remainder(context, RubyFixnum.one(runtime)); - if (nanos instanceof RubyFloat) { - nanos = ((RubyFloat) nanos).op_mul(context, 1000000000); - } else if (nanos instanceof RubyRational) { - nanos = ((RubyRational) nanos).op_mul(context, runtime.newFixnum(1000000000)); - } else if (nanos instanceof RubyBigDecimal) { - nanos = ((RubyBigDecimal) nanos).op_mul(context, runtime.newFixnum(1000000000)); - } else { - nanos = ((RubyInteger) nanos).op_mul(context, 1000000000); - } - - RubyHash durationArgs = - Helpers.constructHash(runtime, - runtime.newString("nanos"), ((RubyNumeric) nanos).round(context), false, - runtime.newString("seconds"), seconds, false); - return ((RubyClass) typeClass).newInstance(context, durationArgs, Block.NULL_BLOCK); - } - - // Not able to convert so flag as invalid - throw createTypeError(context, "Invalid type " + value.getMetaClass() + " to assign to submessage field '" + fieldName + "'."); - } - - break; - case ENUM: - boolean isValid = ((RubyEnumDescriptor) typeClass.getInstanceVariable(DESCRIPTOR_INSTANCE_VAR)).isValidValue(context, value); - if (!isValid) { - throw runtime.newRangeError("Unknown symbol value for enum field '" + fieldName + "'."); - } - break; - default: - break; + if (value instanceof RubyFloat) { + double doubleVal = RubyNumeric.num2dbl(value); + if (Math.floor(doubleVal) != doubleVal) { + throw runtime.newRangeError( + "Non-integral floating point value assigned to integer field '" + + fieldName + + "' (given " + + value.getMetaClass() + + ")."); + } + } + if (fieldType == FieldDescriptor.Type.UINT32 + || fieldType == FieldDescriptor.Type.UINT64 + || fieldType == FieldDescriptor.Type.FIXED32 + || fieldType == FieldDescriptor.Type.FIXED64) { + if (((RubyNumeric) value).isNegative()) { + throw runtime.newRangeError( + "Assigning negative value to unsigned integer field '" + + fieldName + + "' (given " + + value.getMetaClass() + + ")."); + } } - return value; - } - - public static IRubyObject wrapPrimaryValue(ThreadContext context, FieldDescriptor.Type fieldType, Object value) { - return wrapPrimaryValue(context, fieldType, value, false); - } - public static IRubyObject wrapPrimaryValue(ThreadContext context, FieldDescriptor.Type fieldType, Object value, boolean encodeBytes) { - Ruby runtime = context.runtime; switch (fieldType) { - case INT32: - case SFIXED32: - case SINT32: - return runtime.newFixnum((Integer) value); - case SFIXED64: - case SINT64: - case INT64: - return runtime.newFixnum((Long) value); - case FIXED32: - case UINT32: - return runtime.newFixnum(((Integer) value) & (-1l >>> 32)); - case FIXED64: - case UINT64: - long ret = (Long) value; - return ret >= 0 ? runtime.newFixnum(ret) : - RubyBignum.newBignum(runtime, UINT64_COMPLEMENTARY.add(new BigInteger(ret + ""))); - case FLOAT: - return runtime.newFloat((Float) value); - case DOUBLE: - return runtime.newFloat((Double) value); - case BOOL: - return (Boolean) value ? runtime.getTrue() : runtime.getFalse(); - case BYTES: { - IRubyObject wrapped = encodeBytes ? - RubyString.newString(runtime, ((ByteString) value).toStringUtf8(), ASCIIEncoding.INSTANCE) : - RubyString.newString(runtime, ((ByteString) value).toByteArray()); - wrapped.setFrozen(true); - return wrapped; - } - case STRING: { - IRubyObject wrapped = runtime.newString(value.toString()); - wrapped.setFrozen(true); - return wrapped; - } - default: - return runtime.getNil(); + case INT32: + RubyNumeric.num2int(value); + break; + case UINT32: + case FIXED32: + num2uint(value); + break; + case UINT64: + case FIXED64: + num2ulong(context.runtime, value); + break; + default: + RubyNumeric.num2long(value); + break; } - } + break; + case FLOAT: + if (!isRubyNum(value)) + throw createExpectedTypeError(context, "number", "float", fieldName, value); + break; + case DOUBLE: + if (!isRubyNum(value)) + throw createExpectedTypeError(context, "number", "double", fieldName, value); + break; + case BOOL: + if (!(value instanceof RubyBoolean)) + throw createInvalidTypeError(context, "boolean", fieldName, value); + break; + case BYTES: + value = validateAndEncodeString(context, "bytes", fieldName, value, "Encoding::ASCII_8BIT"); + break; + case STRING: + value = + validateAndEncodeString( + context, "string", fieldName, symToString(value), "Encoding::UTF_8"); + break; + case MESSAGE: + if (value.getMetaClass() != typeClass) { + // See if we can convert the value before flagging it as invalid + String className = typeClass.getName(); + + if (className.equals("Google::Protobuf::Timestamp") && value instanceof RubyTime) { + RubyTime rt = (RubyTime) value; + RubyHash timestampArgs = + Helpers.constructHash( + runtime, + runtime.newString("nanos"), + rt.nsec(), + false, + runtime.newString("seconds"), + rt.to_i(), + false); + return ((RubyClass) typeClass).newInstance(context, timestampArgs, Block.NULL_BLOCK); + + } else if (className.equals("Google::Protobuf::Duration") + && value instanceof RubyNumeric) { + IRubyObject seconds; + if (value instanceof RubyFloat) { + seconds = ((RubyFloat) value).truncate(context); + } else if (value instanceof RubyRational) { + seconds = ((RubyRational) value).to_i(context); + } else if (value instanceof RubyBigDecimal) { + seconds = ((RubyBigDecimal) value).to_int(context); + } else { + seconds = ((RubyInteger) value).to_i(); + } - public static int num2uint(IRubyObject value) { - long longVal = RubyNumeric.num2long(value); - if (longVal > UINT_MAX) - throw value.getRuntime().newRangeError("Integer " + longVal + " too big to convert to 'unsigned int'"); - long num = longVal; - if (num > Integer.MAX_VALUE || num < Integer.MIN_VALUE) - // encode to UINT32 - num = (-longVal ^ (-1l >>> 32) ) + 1; - RubyNumeric.checkInt(value, num); - return (int) num; - } + IRubyObject nanos = ((RubyNumeric) value).remainder(context, RubyFixnum.one(runtime)); + if (nanos instanceof RubyFloat) { + nanos = ((RubyFloat) nanos).op_mul(context, 1000000000); + } else if (nanos instanceof RubyRational) { + nanos = ((RubyRational) nanos).op_mul(context, runtime.newFixnum(1000000000)); + } else if (nanos instanceof RubyBigDecimal) { + nanos = ((RubyBigDecimal) nanos).op_mul(context, runtime.newFixnum(1000000000)); + } else { + nanos = ((RubyInteger) nanos).op_mul(context, 1000000000); + } - public static long num2ulong(Ruby runtime, IRubyObject value) { - if (value instanceof RubyFloat) { - RubyBignum bignum = RubyBignum.newBignum(runtime, ((RubyFloat) value).getDoubleValue()); - return RubyBignum.big2ulong(bignum); - } else if (value instanceof RubyBignum) { - return RubyBignum.big2ulong((RubyBignum) value); - } else { - return RubyNumeric.num2long(value); + RubyHash durationArgs = + Helpers.constructHash( + runtime, + runtime.newString("nanos"), + ((RubyNumeric) nanos).round(context), + false, + runtime.newString("seconds"), + seconds, + false); + return ((RubyClass) typeClass).newInstance(context, durationArgs, Block.NULL_BLOCK); + } + + // Not able to convert so flag as invalid + throw createTypeError( + context, + "Invalid type " + + value.getMetaClass() + + " to assign to submessage field '" + + fieldName + + "'."); } - } - /* - * Helper to make it easier to support symbols being passed instead of strings - */ - public static IRubyObject symToString(IRubyObject sym) { - if (sym instanceof RubySymbol) { - return ((RubySymbol) sym).id2name(); + break; + case ENUM: + boolean isValid = + ((RubyEnumDescriptor) typeClass.getInstanceVariable(DESCRIPTOR_INSTANCE_VAR)) + .isValidValue(context, value); + if (!isValid) { + throw runtime.newRangeError("Unknown symbol value for enum field '" + fieldName + "'."); } - return sym; + break; + default: + break; } - - public static void checkNameAvailability(ThreadContext context, String name) { - if (context.runtime.getObject().getConstantAt(name) != null) - throw context.runtime.newNameError(name + " is already defined", name); + return value; + } + + public static IRubyObject wrapPrimaryValue( + ThreadContext context, FieldDescriptor.Type fieldType, Object value) { + return wrapPrimaryValue(context, fieldType, value, false); + } + + public static IRubyObject wrapPrimaryValue( + ThreadContext context, FieldDescriptor.Type fieldType, Object value, boolean encodeBytes) { + Ruby runtime = context.runtime; + switch (fieldType) { + case INT32: + case SFIXED32: + case SINT32: + return runtime.newFixnum((Integer) value); + case SFIXED64: + case SINT64: + case INT64: + return runtime.newFixnum((Long) value); + case FIXED32: + case UINT32: + return runtime.newFixnum(((Integer) value) & (-1l >>> 32)); + case FIXED64: + case UINT64: + long ret = (Long) value; + return ret >= 0 + ? runtime.newFixnum(ret) + : RubyBignum.newBignum(runtime, UINT64_COMPLEMENTARY.add(new BigInteger(ret + ""))); + case FLOAT: + return runtime.newFloat((Float) value); + case DOUBLE: + return runtime.newFloat((Double) value); + case BOOL: + return (Boolean) value ? runtime.getTrue() : runtime.getFalse(); + case BYTES: + { + IRubyObject wrapped = + encodeBytes + ? RubyString.newString( + runtime, ((ByteString) value).toStringUtf8(), ASCIIEncoding.INSTANCE) + : RubyString.newString(runtime, ((ByteString) value).toByteArray()); + wrapped.setFrozen(true); + return wrapped; + } + case STRING: + { + IRubyObject wrapped = runtime.newString(value.toString()); + wrapped.setFrozen(true); + return wrapped; + } + default: + return runtime.getNil(); } - - public static boolean isMapEntry(FieldDescriptor fieldDescriptor) { - return fieldDescriptor.getType() == FieldDescriptor.Type.MESSAGE && - fieldDescriptor.isRepeated() && - fieldDescriptor.getMessageType().getOptions().getMapEntry(); + } + + public static int num2uint(IRubyObject value) { + long longVal = RubyNumeric.num2long(value); + if (longVal > UINT_MAX) + throw value + .getRuntime() + .newRangeError("Integer " + longVal + " too big to convert to 'unsigned int'"); + long num = longVal; + if (num > Integer.MAX_VALUE || num < Integer.MIN_VALUE) + // encode to UINT32 + num = (-longVal ^ (-1l >>> 32)) + 1; + RubyNumeric.checkInt(value, num); + return (int) num; + } + + public static long num2ulong(Ruby runtime, IRubyObject value) { + if (value instanceof RubyFloat) { + RubyBignum bignum = RubyBignum.newBignum(runtime, ((RubyFloat) value).getDoubleValue()); + return RubyBignum.big2ulong(bignum); + } else if (value instanceof RubyBignum) { + return RubyBignum.big2ulong((RubyBignum) value); + } else { + return RubyNumeric.num2long(value); } - - public static RaiseException createTypeError(ThreadContext context, String message) { - if (cTypeError == null) { - cTypeError = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::TypeError"); - } - return RaiseException.from(context.runtime, cTypeError, message); + } + + /* + * Helper to make it easier to support symbols being passed instead of strings + */ + public static IRubyObject symToString(IRubyObject sym) { + if (sym instanceof RubySymbol) { + return ((RubySymbol) sym).id2name(); } - - public static RaiseException createExpectedTypeError(ThreadContext context, String type, String fieldType, String fieldName, IRubyObject value) { - return createTypeError(context, String.format(EXPECTED_TYPE_ERROR_FORMAT, type, fieldType, fieldName, value.getMetaClass())); + return sym; + } + + public static void checkNameAvailability(ThreadContext context, String name) { + if (context.runtime.getObject().getConstantAt(name) != null) + throw context.runtime.newNameError(name + " is already defined", name); + } + + public static boolean isMapEntry(FieldDescriptor fieldDescriptor) { + return fieldDescriptor.getType() == FieldDescriptor.Type.MESSAGE + && fieldDescriptor.isRepeated() + && fieldDescriptor.getMessageType().getOptions().getMapEntry(); + } + + public static RaiseException createTypeError(ThreadContext context, String message) { + if (cTypeError == null) { + cTypeError = (RubyClass) context.runtime.getClassFromPath("Google::Protobuf::TypeError"); } - - public static RaiseException createInvalidTypeError(ThreadContext context, String fieldType, String fieldName, IRubyObject value) { - return createTypeError(context, String.format(INVALID_TYPE_ERROR_FORMAT, fieldType, fieldName, value.getMetaClass())); + return RaiseException.from(context.runtime, cTypeError, message); + } + + public static RaiseException createExpectedTypeError( + ThreadContext context, String type, String fieldType, String fieldName, IRubyObject value) { + return createTypeError( + context, + String.format( + EXPECTED_TYPE_ERROR_FORMAT, type, fieldType, fieldName, value.getMetaClass())); + } + + public static RaiseException createInvalidTypeError( + ThreadContext context, String fieldType, String fieldName, IRubyObject value) { + return createTypeError( + context, + String.format(INVALID_TYPE_ERROR_FORMAT, fieldType, fieldName, value.getMetaClass())); + } + + protected static boolean isRubyNum(Object value) { + return value instanceof RubyFixnum || value instanceof RubyFloat || value instanceof RubyBignum; + } + + protected static void validateTypeClass( + ThreadContext context, FieldDescriptor.Type type, IRubyObject value) { + Ruby runtime = context.runtime; + if (!(value instanceof RubyModule)) { + throw runtime.newArgumentError("TypeClass has incorrect type"); } - - protected static boolean isRubyNum(Object value) { - return value instanceof RubyFixnum || value instanceof RubyFloat || value instanceof RubyBignum; + RubyModule klass = (RubyModule) value; + IRubyObject descriptor = klass.getInstanceVariable(DESCRIPTOR_INSTANCE_VAR); + if (descriptor.isNil()) { + throw runtime.newArgumentError( + "Type class has no descriptor. Please pass a " + + "class or enum as returned by the DescriptorPool."); } - - protected static void validateTypeClass(ThreadContext context, FieldDescriptor.Type type, IRubyObject value) { - Ruby runtime = context.runtime; - if (!(value instanceof RubyModule)) { - throw runtime.newArgumentError("TypeClass has incorrect type"); - } - RubyModule klass = (RubyModule) value; - IRubyObject descriptor = klass.getInstanceVariable(DESCRIPTOR_INSTANCE_VAR); - if (descriptor.isNil()) { - throw runtime.newArgumentError("Type class has no descriptor. Please pass a " + - "class or enum as returned by the DescriptorPool."); - } - if (type == FieldDescriptor.Type.MESSAGE) { - if (! (descriptor instanceof RubyDescriptor)) { - throw runtime.newArgumentError("Descriptor has an incorrect type"); - } - } else if (type == FieldDescriptor.Type.ENUM) { - if (! (descriptor instanceof RubyEnumDescriptor)) { - throw runtime.newArgumentError("Descriptor has an incorrect type"); - } - } + if (type == FieldDescriptor.Type.MESSAGE) { + if (!(descriptor instanceof RubyDescriptor)) { + throw runtime.newArgumentError("Descriptor has an incorrect type"); + } + } else if (type == FieldDescriptor.Type.ENUM) { + if (!(descriptor instanceof RubyEnumDescriptor)) { + throw runtime.newArgumentError("Descriptor has an incorrect type"); + } } + } - private static IRubyObject validateAndEncodeString(ThreadContext context, String fieldType, String fieldName, IRubyObject value, String encoding) { - if (!(value instanceof RubyString)) - throw createInvalidTypeError(context, fieldType, fieldName, value); + private static IRubyObject validateAndEncodeString( + ThreadContext context, + String fieldType, + String fieldName, + IRubyObject value, + String encoding) { + if (!(value instanceof RubyString)) + throw createInvalidTypeError(context, fieldType, fieldName, value); - value = ((RubyString) value).encode(context, context.runtime.evalScriptlet(encoding)); - value.setFrozen(true); - return value; - } + value = ((RubyString) value).encode(context, context.runtime.evalScriptlet(encoding)); + value.setFrozen(true); + return value; + } - public static final String DESCRIPTOR_INSTANCE_VAR = "@descriptor"; + public static final String DESCRIPTOR_INSTANCE_VAR = "@descriptor"; - public static final String EQUAL_SIGN = "="; + public static final String EQUAL_SIGN = "="; - private static final BigInteger UINT64_COMPLEMENTARY = new BigInteger("18446744073709551616"); //Math.pow(2, 64) + private static final BigInteger UINT64_COMPLEMENTARY = + new BigInteger("18446744073709551616"); // Math.pow(2, 64) - private static final String EXPECTED_TYPE_ERROR_FORMAT = "Expected %s type for %s field '%s' (given %s)."; - private static final String INVALID_TYPE_ERROR_FORMAT = "Invalid argument for %s field '%s' (given %s)."; + private static final String EXPECTED_TYPE_ERROR_FORMAT = + "Expected %s type for %s field '%s' (given %s)."; + private static final String INVALID_TYPE_ERROR_FORMAT = + "Invalid argument for %s field '%s' (given %s)."; - private static final long UINT_MAX = 0xffffffffl; + private static final long UINT_MAX = 0xffffffffl; - private static RubyClass cTypeError; + private static RubyClass cTypeError; } diff --git a/ruby/src/main/java/google/ProtobufJavaService.java b/ruby/src/main/java/google/ProtobufJavaService.java index 713891e1c121..00d60a1498ec 100644 --- a/ruby/src/main/java/google/ProtobufJavaService.java +++ b/ruby/src/main/java/google/ProtobufJavaService.java @@ -33,30 +33,29 @@ package google; import com.google.protobuf.jruby.*; +import java.io.IOException; import org.jruby.Ruby; import org.jruby.runtime.load.BasicLibraryService; -import java.io.IOException; - public class ProtobufJavaService implements BasicLibraryService { - @Override - public boolean basicLoad(Ruby ruby) throws IOException { - ruby.defineModule("Google"); + @Override + public boolean basicLoad(Ruby ruby) throws IOException { + ruby.defineModule("Google"); - /* - * The order these happen in is important because we - * save a static reference to some classes and they - * need to exist before we try to save a reference to them - */ - RubyProtobuf.createProtobuf(ruby); - RubyFileDescriptor.createRubyFileDescriptor(ruby); - RubyEnumDescriptor.createRubyEnumDescriptor(ruby); - RubyRepeatedField.createRubyRepeatedField(ruby); - RubyFieldDescriptor.createRubyFieldDescriptor(ruby); - RubyMap.createRubyMap(ruby); - RubyOneofDescriptor.createRubyOneofDescriptor(ruby); - RubyDescriptor.createRubyDescriptor(ruby); - RubyDescriptorPool.createRubyDescriptorPool(ruby); - return true; - } + /* + * The order these happen in is important because we + * save a static reference to some classes and they + * need to exist before we try to save a reference to them + */ + RubyProtobuf.createProtobuf(ruby); + RubyFileDescriptor.createRubyFileDescriptor(ruby); + RubyEnumDescriptor.createRubyEnumDescriptor(ruby); + RubyRepeatedField.createRubyRepeatedField(ruby); + RubyFieldDescriptor.createRubyFieldDescriptor(ruby); + RubyMap.createRubyMap(ruby); + RubyOneofDescriptor.createRubyOneofDescriptor(ruby); + RubyDescriptor.createRubyDescriptor(ruby); + RubyDescriptorPool.createRubyDescriptorPool(ruby); + return true; + } } From d0fc2794c4333c43d2a166ebac6b56da872eff50 Mon Sep 17 00:00:00 2001 From: Jason Lunn Date: Mon, 28 Mar 2022 19:00:18 -0400 Subject: [PATCH 17/54] Cleanup warnings seen when running tests. --- ruby/tests/repeated_field_test.rb | 35 ++++++++++++++----------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/ruby/tests/repeated_field_test.rb b/ruby/tests/repeated_field_test.rb index 7ffc0f180175..6ad39b556300 100755 --- a/ruby/tests/repeated_field_test.rb +++ b/ruby/tests/repeated_field_test.rb @@ -36,13 +36,13 @@ def test_first end fill_test_msg(m) - assert_equal -10, m.repeated_int32.first - assert_equal -1_000_000, m.repeated_int64.first + assert_equal( -10, m.repeated_int32.first ) + assert_equal( -1_000_000, m.repeated_int64.first ) assert_equal 10, m.repeated_uint32.first assert_equal 1_000_000, m.repeated_uint64.first assert_equal true, m.repeated_bool.first - assert_equal -1.01, m.repeated_float.first.round(2) - assert_equal -1.0000000000001, m.repeated_double.first + assert_equal( -1.01, m.repeated_float.first.round(2) ) + assert_equal( -1.0000000000001, m.repeated_double.first ) assert_equal 'foo', m.repeated_string.first assert_equal "bar".encode!('ASCII-8BIT'), m.repeated_bytes.first assert_equal TestMessage2.new(:foo => 1), m.repeated_msg.first @@ -61,13 +61,13 @@ def test_last assert_nil m.send(field_name).first end fill_test_msg(m) - assert_equal -11, m.repeated_int32.last - assert_equal -1_000_001, m.repeated_int64.last + assert_equal( -11, m.repeated_int32.last ) + assert_equal( -1_000_001, m.repeated_int64.last ) assert_equal 11, m.repeated_uint32.last assert_equal 1_000_001, m.repeated_uint64.last assert_equal false, m.repeated_bool.last - assert_equal -1.02, m.repeated_float.last.round(2) - assert_equal -1.0000000000002, m.repeated_double.last + assert_equal( -1.02, m.repeated_float.last.round(2) ) + assert_equal( -1.0000000000002, m.repeated_double.last ) assert_equal 'bar', m.repeated_string.last assert_equal "foo".encode!('ASCII-8BIT'), m.repeated_bytes.last assert_equal TestMessage2.new(:foo => 2), m.repeated_msg.last @@ -82,20 +82,20 @@ def test_pop end fill_test_msg(m) - assert_equal -11, m.repeated_int32.pop - assert_equal -10, m.repeated_int32.pop - assert_equal -1_000_001, m.repeated_int64.pop - assert_equal -1_000_000, m.repeated_int64.pop + assert_equal( -11, m.repeated_int32.pop ) + assert_equal( -10, m.repeated_int32.pop ) + assert_equal( -1_000_001, m.repeated_int64.pop ) + assert_equal( -1_000_000, m.repeated_int64.pop ) assert_equal 11, m.repeated_uint32.pop assert_equal 10, m.repeated_uint32.pop assert_equal 1_000_001, m.repeated_uint64.pop assert_equal 1_000_000, m.repeated_uint64.pop assert_equal false, m.repeated_bool.pop assert_equal true, m.repeated_bool.pop - assert_equal -1.02, m.repeated_float.pop.round(2) - assert_equal -1.01, m.repeated_float.pop.round(2) - assert_equal -1.0000000000002, m.repeated_double.pop - assert_equal -1.0000000000001, m.repeated_double.pop + assert_equal( -1.02, m.repeated_float.pop.round(2) ) + assert_equal( -1.01, m.repeated_float.pop.round(2) ) + assert_equal( -1.0000000000002, m.repeated_double.pop ) + assert_equal( -1.0000000000001, m.repeated_double.pop ) assert_equal 'bar', m.repeated_string.pop assert_equal 'foo', m.repeated_string.pop assert_equal "foo".encode!('ASCII-8BIT'), m.repeated_bytes.pop @@ -487,11 +487,8 @@ def test_shift def test_shuffle! m = TestMessage.new m.repeated_string += %w(foo bar baz) - orig_repeated_string = m.repeated_string.clone result = m.repeated_string.shuffle! assert_equal m.repeated_string, result - # NOTE: sometimes it doesn't change the order... - # assert_not_equal m.repeated_string.to_a, orig_repeated_string.to_a end def test_slice! From a114b008a205cebedd6e51762496d12841778d58 Mon Sep 17 00:00:00 2001 From: mkruskal-google Date: Mon, 28 Mar 2022 16:25:46 -0700 Subject: [PATCH 18/54] Reverting change to target frameworks that breaks kokoro --- csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj index a22ef944615c..fe5ff8046782 100644 --- a/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj +++ b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj @@ -1,7 +1,7 @@  - net462;netcoreapp3.1;net6.0 + net462;netcoreapp3.1;net60 ../../keys/Google.Protobuf.snk true False From e1e9d3e6da898dcce08381b50df20464dcc549c7 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Mon, 28 Mar 2022 11:31:18 +0100 Subject: [PATCH 19/54] Normalize all C# and .proto files to LF This commit should have no non-whitespace changes Fixes #9526 (in terms of content) --- .../Google.Protobuf.Test/ByteStringTest.cs | 340 +-- .../CodedInputStreamTest.cs | 1194 +++++----- .../CodedOutputStreamTest.cs | 836 +++---- .../DeprecatedMemberTest.cs | 110 +- .../GeneratedMessageTest.cs | 1450 ++++++------ .../src/Google.Protobuf.Test/IssuesTest.cs | 164 +- .../Google.Protobuf.Test/TestCornerCases.cs | 124 +- csharp/src/AddressBook/AddPerson.cs | 262 +-- csharp/src/AddressBook/ListPeople.cs | 196 +- csharp/src/AddressBook/Program.cs | 188 +- csharp/src/AddressBook/SampleUsage.cs | 144 +- .../src/Google.Protobuf.JsonDump/Program.cs | 144 +- .../Google.Protobuf.Test.TestProtos.csproj | 50 +- .../Google.Protobuf.Test/ByteStringTest.cs | 876 +++---- .../CodedInputStreamTest.cs | 2016 ++++++++--------- .../CodedOutputStreamTest.cs | 1164 +++++----- .../DeprecatedMemberTest.cs | 110 +- .../Google.Protobuf.Test/ExtensionSetTest.cs | 392 ++-- .../GeneratedMessageTest.Proto2.cs | 794 +++---- .../GeneratedMessageTest.cs | 1596 ++++++------- csharp/src/Google.Protobuf.Test/IssuesTest.cs | 232 +- .../Google.Protobuf.Test/JsonFormatterTest.cs | 1410 ++++++------ .../Google.Protobuf.Test/TestCornerCases.cs | 124 +- .../WellKnownTypes/AnyTest.cs | 18 +- csharp/src/Google.Protobuf/ByteArray.cs | 156 +- csharp/src/Google.Protobuf/ByteString.cs | 866 +++---- .../src/Google.Protobuf/CodedInputStream.cs | 1396 ++++++------ .../CodedOutputStream.ComputeSize.cs | 614 ++--- .../src/Google.Protobuf/CodedOutputStream.cs | 1214 +++++----- .../Google.Protobuf/Collections/MapField.cs | 1524 ++++++------- .../Collections/ReadOnlyDictionary.cs | 292 +-- .../Collections/RepeatedField.cs | 1396 ++++++------ csharp/src/Google.Protobuf/ExtensionSet.cs | 856 +++---- .../Google.Protobuf/FrameworkPortability.cs | 96 +- csharp/src/Google.Protobuf/IMessage.cs | 174 +- .../InvalidProtocolBufferException.cs | 278 +-- csharp/src/Google.Protobuf/JsonFormatter.cs | 24 +- csharp/src/Google.Protobuf/ObjectIntPair.cs | 74 +- .../Properties/AssemblyInfo.cs | 112 +- .../src/Google.Protobuf/ProtoPreconditions.cs | 156 +- .../WellKnownTypes/AnyPartial.cs | 18 +- csharp/src/Google.Protobuf/WireFormat.cs | 206 +- 42 files changed, 11693 insertions(+), 11693 deletions(-) diff --git a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/ByteStringTest.cs b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/ByteStringTest.cs index 685e130a748c..8935b7829d4a 100644 --- a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/ByteStringTest.cs +++ b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/ByteStringTest.cs @@ -1,171 +1,171 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.Text; -using NUnit.Framework; - -namespace Google.Protobuf -{ - public class ByteStringTest - { - [Test] - public void Equality() - { - ByteString b1 = ByteString.CopyFrom(1, 2, 3); - ByteString b2 = ByteString.CopyFrom(1, 2, 3); - ByteString b3 = ByteString.CopyFrom(1, 2, 4); - ByteString b4 = ByteString.CopyFrom(1, 2, 3, 4); - EqualityTester.AssertEquality(b1, b1); - EqualityTester.AssertEquality(b1, b2); - EqualityTester.AssertInequality(b1, b3); - EqualityTester.AssertInequality(b1, b4); - EqualityTester.AssertInequality(b1, null); -#pragma warning disable 1718 // Deliberately calling ==(b1, b1) and !=(b1, b1) - Assert.IsTrue(b1 == b1); - Assert.IsTrue(b1 == b2); - Assert.IsFalse(b1 == b3); - Assert.IsFalse(b1 == b4); - Assert.IsFalse(b1 == null); - Assert.IsTrue((ByteString) null == null); - Assert.IsFalse(b1 != b1); - Assert.IsFalse(b1 != b2); -#pragma warning disable 1718 - Assert.IsTrue(b1 != b3); - Assert.IsTrue(b1 != b4); - Assert.IsTrue(b1 != null); - Assert.IsFalse((ByteString) null != null); - } - - [Test] - public void EmptyByteStringHasZeroSize() - { - Assert.AreEqual(0, ByteString.Empty.Length); - } - - [Test] - public void CopyFromStringWithExplicitEncoding() - { - ByteString bs = ByteString.CopyFrom("AB", Encoding.Unicode); - Assert.AreEqual(4, bs.Length); - Assert.AreEqual(65, bs[0]); - Assert.AreEqual(0, bs[1]); - Assert.AreEqual(66, bs[2]); - Assert.AreEqual(0, bs[3]); - } - - [Test] - public void IsEmptyWhenEmpty() - { - Assert.IsTrue(ByteString.CopyFromUtf8("").IsEmpty); - } - - [Test] - public void IsEmptyWhenNotEmpty() - { - Assert.IsFalse(ByteString.CopyFromUtf8("X").IsEmpty); - } - - [Test] - public void CopyFromByteArrayCopiesContents() - { - byte[] data = new byte[1]; - data[0] = 10; - ByteString bs = ByteString.CopyFrom(data); - Assert.AreEqual(10, bs[0]); - data[0] = 5; - Assert.AreEqual(10, bs[0]); - } - - [Test] - public void ToByteArrayCopiesContents() - { - ByteString bs = ByteString.CopyFromUtf8("Hello"); - byte[] data = bs.ToByteArray(); - Assert.AreEqual((byte)'H', data[0]); - Assert.AreEqual((byte)'H', bs[0]); - data[0] = 0; - Assert.AreEqual(0, data[0]); - Assert.AreEqual((byte)'H', bs[0]); - } - - [Test] - public void CopyFromUtf8UsesUtf8() - { - ByteString bs = ByteString.CopyFromUtf8("\u20ac"); - Assert.AreEqual(3, bs.Length); - Assert.AreEqual(0xe2, bs[0]); - Assert.AreEqual(0x82, bs[1]); - Assert.AreEqual(0xac, bs[2]); - } - - [Test] - public void CopyFromPortion() - { - byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6}; - ByteString bs = ByteString.CopyFrom(data, 2, 3); - Assert.AreEqual(3, bs.Length); - Assert.AreEqual(2, bs[0]); - Assert.AreEqual(3, bs[1]); - } - - [Test] - public void ToStringUtf8() - { - ByteString bs = ByteString.CopyFromUtf8("\u20ac"); - Assert.AreEqual("\u20ac", bs.ToStringUtf8()); - } - - [Test] - public void ToStringWithExplicitEncoding() - { - ByteString bs = ByteString.CopyFrom("\u20ac", Encoding.Unicode); - Assert.AreEqual("\u20ac", bs.ToString(Encoding.Unicode)); - } - - [Test] - public void FromBase64_WithText() - { - byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6}; - string base64 = Convert.ToBase64String(data); - ByteString bs = ByteString.FromBase64(base64); - Assert.AreEqual(data, bs.ToByteArray()); - } - - [Test] - public void FromBase64_Empty() - { - // Optimization which also fixes issue 61. - Assert.AreSame(ByteString.Empty, ByteString.FromBase64("")); - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.Text; +using NUnit.Framework; + +namespace Google.Protobuf +{ + public class ByteStringTest + { + [Test] + public void Equality() + { + ByteString b1 = ByteString.CopyFrom(1, 2, 3); + ByteString b2 = ByteString.CopyFrom(1, 2, 3); + ByteString b3 = ByteString.CopyFrom(1, 2, 4); + ByteString b4 = ByteString.CopyFrom(1, 2, 3, 4); + EqualityTester.AssertEquality(b1, b1); + EqualityTester.AssertEquality(b1, b2); + EqualityTester.AssertInequality(b1, b3); + EqualityTester.AssertInequality(b1, b4); + EqualityTester.AssertInequality(b1, null); +#pragma warning disable 1718 // Deliberately calling ==(b1, b1) and !=(b1, b1) + Assert.IsTrue(b1 == b1); + Assert.IsTrue(b1 == b2); + Assert.IsFalse(b1 == b3); + Assert.IsFalse(b1 == b4); + Assert.IsFalse(b1 == null); + Assert.IsTrue((ByteString) null == null); + Assert.IsFalse(b1 != b1); + Assert.IsFalse(b1 != b2); +#pragma warning disable 1718 + Assert.IsTrue(b1 != b3); + Assert.IsTrue(b1 != b4); + Assert.IsTrue(b1 != null); + Assert.IsFalse((ByteString) null != null); + } + + [Test] + public void EmptyByteStringHasZeroSize() + { + Assert.AreEqual(0, ByteString.Empty.Length); + } + + [Test] + public void CopyFromStringWithExplicitEncoding() + { + ByteString bs = ByteString.CopyFrom("AB", Encoding.Unicode); + Assert.AreEqual(4, bs.Length); + Assert.AreEqual(65, bs[0]); + Assert.AreEqual(0, bs[1]); + Assert.AreEqual(66, bs[2]); + Assert.AreEqual(0, bs[3]); + } + + [Test] + public void IsEmptyWhenEmpty() + { + Assert.IsTrue(ByteString.CopyFromUtf8("").IsEmpty); + } + + [Test] + public void IsEmptyWhenNotEmpty() + { + Assert.IsFalse(ByteString.CopyFromUtf8("X").IsEmpty); + } + + [Test] + public void CopyFromByteArrayCopiesContents() + { + byte[] data = new byte[1]; + data[0] = 10; + ByteString bs = ByteString.CopyFrom(data); + Assert.AreEqual(10, bs[0]); + data[0] = 5; + Assert.AreEqual(10, bs[0]); + } + + [Test] + public void ToByteArrayCopiesContents() + { + ByteString bs = ByteString.CopyFromUtf8("Hello"); + byte[] data = bs.ToByteArray(); + Assert.AreEqual((byte)'H', data[0]); + Assert.AreEqual((byte)'H', bs[0]); + data[0] = 0; + Assert.AreEqual(0, data[0]); + Assert.AreEqual((byte)'H', bs[0]); + } + + [Test] + public void CopyFromUtf8UsesUtf8() + { + ByteString bs = ByteString.CopyFromUtf8("\u20ac"); + Assert.AreEqual(3, bs.Length); + Assert.AreEqual(0xe2, bs[0]); + Assert.AreEqual(0x82, bs[1]); + Assert.AreEqual(0xac, bs[2]); + } + + [Test] + public void CopyFromPortion() + { + byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6}; + ByteString bs = ByteString.CopyFrom(data, 2, 3); + Assert.AreEqual(3, bs.Length); + Assert.AreEqual(2, bs[0]); + Assert.AreEqual(3, bs[1]); + } + + [Test] + public void ToStringUtf8() + { + ByteString bs = ByteString.CopyFromUtf8("\u20ac"); + Assert.AreEqual("\u20ac", bs.ToStringUtf8()); + } + + [Test] + public void ToStringWithExplicitEncoding() + { + ByteString bs = ByteString.CopyFrom("\u20ac", Encoding.Unicode); + Assert.AreEqual("\u20ac", bs.ToString(Encoding.Unicode)); + } + + [Test] + public void FromBase64_WithText() + { + byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6}; + string base64 = Convert.ToBase64String(data); + ByteString bs = ByteString.FromBase64(base64); + Assert.AreEqual(data, bs.ToByteArray()); + } + + [Test] + public void FromBase64_Empty() + { + // Optimization which also fixes issue 61. + Assert.AreSame(ByteString.Empty, ByteString.FromBase64("")); + } + } } \ No newline at end of file diff --git a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/CodedInputStreamTest.cs b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/CodedInputStreamTest.cs index 11d06f1d7b43..5ac8c71a82e2 100644 --- a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/CodedInputStreamTest.cs +++ b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/CodedInputStreamTest.cs @@ -1,598 +1,598 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.IO; -using Google.Protobuf.TestProtos; -using NUnit.Framework; - -namespace Google.Protobuf -{ - public class CodedInputStreamTest - { - /// - /// Helper to construct a byte array from a bunch of bytes. The inputs are - /// actually ints so that I can use hex notation and not get stupid errors - /// about precision. - /// - private static byte[] Bytes(params int[] bytesAsInts) - { - byte[] bytes = new byte[bytesAsInts.Length]; - for (int i = 0; i < bytesAsInts.Length; i++) - { - bytes[i] = (byte) bytesAsInts[i]; - } - return bytes; - } - - /// - /// Parses the given bytes using ReadRawVarint32() and ReadRawVarint64() - /// - private static void AssertReadVarint(byte[] data, ulong value) - { - CodedInputStream input = new CodedInputStream(data); - Assert.AreEqual((uint) value, input.ReadRawVarint32()); - - input = new CodedInputStream(data); - Assert.AreEqual(value, input.ReadRawVarint64()); - Assert.IsTrue(input.IsAtEnd); - - // Try different block sizes. - for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2) - { - input = new CodedInputStream(new SmallBlockInputStream(data, bufferSize)); - Assert.AreEqual((uint) value, input.ReadRawVarint32()); - - input = new CodedInputStream(new SmallBlockInputStream(data, bufferSize)); - Assert.AreEqual(value, input.ReadRawVarint64()); - Assert.IsTrue(input.IsAtEnd); - } - - // Try reading directly from a MemoryStream. We want to verify that it - // doesn't read past the end of the input, so write an extra byte - this - // lets us test the position at the end. - MemoryStream memoryStream = new MemoryStream(); - memoryStream.Write(data, 0, data.Length); - memoryStream.WriteByte(0); - memoryStream.Position = 0; - Assert.AreEqual((uint) value, CodedInputStream.ReadRawVarint32(memoryStream)); - Assert.AreEqual(data.Length, memoryStream.Position); - } - - /// - /// Parses the given bytes using ReadRawVarint32() and ReadRawVarint64() and - /// expects them to fail with an InvalidProtocolBufferException whose - /// description matches the given one. - /// - private static void AssertReadVarintFailure(InvalidProtocolBufferException expected, byte[] data) - { - CodedInputStream input = new CodedInputStream(data); - var exception = Assert.Throws(() => input.ReadRawVarint32()); - Assert.AreEqual(expected.Message, exception.Message); - - input = new CodedInputStream(data); - exception = Assert.Throws(() => input.ReadRawVarint64()); - Assert.AreEqual(expected.Message, exception.Message); - - // Make sure we get the same error when reading directly from a Stream. - exception = Assert.Throws(() => CodedInputStream.ReadRawVarint32(new MemoryStream(data))); - Assert.AreEqual(expected.Message, exception.Message); - } - - [Test] - public void ReadVarint() - { - AssertReadVarint(Bytes(0x00), 0); - AssertReadVarint(Bytes(0x01), 1); - AssertReadVarint(Bytes(0x7f), 127); - // 14882 - AssertReadVarint(Bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7)); - // 2961488830 - AssertReadVarint(Bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b), - (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | - (0x0bL << 28)); - - // 64-bit - // 7256456126 - AssertReadVarint(Bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b), - (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | - (0x1bL << 28)); - // 41256202580718336 - AssertReadVarint(Bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49), - (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | - (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49)); - // 11964378330978735131 - AssertReadVarint(Bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01), - (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | - (0x3bUL << 28) | (0x56UL << 35) | (0x00UL << 42) | - (0x05UL << 49) | (0x26UL << 56) | (0x01UL << 63)); - - // Failures - AssertReadVarintFailure( - InvalidProtocolBufferException.MalformedVarint(), - Bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x00)); - AssertReadVarintFailure( - InvalidProtocolBufferException.TruncatedMessage(), - Bytes(0x80)); - } - - /// - /// Parses the given bytes using ReadRawLittleEndian32() and checks - /// that the result matches the given value. - /// - private static void AssertReadLittleEndian32(byte[] data, uint value) - { - CodedInputStream input = new CodedInputStream(data); - Assert.AreEqual(value, input.ReadRawLittleEndian32()); - Assert.IsTrue(input.IsAtEnd); - - // Try different block sizes. - for (int blockSize = 1; blockSize <= 16; blockSize *= 2) - { - input = new CodedInputStream( - new SmallBlockInputStream(data, blockSize)); - Assert.AreEqual(value, input.ReadRawLittleEndian32()); - Assert.IsTrue(input.IsAtEnd); - } - } - - /// - /// Parses the given bytes using ReadRawLittleEndian64() and checks - /// that the result matches the given value. - /// - private static void AssertReadLittleEndian64(byte[] data, ulong value) - { - CodedInputStream input = new CodedInputStream(data); - Assert.AreEqual(value, input.ReadRawLittleEndian64()); - Assert.IsTrue(input.IsAtEnd); - - // Try different block sizes. - for (int blockSize = 1; blockSize <= 16; blockSize *= 2) - { - input = new CodedInputStream( - new SmallBlockInputStream(data, blockSize)); - Assert.AreEqual(value, input.ReadRawLittleEndian64()); - Assert.IsTrue(input.IsAtEnd); - } - } - - [Test] - public void ReadLittleEndian() - { - AssertReadLittleEndian32(Bytes(0x78, 0x56, 0x34, 0x12), 0x12345678); - AssertReadLittleEndian32(Bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0); - - AssertReadLittleEndian64(Bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12), - 0x123456789abcdef0L); - AssertReadLittleEndian64( - Bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef012345678UL); - } - - [Test] - public void DecodeZigZag32() - { - Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag32(0)); - Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag32(1)); - Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag32(2)); - Assert.AreEqual(-2, ParsingPrimitives.DecodeZigZag32(3)); - Assert.AreEqual(0x3FFFFFFF, ParsingPrimitives.DecodeZigZag32(0x7FFFFFFE)); - Assert.AreEqual(unchecked((int) 0xC0000000), ParsingPrimitives.DecodeZigZag32(0x7FFFFFFF)); - Assert.AreEqual(0x7FFFFFFF, ParsingPrimitives.DecodeZigZag32(0xFFFFFFFE)); - Assert.AreEqual(unchecked((int) 0x80000000), ParsingPrimitives.DecodeZigZag32(0xFFFFFFFF)); - } - - [Test] - public void DecodeZigZag64() - { - Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag64(0)); - Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag64(1)); - Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag64(2)); - Assert.AreEqual(-2, ParsingPrimitives.DecodeZigZag64(3)); - Assert.AreEqual(0x000000003FFFFFFFL, ParsingPrimitives.DecodeZigZag64(0x000000007FFFFFFEL)); - Assert.AreEqual(unchecked((long) 0xFFFFFFFFC0000000L), ParsingPrimitives.DecodeZigZag64(0x000000007FFFFFFFL)); - Assert.AreEqual(0x000000007FFFFFFFL, ParsingPrimitives.DecodeZigZag64(0x00000000FFFFFFFEL)); - Assert.AreEqual(unchecked((long) 0xFFFFFFFF80000000L), ParsingPrimitives.DecodeZigZag64(0x00000000FFFFFFFFL)); - Assert.AreEqual(0x7FFFFFFFFFFFFFFFL, ParsingPrimitives.DecodeZigZag64(0xFFFFFFFFFFFFFFFEL)); - Assert.AreEqual(unchecked((long) 0x8000000000000000L), ParsingPrimitives.DecodeZigZag64(0xFFFFFFFFFFFFFFFFL)); - } - - [Test] - public void ReadWholeMessage_VaryingBlockSizes() - { - TestAllTypes message = SampleMessages.CreateFullTestAllTypes(); - - byte[] rawBytes = message.ToByteArray(); - Assert.AreEqual(rawBytes.Length, message.CalculateSize()); - TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(rawBytes); - Assert.AreEqual(message, message2); - - // Try different block sizes. - for (int blockSize = 1; blockSize < 256; blockSize *= 2) - { - message2 = TestAllTypes.Parser.ParseFrom(new SmallBlockInputStream(rawBytes, blockSize)); - Assert.AreEqual(message, message2); - } - } - - [Test] - public void ReadHugeBlob() - { - // Allocate and initialize a 1MB blob. - byte[] blob = new byte[1 << 20]; - for (int i = 0; i < blob.Length; i++) - { - blob[i] = (byte) i; - } - - // Make a message containing it. - var message = new TestAllTypes { SingleBytes = ByteString.CopyFrom(blob) }; - - // Serialize and parse it. Make sure to parse from an InputStream, not - // directly from a ByteString, so that CodedInputStream uses buffered - // reading. - TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(message.ToByteString()); - - Assert.AreEqual(message, message2); - } - - [Test] - public void ReadMaliciouslyLargeBlob() - { - MemoryStream ms = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(ms); - - uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); - output.WriteRawVarint32(tag); - output.WriteRawVarint32(0x7FFFFFFF); - output.WriteRawBytes(new byte[32]); // Pad with a few random bytes. - output.Flush(); - ms.Position = 0; - - CodedInputStream input = new CodedInputStream(ms); - Assert.AreEqual(tag, input.ReadTag()); - - Assert.Throws(() => input.ReadBytes()); - } - - internal static TestRecursiveMessage MakeRecursiveMessage(int depth) - { - if (depth == 0) - { - return new TestRecursiveMessage { I = 5 }; - } - else - { - return new TestRecursiveMessage { A = MakeRecursiveMessage(depth - 1) }; - } - } - - internal static void AssertMessageDepth(TestRecursiveMessage message, int depth) - { - if (depth == 0) - { - Assert.IsNull(message.A); - Assert.AreEqual(5, message.I); - } - else - { - Assert.IsNotNull(message.A); - AssertMessageDepth(message.A, depth - 1); - } - } - - [Test] - public void MaliciousRecursion() - { - ByteString atRecursiveLimit = MakeRecursiveMessage(CodedInputStream.DefaultRecursionLimit).ToByteString(); - ByteString beyondRecursiveLimit = MakeRecursiveMessage(CodedInputStream.DefaultRecursionLimit + 1).ToByteString(); - - AssertMessageDepth(TestRecursiveMessage.Parser.ParseFrom(atRecursiveLimit), CodedInputStream.DefaultRecursionLimit); - - Assert.Throws(() => TestRecursiveMessage.Parser.ParseFrom(beyondRecursiveLimit)); - - CodedInputStream input = CodedInputStream.CreateWithLimits(new MemoryStream(atRecursiveLimit.ToByteArray()), 1000000, CodedInputStream.DefaultRecursionLimit - 1); - Assert.Throws(() => TestRecursiveMessage.Parser.ParseFrom(input)); - } - - [Test] - public void SizeLimit() - { - // Have to use a Stream rather than ByteString.CreateCodedInput as SizeLimit doesn't - // apply to the latter case. - MemoryStream ms = new MemoryStream(SampleMessages.CreateFullTestAllTypes().ToByteArray()); - CodedInputStream input = CodedInputStream.CreateWithLimits(ms, 16, 100); - Assert.Throws(() => TestAllTypes.Parser.ParseFrom(input)); - } - - /// - /// Tests that if we read an string that contains invalid UTF-8, no exception - /// is thrown. Instead, the invalid bytes are replaced with the Unicode - /// "replacement character" U+FFFD. - /// - [Test] - public void ReadInvalidUtf8() - { - MemoryStream ms = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(ms); - - uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); - output.WriteRawVarint32(tag); - output.WriteRawVarint32(1); - output.WriteRawBytes(new byte[] {0x80}); - output.Flush(); - ms.Position = 0; - - CodedInputStream input = new CodedInputStream(ms); - - Assert.AreEqual(tag, input.ReadTag()); - string text = input.ReadString(); - Assert.AreEqual('\ufffd', text[0]); - } - - /// - /// A stream which limits the number of bytes it reads at a time. - /// We use this to make sure that CodedInputStream doesn't screw up when - /// reading in small blocks. - /// - private sealed class SmallBlockInputStream : MemoryStream - { - private readonly int blockSize; - - public SmallBlockInputStream(byte[] data, int blockSize) - : base(data) - { - this.blockSize = blockSize; - } - - public override int Read(byte[] buffer, int offset, int count) - { - return base.Read(buffer, offset, Math.Min(count, blockSize)); - } - } - - [Test] - public void TestNegativeEnum() - { - byte[] bytes = { 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01 }; - CodedInputStream input = new CodedInputStream(bytes); - Assert.AreEqual((int)SampleEnum.NegativeValue, input.ReadEnum()); - Assert.IsTrue(input.IsAtEnd); - } - - //Issue 71: CodedInputStream.ReadBytes go to slow path unnecessarily - [Test] - public void TestSlowPathAvoidance() - { - using (var ms = new MemoryStream()) - { - CodedOutputStream output = new CodedOutputStream(ms); - output.WriteTag(1, WireFormat.WireType.LengthDelimited); - output.WriteBytes(ByteString.CopyFrom(new byte[100])); - output.WriteTag(2, WireFormat.WireType.LengthDelimited); - output.WriteBytes(ByteString.CopyFrom(new byte[100])); - output.Flush(); - - ms.Position = 0; - CodedInputStream input = new CodedInputStream(ms, new byte[ms.Length / 2], 0, 0, false); - - uint tag = input.ReadTag(); - Assert.AreEqual(1, WireFormat.GetTagFieldNumber(tag)); - Assert.AreEqual(100, input.ReadBytes().Length); - - tag = input.ReadTag(); - Assert.AreEqual(2, WireFormat.GetTagFieldNumber(tag)); - Assert.AreEqual(100, input.ReadBytes().Length); - } - } - - [Test] - public void Tag0Throws() - { - var input = new CodedInputStream(new byte[] { 0 }); - Assert.Throws(() => input.ReadTag()); - } - - [Test] - public void SkipGroup() - { - // Create an output stream with a group in: - // Field 1: string "field 1" - // Field 2: group containing: - // Field 1: fixed int32 value 100 - // Field 2: string "ignore me" - // Field 3: nested group containing - // Field 1: fixed int64 value 1000 - // Field 3: string "field 3" - var stream = new MemoryStream(); - var output = new CodedOutputStream(stream); - output.WriteTag(1, WireFormat.WireType.LengthDelimited); - output.WriteString("field 1"); - - // The outer group... - output.WriteTag(2, WireFormat.WireType.StartGroup); - output.WriteTag(1, WireFormat.WireType.Fixed32); - output.WriteFixed32(100); - output.WriteTag(2, WireFormat.WireType.LengthDelimited); - output.WriteString("ignore me"); - // The nested group... - output.WriteTag(3, WireFormat.WireType.StartGroup); - output.WriteTag(1, WireFormat.WireType.Fixed64); - output.WriteFixed64(1000); - // Note: Not sure the field number is relevant for end group... - output.WriteTag(3, WireFormat.WireType.EndGroup); - - // End the outer group - output.WriteTag(2, WireFormat.WireType.EndGroup); - - output.WriteTag(3, WireFormat.WireType.LengthDelimited); - output.WriteString("field 3"); - output.Flush(); - stream.Position = 0; - - // Now act like a generated client - var input = new CodedInputStream(stream); - Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited), input.ReadTag()); - Assert.AreEqual("field 1", input.ReadString()); - Assert.AreEqual(WireFormat.MakeTag(2, WireFormat.WireType.StartGroup), input.ReadTag()); - input.SkipLastField(); // Should consume the whole group, including the nested one. - Assert.AreEqual(WireFormat.MakeTag(3, WireFormat.WireType.LengthDelimited), input.ReadTag()); - Assert.AreEqual("field 3", input.ReadString()); - } - - [Test] - public void SkipGroup_WrongEndGroupTag() - { - // Create an output stream with: - // Field 1: string "field 1" - // Start group 2 - // Field 3: fixed int32 - // End group 4 (should give an error) - var stream = new MemoryStream(); - var output = new CodedOutputStream(stream); - output.WriteTag(1, WireFormat.WireType.LengthDelimited); - output.WriteString("field 1"); - - // The outer group... - output.WriteTag(2, WireFormat.WireType.StartGroup); - output.WriteTag(3, WireFormat.WireType.Fixed32); - output.WriteFixed32(100); - output.WriteTag(4, WireFormat.WireType.EndGroup); - output.Flush(); - stream.Position = 0; - - // Now act like a generated client - var input = new CodedInputStream(stream); - Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited), input.ReadTag()); - Assert.AreEqual("field 1", input.ReadString()); - Assert.AreEqual(WireFormat.MakeTag(2, WireFormat.WireType.StartGroup), input.ReadTag()); - Assert.Throws(input.SkipLastField); - } - - [Test] - public void RogueEndGroupTag() - { - // If we have an end-group tag without a leading start-group tag, generated - // code will just call SkipLastField... so that should fail. - - var stream = new MemoryStream(); - var output = new CodedOutputStream(stream); - output.WriteTag(1, WireFormat.WireType.EndGroup); - output.Flush(); - stream.Position = 0; - - var input = new CodedInputStream(stream); - Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.EndGroup), input.ReadTag()); - Assert.Throws(input.SkipLastField); - } - - [Test] - public void EndOfStreamReachedWhileSkippingGroup() - { - var stream = new MemoryStream(); - var output = new CodedOutputStream(stream); - output.WriteTag(1, WireFormat.WireType.StartGroup); - output.WriteTag(2, WireFormat.WireType.StartGroup); - output.WriteTag(2, WireFormat.WireType.EndGroup); - - output.Flush(); - stream.Position = 0; - - // Now act like a generated client - var input = new CodedInputStream(stream); - input.ReadTag(); - Assert.Throws(input.SkipLastField); - } - - [Test] - public void RecursionLimitAppliedWhileSkippingGroup() - { - var stream = new MemoryStream(); - var output = new CodedOutputStream(stream); - for (int i = 0; i < CodedInputStream.DefaultRecursionLimit + 1; i++) - { - output.WriteTag(1, WireFormat.WireType.StartGroup); - } - for (int i = 0; i < CodedInputStream.DefaultRecursionLimit + 1; i++) - { - output.WriteTag(1, WireFormat.WireType.EndGroup); - } - output.Flush(); - stream.Position = 0; - - // Now act like a generated client - var input = new CodedInputStream(stream); - Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.StartGroup), input.ReadTag()); - Assert.Throws(input.SkipLastField); - } - - [Test] - public void Construction_Invalid() - { - Assert.Throws(() => new CodedInputStream((byte[]) null)); - Assert.Throws(() => new CodedInputStream(null, 0, 0)); - Assert.Throws(() => new CodedInputStream((Stream) null)); - Assert.Throws(() => new CodedInputStream(new byte[10], 100, 0)); - Assert.Throws(() => new CodedInputStream(new byte[10], 5, 10)); - } - - [Test] - public void CreateWithLimits_InvalidLimits() - { - var stream = new MemoryStream(); - Assert.Throws(() => CodedInputStream.CreateWithLimits(stream, 0, 1)); - Assert.Throws(() => CodedInputStream.CreateWithLimits(stream, 1, 0)); - } - - [Test] - public void Dispose_DisposesUnderlyingStream() - { - var memoryStream = new MemoryStream(); - Assert.IsTrue(memoryStream.CanRead); - using (var cis = new CodedInputStream(memoryStream)) - { - } - Assert.IsFalse(memoryStream.CanRead); // Disposed - } - - [Test] - public void Dispose_WithLeaveOpen() - { - var memoryStream = new MemoryStream(); - Assert.IsTrue(memoryStream.CanRead); - using (var cis = new CodedInputStream(memoryStream, true)) - { - } - Assert.IsTrue(memoryStream.CanRead); // We left the stream open - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.IO; +using Google.Protobuf.TestProtos; +using NUnit.Framework; + +namespace Google.Protobuf +{ + public class CodedInputStreamTest + { + /// + /// Helper to construct a byte array from a bunch of bytes. The inputs are + /// actually ints so that I can use hex notation and not get stupid errors + /// about precision. + /// + private static byte[] Bytes(params int[] bytesAsInts) + { + byte[] bytes = new byte[bytesAsInts.Length]; + for (int i = 0; i < bytesAsInts.Length; i++) + { + bytes[i] = (byte) bytesAsInts[i]; + } + return bytes; + } + + /// + /// Parses the given bytes using ReadRawVarint32() and ReadRawVarint64() + /// + private static void AssertReadVarint(byte[] data, ulong value) + { + CodedInputStream input = new CodedInputStream(data); + Assert.AreEqual((uint) value, input.ReadRawVarint32()); + + input = new CodedInputStream(data); + Assert.AreEqual(value, input.ReadRawVarint64()); + Assert.IsTrue(input.IsAtEnd); + + // Try different block sizes. + for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2) + { + input = new CodedInputStream(new SmallBlockInputStream(data, bufferSize)); + Assert.AreEqual((uint) value, input.ReadRawVarint32()); + + input = new CodedInputStream(new SmallBlockInputStream(data, bufferSize)); + Assert.AreEqual(value, input.ReadRawVarint64()); + Assert.IsTrue(input.IsAtEnd); + } + + // Try reading directly from a MemoryStream. We want to verify that it + // doesn't read past the end of the input, so write an extra byte - this + // lets us test the position at the end. + MemoryStream memoryStream = new MemoryStream(); + memoryStream.Write(data, 0, data.Length); + memoryStream.WriteByte(0); + memoryStream.Position = 0; + Assert.AreEqual((uint) value, CodedInputStream.ReadRawVarint32(memoryStream)); + Assert.AreEqual(data.Length, memoryStream.Position); + } + + /// + /// Parses the given bytes using ReadRawVarint32() and ReadRawVarint64() and + /// expects them to fail with an InvalidProtocolBufferException whose + /// description matches the given one. + /// + private static void AssertReadVarintFailure(InvalidProtocolBufferException expected, byte[] data) + { + CodedInputStream input = new CodedInputStream(data); + var exception = Assert.Throws(() => input.ReadRawVarint32()); + Assert.AreEqual(expected.Message, exception.Message); + + input = new CodedInputStream(data); + exception = Assert.Throws(() => input.ReadRawVarint64()); + Assert.AreEqual(expected.Message, exception.Message); + + // Make sure we get the same error when reading directly from a Stream. + exception = Assert.Throws(() => CodedInputStream.ReadRawVarint32(new MemoryStream(data))); + Assert.AreEqual(expected.Message, exception.Message); + } + + [Test] + public void ReadVarint() + { + AssertReadVarint(Bytes(0x00), 0); + AssertReadVarint(Bytes(0x01), 1); + AssertReadVarint(Bytes(0x7f), 127); + // 14882 + AssertReadVarint(Bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7)); + // 2961488830 + AssertReadVarint(Bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b), + (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | + (0x0bL << 28)); + + // 64-bit + // 7256456126 + AssertReadVarint(Bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b), + (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | + (0x1bL << 28)); + // 41256202580718336 + AssertReadVarint(Bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49), + (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | + (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49)); + // 11964378330978735131 + AssertReadVarint(Bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01), + (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | + (0x3bUL << 28) | (0x56UL << 35) | (0x00UL << 42) | + (0x05UL << 49) | (0x26UL << 56) | (0x01UL << 63)); + + // Failures + AssertReadVarintFailure( + InvalidProtocolBufferException.MalformedVarint(), + Bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x00)); + AssertReadVarintFailure( + InvalidProtocolBufferException.TruncatedMessage(), + Bytes(0x80)); + } + + /// + /// Parses the given bytes using ReadRawLittleEndian32() and checks + /// that the result matches the given value. + /// + private static void AssertReadLittleEndian32(byte[] data, uint value) + { + CodedInputStream input = new CodedInputStream(data); + Assert.AreEqual(value, input.ReadRawLittleEndian32()); + Assert.IsTrue(input.IsAtEnd); + + // Try different block sizes. + for (int blockSize = 1; blockSize <= 16; blockSize *= 2) + { + input = new CodedInputStream( + new SmallBlockInputStream(data, blockSize)); + Assert.AreEqual(value, input.ReadRawLittleEndian32()); + Assert.IsTrue(input.IsAtEnd); + } + } + + /// + /// Parses the given bytes using ReadRawLittleEndian64() and checks + /// that the result matches the given value. + /// + private static void AssertReadLittleEndian64(byte[] data, ulong value) + { + CodedInputStream input = new CodedInputStream(data); + Assert.AreEqual(value, input.ReadRawLittleEndian64()); + Assert.IsTrue(input.IsAtEnd); + + // Try different block sizes. + for (int blockSize = 1; blockSize <= 16; blockSize *= 2) + { + input = new CodedInputStream( + new SmallBlockInputStream(data, blockSize)); + Assert.AreEqual(value, input.ReadRawLittleEndian64()); + Assert.IsTrue(input.IsAtEnd); + } + } + + [Test] + public void ReadLittleEndian() + { + AssertReadLittleEndian32(Bytes(0x78, 0x56, 0x34, 0x12), 0x12345678); + AssertReadLittleEndian32(Bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0); + + AssertReadLittleEndian64(Bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12), + 0x123456789abcdef0L); + AssertReadLittleEndian64( + Bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef012345678UL); + } + + [Test] + public void DecodeZigZag32() + { + Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag32(0)); + Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag32(1)); + Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag32(2)); + Assert.AreEqual(-2, ParsingPrimitives.DecodeZigZag32(3)); + Assert.AreEqual(0x3FFFFFFF, ParsingPrimitives.DecodeZigZag32(0x7FFFFFFE)); + Assert.AreEqual(unchecked((int) 0xC0000000), ParsingPrimitives.DecodeZigZag32(0x7FFFFFFF)); + Assert.AreEqual(0x7FFFFFFF, ParsingPrimitives.DecodeZigZag32(0xFFFFFFFE)); + Assert.AreEqual(unchecked((int) 0x80000000), ParsingPrimitives.DecodeZigZag32(0xFFFFFFFF)); + } + + [Test] + public void DecodeZigZag64() + { + Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag64(0)); + Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag64(1)); + Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag64(2)); + Assert.AreEqual(-2, ParsingPrimitives.DecodeZigZag64(3)); + Assert.AreEqual(0x000000003FFFFFFFL, ParsingPrimitives.DecodeZigZag64(0x000000007FFFFFFEL)); + Assert.AreEqual(unchecked((long) 0xFFFFFFFFC0000000L), ParsingPrimitives.DecodeZigZag64(0x000000007FFFFFFFL)); + Assert.AreEqual(0x000000007FFFFFFFL, ParsingPrimitives.DecodeZigZag64(0x00000000FFFFFFFEL)); + Assert.AreEqual(unchecked((long) 0xFFFFFFFF80000000L), ParsingPrimitives.DecodeZigZag64(0x00000000FFFFFFFFL)); + Assert.AreEqual(0x7FFFFFFFFFFFFFFFL, ParsingPrimitives.DecodeZigZag64(0xFFFFFFFFFFFFFFFEL)); + Assert.AreEqual(unchecked((long) 0x8000000000000000L), ParsingPrimitives.DecodeZigZag64(0xFFFFFFFFFFFFFFFFL)); + } + + [Test] + public void ReadWholeMessage_VaryingBlockSizes() + { + TestAllTypes message = SampleMessages.CreateFullTestAllTypes(); + + byte[] rawBytes = message.ToByteArray(); + Assert.AreEqual(rawBytes.Length, message.CalculateSize()); + TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(rawBytes); + Assert.AreEqual(message, message2); + + // Try different block sizes. + for (int blockSize = 1; blockSize < 256; blockSize *= 2) + { + message2 = TestAllTypes.Parser.ParseFrom(new SmallBlockInputStream(rawBytes, blockSize)); + Assert.AreEqual(message, message2); + } + } + + [Test] + public void ReadHugeBlob() + { + // Allocate and initialize a 1MB blob. + byte[] blob = new byte[1 << 20]; + for (int i = 0; i < blob.Length; i++) + { + blob[i] = (byte) i; + } + + // Make a message containing it. + var message = new TestAllTypes { SingleBytes = ByteString.CopyFrom(blob) }; + + // Serialize and parse it. Make sure to parse from an InputStream, not + // directly from a ByteString, so that CodedInputStream uses buffered + // reading. + TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(message.ToByteString()); + + Assert.AreEqual(message, message2); + } + + [Test] + public void ReadMaliciouslyLargeBlob() + { + MemoryStream ms = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(ms); + + uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); + output.WriteRawVarint32(tag); + output.WriteRawVarint32(0x7FFFFFFF); + output.WriteRawBytes(new byte[32]); // Pad with a few random bytes. + output.Flush(); + ms.Position = 0; + + CodedInputStream input = new CodedInputStream(ms); + Assert.AreEqual(tag, input.ReadTag()); + + Assert.Throws(() => input.ReadBytes()); + } + + internal static TestRecursiveMessage MakeRecursiveMessage(int depth) + { + if (depth == 0) + { + return new TestRecursiveMessage { I = 5 }; + } + else + { + return new TestRecursiveMessage { A = MakeRecursiveMessage(depth - 1) }; + } + } + + internal static void AssertMessageDepth(TestRecursiveMessage message, int depth) + { + if (depth == 0) + { + Assert.IsNull(message.A); + Assert.AreEqual(5, message.I); + } + else + { + Assert.IsNotNull(message.A); + AssertMessageDepth(message.A, depth - 1); + } + } + + [Test] + public void MaliciousRecursion() + { + ByteString atRecursiveLimit = MakeRecursiveMessage(CodedInputStream.DefaultRecursionLimit).ToByteString(); + ByteString beyondRecursiveLimit = MakeRecursiveMessage(CodedInputStream.DefaultRecursionLimit + 1).ToByteString(); + + AssertMessageDepth(TestRecursiveMessage.Parser.ParseFrom(atRecursiveLimit), CodedInputStream.DefaultRecursionLimit); + + Assert.Throws(() => TestRecursiveMessage.Parser.ParseFrom(beyondRecursiveLimit)); + + CodedInputStream input = CodedInputStream.CreateWithLimits(new MemoryStream(atRecursiveLimit.ToByteArray()), 1000000, CodedInputStream.DefaultRecursionLimit - 1); + Assert.Throws(() => TestRecursiveMessage.Parser.ParseFrom(input)); + } + + [Test] + public void SizeLimit() + { + // Have to use a Stream rather than ByteString.CreateCodedInput as SizeLimit doesn't + // apply to the latter case. + MemoryStream ms = new MemoryStream(SampleMessages.CreateFullTestAllTypes().ToByteArray()); + CodedInputStream input = CodedInputStream.CreateWithLimits(ms, 16, 100); + Assert.Throws(() => TestAllTypes.Parser.ParseFrom(input)); + } + + /// + /// Tests that if we read an string that contains invalid UTF-8, no exception + /// is thrown. Instead, the invalid bytes are replaced with the Unicode + /// "replacement character" U+FFFD. + /// + [Test] + public void ReadInvalidUtf8() + { + MemoryStream ms = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(ms); + + uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); + output.WriteRawVarint32(tag); + output.WriteRawVarint32(1); + output.WriteRawBytes(new byte[] {0x80}); + output.Flush(); + ms.Position = 0; + + CodedInputStream input = new CodedInputStream(ms); + + Assert.AreEqual(tag, input.ReadTag()); + string text = input.ReadString(); + Assert.AreEqual('\ufffd', text[0]); + } + + /// + /// A stream which limits the number of bytes it reads at a time. + /// We use this to make sure that CodedInputStream doesn't screw up when + /// reading in small blocks. + /// + private sealed class SmallBlockInputStream : MemoryStream + { + private readonly int blockSize; + + public SmallBlockInputStream(byte[] data, int blockSize) + : base(data) + { + this.blockSize = blockSize; + } + + public override int Read(byte[] buffer, int offset, int count) + { + return base.Read(buffer, offset, Math.Min(count, blockSize)); + } + } + + [Test] + public void TestNegativeEnum() + { + byte[] bytes = { 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01 }; + CodedInputStream input = new CodedInputStream(bytes); + Assert.AreEqual((int)SampleEnum.NegativeValue, input.ReadEnum()); + Assert.IsTrue(input.IsAtEnd); + } + + //Issue 71: CodedInputStream.ReadBytes go to slow path unnecessarily + [Test] + public void TestSlowPathAvoidance() + { + using (var ms = new MemoryStream()) + { + CodedOutputStream output = new CodedOutputStream(ms); + output.WriteTag(1, WireFormat.WireType.LengthDelimited); + output.WriteBytes(ByteString.CopyFrom(new byte[100])); + output.WriteTag(2, WireFormat.WireType.LengthDelimited); + output.WriteBytes(ByteString.CopyFrom(new byte[100])); + output.Flush(); + + ms.Position = 0; + CodedInputStream input = new CodedInputStream(ms, new byte[ms.Length / 2], 0, 0, false); + + uint tag = input.ReadTag(); + Assert.AreEqual(1, WireFormat.GetTagFieldNumber(tag)); + Assert.AreEqual(100, input.ReadBytes().Length); + + tag = input.ReadTag(); + Assert.AreEqual(2, WireFormat.GetTagFieldNumber(tag)); + Assert.AreEqual(100, input.ReadBytes().Length); + } + } + + [Test] + public void Tag0Throws() + { + var input = new CodedInputStream(new byte[] { 0 }); + Assert.Throws(() => input.ReadTag()); + } + + [Test] + public void SkipGroup() + { + // Create an output stream with a group in: + // Field 1: string "field 1" + // Field 2: group containing: + // Field 1: fixed int32 value 100 + // Field 2: string "ignore me" + // Field 3: nested group containing + // Field 1: fixed int64 value 1000 + // Field 3: string "field 3" + var stream = new MemoryStream(); + var output = new CodedOutputStream(stream); + output.WriteTag(1, WireFormat.WireType.LengthDelimited); + output.WriteString("field 1"); + + // The outer group... + output.WriteTag(2, WireFormat.WireType.StartGroup); + output.WriteTag(1, WireFormat.WireType.Fixed32); + output.WriteFixed32(100); + output.WriteTag(2, WireFormat.WireType.LengthDelimited); + output.WriteString("ignore me"); + // The nested group... + output.WriteTag(3, WireFormat.WireType.StartGroup); + output.WriteTag(1, WireFormat.WireType.Fixed64); + output.WriteFixed64(1000); + // Note: Not sure the field number is relevant for end group... + output.WriteTag(3, WireFormat.WireType.EndGroup); + + // End the outer group + output.WriteTag(2, WireFormat.WireType.EndGroup); + + output.WriteTag(3, WireFormat.WireType.LengthDelimited); + output.WriteString("field 3"); + output.Flush(); + stream.Position = 0; + + // Now act like a generated client + var input = new CodedInputStream(stream); + Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited), input.ReadTag()); + Assert.AreEqual("field 1", input.ReadString()); + Assert.AreEqual(WireFormat.MakeTag(2, WireFormat.WireType.StartGroup), input.ReadTag()); + input.SkipLastField(); // Should consume the whole group, including the nested one. + Assert.AreEqual(WireFormat.MakeTag(3, WireFormat.WireType.LengthDelimited), input.ReadTag()); + Assert.AreEqual("field 3", input.ReadString()); + } + + [Test] + public void SkipGroup_WrongEndGroupTag() + { + // Create an output stream with: + // Field 1: string "field 1" + // Start group 2 + // Field 3: fixed int32 + // End group 4 (should give an error) + var stream = new MemoryStream(); + var output = new CodedOutputStream(stream); + output.WriteTag(1, WireFormat.WireType.LengthDelimited); + output.WriteString("field 1"); + + // The outer group... + output.WriteTag(2, WireFormat.WireType.StartGroup); + output.WriteTag(3, WireFormat.WireType.Fixed32); + output.WriteFixed32(100); + output.WriteTag(4, WireFormat.WireType.EndGroup); + output.Flush(); + stream.Position = 0; + + // Now act like a generated client + var input = new CodedInputStream(stream); + Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited), input.ReadTag()); + Assert.AreEqual("field 1", input.ReadString()); + Assert.AreEqual(WireFormat.MakeTag(2, WireFormat.WireType.StartGroup), input.ReadTag()); + Assert.Throws(input.SkipLastField); + } + + [Test] + public void RogueEndGroupTag() + { + // If we have an end-group tag without a leading start-group tag, generated + // code will just call SkipLastField... so that should fail. + + var stream = new MemoryStream(); + var output = new CodedOutputStream(stream); + output.WriteTag(1, WireFormat.WireType.EndGroup); + output.Flush(); + stream.Position = 0; + + var input = new CodedInputStream(stream); + Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.EndGroup), input.ReadTag()); + Assert.Throws(input.SkipLastField); + } + + [Test] + public void EndOfStreamReachedWhileSkippingGroup() + { + var stream = new MemoryStream(); + var output = new CodedOutputStream(stream); + output.WriteTag(1, WireFormat.WireType.StartGroup); + output.WriteTag(2, WireFormat.WireType.StartGroup); + output.WriteTag(2, WireFormat.WireType.EndGroup); + + output.Flush(); + stream.Position = 0; + + // Now act like a generated client + var input = new CodedInputStream(stream); + input.ReadTag(); + Assert.Throws(input.SkipLastField); + } + + [Test] + public void RecursionLimitAppliedWhileSkippingGroup() + { + var stream = new MemoryStream(); + var output = new CodedOutputStream(stream); + for (int i = 0; i < CodedInputStream.DefaultRecursionLimit + 1; i++) + { + output.WriteTag(1, WireFormat.WireType.StartGroup); + } + for (int i = 0; i < CodedInputStream.DefaultRecursionLimit + 1; i++) + { + output.WriteTag(1, WireFormat.WireType.EndGroup); + } + output.Flush(); + stream.Position = 0; + + // Now act like a generated client + var input = new CodedInputStream(stream); + Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.StartGroup), input.ReadTag()); + Assert.Throws(input.SkipLastField); + } + + [Test] + public void Construction_Invalid() + { + Assert.Throws(() => new CodedInputStream((byte[]) null)); + Assert.Throws(() => new CodedInputStream(null, 0, 0)); + Assert.Throws(() => new CodedInputStream((Stream) null)); + Assert.Throws(() => new CodedInputStream(new byte[10], 100, 0)); + Assert.Throws(() => new CodedInputStream(new byte[10], 5, 10)); + } + + [Test] + public void CreateWithLimits_InvalidLimits() + { + var stream = new MemoryStream(); + Assert.Throws(() => CodedInputStream.CreateWithLimits(stream, 0, 1)); + Assert.Throws(() => CodedInputStream.CreateWithLimits(stream, 1, 0)); + } + + [Test] + public void Dispose_DisposesUnderlyingStream() + { + var memoryStream = new MemoryStream(); + Assert.IsTrue(memoryStream.CanRead); + using (var cis = new CodedInputStream(memoryStream)) + { + } + Assert.IsFalse(memoryStream.CanRead); // Disposed + } + + [Test] + public void Dispose_WithLeaveOpen() + { + var memoryStream = new MemoryStream(); + Assert.IsTrue(memoryStream.CanRead); + using (var cis = new CodedInputStream(memoryStream, true)) + { + } + Assert.IsTrue(memoryStream.CanRead); // We left the stream open + } + } } \ No newline at end of file diff --git a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/CodedOutputStreamTest.cs b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/CodedOutputStreamTest.cs index e9b4ea8cf0f3..489041751746 100644 --- a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/CodedOutputStreamTest.cs +++ b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/CodedOutputStreamTest.cs @@ -1,419 +1,419 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.IO; -using Google.Protobuf.TestProtos; -using NUnit.Framework; - -namespace Google.Protobuf -{ - public class CodedOutputStreamTest - { - /// - /// Writes the given value using WriteRawVarint32() and WriteRawVarint64() and - /// checks that the result matches the given bytes - /// - private static void AssertWriteVarint(byte[] data, ulong value) - { - // Only do 32-bit write if the value fits in 32 bits. - if ((value >> 32) == 0) - { - MemoryStream rawOutput = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(rawOutput); - output.WriteRawVarint32((uint) value); - output.Flush(); - Assert.AreEqual(data, rawOutput.ToArray()); - // Also try computing size. - Assert.AreEqual(data.Length, CodedOutputStream.ComputeRawVarint32Size((uint) value)); - } - - { - MemoryStream rawOutput = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(rawOutput); - output.WriteRawVarint64(value); - output.Flush(); - Assert.AreEqual(data, rawOutput.ToArray()); - - // Also try computing size. - Assert.AreEqual(data.Length, CodedOutputStream.ComputeRawVarint64Size(value)); - } - - // Try different buffer sizes. - for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2) - { - // Only do 32-bit write if the value fits in 32 bits. - if ((value >> 32) == 0) - { - MemoryStream rawOutput = new MemoryStream(); - CodedOutputStream output = - new CodedOutputStream(rawOutput, bufferSize); - output.WriteRawVarint32((uint) value); - output.Flush(); - Assert.AreEqual(data, rawOutput.ToArray()); - } - - { - MemoryStream rawOutput = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(rawOutput, bufferSize); - output.WriteRawVarint64(value); - output.Flush(); - Assert.AreEqual(data, rawOutput.ToArray()); - } - } - } - - /// - /// Tests WriteRawVarint32() and WriteRawVarint64() - /// - [Test] - public void WriteVarint() - { - AssertWriteVarint(new byte[] {0x00}, 0); - AssertWriteVarint(new byte[] {0x01}, 1); - AssertWriteVarint(new byte[] {0x7f}, 127); - // 14882 - AssertWriteVarint(new byte[] {0xa2, 0x74}, (0x22 << 0) | (0x74 << 7)); - // 2961488830 - AssertWriteVarint(new byte[] {0xbe, 0xf7, 0x92, 0x84, 0x0b}, - (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | - (0x0bL << 28)); - - // 64-bit - // 7256456126 - AssertWriteVarint(new byte[] {0xbe, 0xf7, 0x92, 0x84, 0x1b}, - (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | - (0x1bL << 28)); - // 41256202580718336 - AssertWriteVarint( - new byte[] {0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49}, - (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | - (0x43UL << 28) | (0x49L << 35) | (0x24UL << 42) | (0x49UL << 49)); - // 11964378330978735131 - AssertWriteVarint( - new byte[] {0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01}, - unchecked((ulong) - ((0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | - (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) | - (0x05L << 49) | (0x26L << 56) | (0x01L << 63)))); - } - - /// - /// Parses the given bytes using WriteRawLittleEndian32() and checks - /// that the result matches the given value. - /// - private static void AssertWriteLittleEndian32(byte[] data, uint value) - { - MemoryStream rawOutput = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(rawOutput); - output.WriteRawLittleEndian32(value); - output.Flush(); - Assert.AreEqual(data, rawOutput.ToArray()); - - // Try different buffer sizes. - for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2) - { - rawOutput = new MemoryStream(); - output = new CodedOutputStream(rawOutput, bufferSize); - output.WriteRawLittleEndian32(value); - output.Flush(); - Assert.AreEqual(data, rawOutput.ToArray()); - } - } - - /// - /// Parses the given bytes using WriteRawLittleEndian64() and checks - /// that the result matches the given value. - /// - private static void AssertWriteLittleEndian64(byte[] data, ulong value) - { - MemoryStream rawOutput = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(rawOutput); - output.WriteRawLittleEndian64(value); - output.Flush(); - Assert.AreEqual(data, rawOutput.ToArray()); - - // Try different block sizes. - for (int blockSize = 1; blockSize <= 16; blockSize *= 2) - { - rawOutput = new MemoryStream(); - output = new CodedOutputStream(rawOutput, blockSize); - output.WriteRawLittleEndian64(value); - output.Flush(); - Assert.AreEqual(data, rawOutput.ToArray()); - } - } - - /// - /// Tests writeRawLittleEndian32() and writeRawLittleEndian64(). - /// - [Test] - public void WriteLittleEndian() - { - AssertWriteLittleEndian32(new byte[] {0x78, 0x56, 0x34, 0x12}, 0x12345678); - AssertWriteLittleEndian32(new byte[] {0xf0, 0xde, 0xbc, 0x9a}, 0x9abcdef0); - - AssertWriteLittleEndian64( - new byte[] {0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12}, - 0x123456789abcdef0L); - AssertWriteLittleEndian64( - new byte[] {0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a}, - 0x9abcdef012345678UL); - } - - [Test] - public void WriteWholeMessage_VaryingBlockSizes() - { - TestAllTypes message = SampleMessages.CreateFullTestAllTypes(); - - byte[] rawBytes = message.ToByteArray(); - - // Try different block sizes. - for (int blockSize = 1; blockSize < 256; blockSize *= 2) - { - MemoryStream rawOutput = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(rawOutput, blockSize); - message.WriteTo(output); - output.Flush(); - Assert.AreEqual(rawBytes, rawOutput.ToArray()); - } - } - - [Test] - public void EncodeZigZag32() - { - Assert.AreEqual(0u, WritingPrimitives.EncodeZigZag32(0)); - Assert.AreEqual(1u, WritingPrimitives.EncodeZigZag32(-1)); - Assert.AreEqual(2u, WritingPrimitives.EncodeZigZag32(1)); - Assert.AreEqual(3u, WritingPrimitives.EncodeZigZag32(-2)); - Assert.AreEqual(0x7FFFFFFEu, WritingPrimitives.EncodeZigZag32(0x3FFFFFFF)); - Assert.AreEqual(0x7FFFFFFFu, WritingPrimitives.EncodeZigZag32(unchecked((int) 0xC0000000))); - Assert.AreEqual(0xFFFFFFFEu, WritingPrimitives.EncodeZigZag32(0x7FFFFFFF)); - Assert.AreEqual(0xFFFFFFFFu, WritingPrimitives.EncodeZigZag32(unchecked((int) 0x80000000))); - } - - [Test] - public void EncodeZigZag64() - { - Assert.AreEqual(0u, WritingPrimitives.EncodeZigZag64(0)); - Assert.AreEqual(1u, WritingPrimitives.EncodeZigZag64(-1)); - Assert.AreEqual(2u, WritingPrimitives.EncodeZigZag64(1)); - Assert.AreEqual(3u, WritingPrimitives.EncodeZigZag64(-2)); - Assert.AreEqual(0x000000007FFFFFFEuL, - WritingPrimitives.EncodeZigZag64(unchecked((long) 0x000000003FFFFFFFUL))); - Assert.AreEqual(0x000000007FFFFFFFuL, - WritingPrimitives.EncodeZigZag64(unchecked((long) 0xFFFFFFFFC0000000UL))); - Assert.AreEqual(0x00000000FFFFFFFEuL, - WritingPrimitives.EncodeZigZag64(unchecked((long) 0x000000007FFFFFFFUL))); - Assert.AreEqual(0x00000000FFFFFFFFuL, - WritingPrimitives.EncodeZigZag64(unchecked((long) 0xFFFFFFFF80000000UL))); - Assert.AreEqual(0xFFFFFFFFFFFFFFFEL, - WritingPrimitives.EncodeZigZag64(unchecked((long) 0x7FFFFFFFFFFFFFFFUL))); - Assert.AreEqual(0xFFFFFFFFFFFFFFFFL, - WritingPrimitives.EncodeZigZag64(unchecked((long) 0x8000000000000000UL))); - } - - [Test] - public void RoundTripZigZag32() - { - // Some easier-to-verify round-trip tests. The inputs (other than 0, 1, -1) - // were chosen semi-randomly via keyboard bashing. - Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(0))); - Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(1))); - Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(-1))); - Assert.AreEqual(14927, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(14927))); - Assert.AreEqual(-3612, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(-3612))); - } - - [Test] - public void RoundTripZigZag64() - { - Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(0))); - Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(1))); - Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-1))); - Assert.AreEqual(14927, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(14927))); - Assert.AreEqual(-3612, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-3612))); - - Assert.AreEqual(856912304801416L, - ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(856912304801416L))); - Assert.AreEqual(-75123905439571256L, - ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-75123905439571256L))); - } - - [Test] - public void TestNegativeEnumNoTag() - { - Assert.AreEqual(10, CodedOutputStream.ComputeInt32Size(-2)); - Assert.AreEqual(10, CodedOutputStream.ComputeEnumSize((int) SampleEnum.NegativeValue)); - - byte[] bytes = new byte[10]; - CodedOutputStream output = new CodedOutputStream(bytes); - output.WriteEnum((int) SampleEnum.NegativeValue); - - Assert.AreEqual(0, output.SpaceLeft); - Assert.AreEqual("FE-FF-FF-FF-FF-FF-FF-FF-FF-01", BitConverter.ToString(bytes)); - } - - [Test] - public void TestCodedInputOutputPosition() - { - byte[] content = new byte[110]; - for (int i = 0; i < content.Length; i++) - content[i] = (byte)i; - - byte[] child = new byte[120]; - { - MemoryStream ms = new MemoryStream(child); - CodedOutputStream cout = new CodedOutputStream(ms, 20); - // Field 11: numeric value: 500 - cout.WriteTag(11, WireFormat.WireType.Varint); - Assert.AreEqual(1, cout.Position); - cout.WriteInt32(500); - Assert.AreEqual(3, cout.Position); - //Field 12: length delimited 120 bytes - cout.WriteTag(12, WireFormat.WireType.LengthDelimited); - Assert.AreEqual(4, cout.Position); - cout.WriteBytes(ByteString.CopyFrom(content)); - Assert.AreEqual(115, cout.Position); - // Field 13: fixed numeric value: 501 - cout.WriteTag(13, WireFormat.WireType.Fixed32); - Assert.AreEqual(116, cout.Position); - cout.WriteSFixed32(501); - Assert.AreEqual(120, cout.Position); - cout.Flush(); - } - - byte[] bytes = new byte[130]; - { - CodedOutputStream cout = new CodedOutputStream(bytes); - // Field 1: numeric value: 500 - cout.WriteTag(1, WireFormat.WireType.Varint); - Assert.AreEqual(1, cout.Position); - cout.WriteInt32(500); - Assert.AreEqual(3, cout.Position); - //Field 2: length delimited 120 bytes - cout.WriteTag(2, WireFormat.WireType.LengthDelimited); - Assert.AreEqual(4, cout.Position); - cout.WriteBytes(ByteString.CopyFrom(child)); - Assert.AreEqual(125, cout.Position); - // Field 3: fixed numeric value: 500 - cout.WriteTag(3, WireFormat.WireType.Fixed32); - Assert.AreEqual(126, cout.Position); - cout.WriteSFixed32(501); - Assert.AreEqual(130, cout.Position); - cout.Flush(); - } - // Now test Input stream: - { - CodedInputStream cin = new CodedInputStream(new MemoryStream(bytes), new byte[50], 0, 0, false); - Assert.AreEqual(0, cin.Position); - // Field 1: - uint tag = cin.ReadTag(); - Assert.AreEqual(1, tag >> 3); - Assert.AreEqual(1, cin.Position); - Assert.AreEqual(500, cin.ReadInt32()); - Assert.AreEqual(3, cin.Position); - //Field 2: - tag = cin.ReadTag(); - Assert.AreEqual(2, tag >> 3); - Assert.AreEqual(4, cin.Position); - int childlen = cin.ReadLength(); - Assert.AreEqual(120, childlen); - Assert.AreEqual(5, cin.Position); - int oldlimit = cin.PushLimit((int)childlen); - Assert.AreEqual(5, cin.Position); - // Now we are reading child message - { - // Field 11: numeric value: 500 - tag = cin.ReadTag(); - Assert.AreEqual(11, tag >> 3); - Assert.AreEqual(6, cin.Position); - Assert.AreEqual(500, cin.ReadInt32()); - Assert.AreEqual(8, cin.Position); - //Field 12: length delimited 120 bytes - tag = cin.ReadTag(); - Assert.AreEqual(12, tag >> 3); - Assert.AreEqual(9, cin.Position); - ByteString bstr = cin.ReadBytes(); - Assert.AreEqual(110, bstr.Length); - Assert.AreEqual((byte) 109, bstr[109]); - Assert.AreEqual(120, cin.Position); - // Field 13: fixed numeric value: 501 - tag = cin.ReadTag(); - Assert.AreEqual(13, tag >> 3); - // ROK - Previously broken here, this returned 126 failing to account for bufferSizeAfterLimit - Assert.AreEqual(121, cin.Position); - Assert.AreEqual(501, cin.ReadSFixed32()); - Assert.AreEqual(125, cin.Position); - Assert.IsTrue(cin.IsAtEnd); - } - cin.PopLimit(oldlimit); - Assert.AreEqual(125, cin.Position); - // Field 3: fixed numeric value: 501 - tag = cin.ReadTag(); - Assert.AreEqual(3, tag >> 3); - Assert.AreEqual(126, cin.Position); - Assert.AreEqual(501, cin.ReadSFixed32()); - Assert.AreEqual(130, cin.Position); - Assert.IsTrue(cin.IsAtEnd); - } - } - - [Test] - public void Dispose_DisposesUnderlyingStream() - { - var memoryStream = new MemoryStream(); - Assert.IsTrue(memoryStream.CanWrite); - using (var cos = new CodedOutputStream(memoryStream)) - { - cos.WriteRawBytes(new byte[] {0}); - Assert.AreEqual(0, memoryStream.Position); // Not flushed yet - } - Assert.AreEqual(1, memoryStream.ToArray().Length); // Flushed data from CodedOutputStream to MemoryStream - Assert.IsFalse(memoryStream.CanWrite); // Disposed - } - - [Test] - public void Dispose_WithLeaveOpen() - { - var memoryStream = new MemoryStream(); - Assert.IsTrue(memoryStream.CanWrite); - using (var cos = new CodedOutputStream(memoryStream, true)) - { - cos.WriteRawBytes(new byte[] {0}); - Assert.AreEqual(0, memoryStream.Position); // Not flushed yet - } - Assert.AreEqual(1, memoryStream.Position); // Flushed data from CodedOutputStream to MemoryStream - Assert.IsTrue(memoryStream.CanWrite); // We left the stream open - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.IO; +using Google.Protobuf.TestProtos; +using NUnit.Framework; + +namespace Google.Protobuf +{ + public class CodedOutputStreamTest + { + /// + /// Writes the given value using WriteRawVarint32() and WriteRawVarint64() and + /// checks that the result matches the given bytes + /// + private static void AssertWriteVarint(byte[] data, ulong value) + { + // Only do 32-bit write if the value fits in 32 bits. + if ((value >> 32) == 0) + { + MemoryStream rawOutput = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(rawOutput); + output.WriteRawVarint32((uint) value); + output.Flush(); + Assert.AreEqual(data, rawOutput.ToArray()); + // Also try computing size. + Assert.AreEqual(data.Length, CodedOutputStream.ComputeRawVarint32Size((uint) value)); + } + + { + MemoryStream rawOutput = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(rawOutput); + output.WriteRawVarint64(value); + output.Flush(); + Assert.AreEqual(data, rawOutput.ToArray()); + + // Also try computing size. + Assert.AreEqual(data.Length, CodedOutputStream.ComputeRawVarint64Size(value)); + } + + // Try different buffer sizes. + for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2) + { + // Only do 32-bit write if the value fits in 32 bits. + if ((value >> 32) == 0) + { + MemoryStream rawOutput = new MemoryStream(); + CodedOutputStream output = + new CodedOutputStream(rawOutput, bufferSize); + output.WriteRawVarint32((uint) value); + output.Flush(); + Assert.AreEqual(data, rawOutput.ToArray()); + } + + { + MemoryStream rawOutput = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(rawOutput, bufferSize); + output.WriteRawVarint64(value); + output.Flush(); + Assert.AreEqual(data, rawOutput.ToArray()); + } + } + } + + /// + /// Tests WriteRawVarint32() and WriteRawVarint64() + /// + [Test] + public void WriteVarint() + { + AssertWriteVarint(new byte[] {0x00}, 0); + AssertWriteVarint(new byte[] {0x01}, 1); + AssertWriteVarint(new byte[] {0x7f}, 127); + // 14882 + AssertWriteVarint(new byte[] {0xa2, 0x74}, (0x22 << 0) | (0x74 << 7)); + // 2961488830 + AssertWriteVarint(new byte[] {0xbe, 0xf7, 0x92, 0x84, 0x0b}, + (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | + (0x0bL << 28)); + + // 64-bit + // 7256456126 + AssertWriteVarint(new byte[] {0xbe, 0xf7, 0x92, 0x84, 0x1b}, + (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | + (0x1bL << 28)); + // 41256202580718336 + AssertWriteVarint( + new byte[] {0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49}, + (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | + (0x43UL << 28) | (0x49L << 35) | (0x24UL << 42) | (0x49UL << 49)); + // 11964378330978735131 + AssertWriteVarint( + new byte[] {0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01}, + unchecked((ulong) + ((0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | + (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) | + (0x05L << 49) | (0x26L << 56) | (0x01L << 63)))); + } + + /// + /// Parses the given bytes using WriteRawLittleEndian32() and checks + /// that the result matches the given value. + /// + private static void AssertWriteLittleEndian32(byte[] data, uint value) + { + MemoryStream rawOutput = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(rawOutput); + output.WriteRawLittleEndian32(value); + output.Flush(); + Assert.AreEqual(data, rawOutput.ToArray()); + + // Try different buffer sizes. + for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2) + { + rawOutput = new MemoryStream(); + output = new CodedOutputStream(rawOutput, bufferSize); + output.WriteRawLittleEndian32(value); + output.Flush(); + Assert.AreEqual(data, rawOutput.ToArray()); + } + } + + /// + /// Parses the given bytes using WriteRawLittleEndian64() and checks + /// that the result matches the given value. + /// + private static void AssertWriteLittleEndian64(byte[] data, ulong value) + { + MemoryStream rawOutput = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(rawOutput); + output.WriteRawLittleEndian64(value); + output.Flush(); + Assert.AreEqual(data, rawOutput.ToArray()); + + // Try different block sizes. + for (int blockSize = 1; blockSize <= 16; blockSize *= 2) + { + rawOutput = new MemoryStream(); + output = new CodedOutputStream(rawOutput, blockSize); + output.WriteRawLittleEndian64(value); + output.Flush(); + Assert.AreEqual(data, rawOutput.ToArray()); + } + } + + /// + /// Tests writeRawLittleEndian32() and writeRawLittleEndian64(). + /// + [Test] + public void WriteLittleEndian() + { + AssertWriteLittleEndian32(new byte[] {0x78, 0x56, 0x34, 0x12}, 0x12345678); + AssertWriteLittleEndian32(new byte[] {0xf0, 0xde, 0xbc, 0x9a}, 0x9abcdef0); + + AssertWriteLittleEndian64( + new byte[] {0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12}, + 0x123456789abcdef0L); + AssertWriteLittleEndian64( + new byte[] {0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a}, + 0x9abcdef012345678UL); + } + + [Test] + public void WriteWholeMessage_VaryingBlockSizes() + { + TestAllTypes message = SampleMessages.CreateFullTestAllTypes(); + + byte[] rawBytes = message.ToByteArray(); + + // Try different block sizes. + for (int blockSize = 1; blockSize < 256; blockSize *= 2) + { + MemoryStream rawOutput = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(rawOutput, blockSize); + message.WriteTo(output); + output.Flush(); + Assert.AreEqual(rawBytes, rawOutput.ToArray()); + } + } + + [Test] + public void EncodeZigZag32() + { + Assert.AreEqual(0u, WritingPrimitives.EncodeZigZag32(0)); + Assert.AreEqual(1u, WritingPrimitives.EncodeZigZag32(-1)); + Assert.AreEqual(2u, WritingPrimitives.EncodeZigZag32(1)); + Assert.AreEqual(3u, WritingPrimitives.EncodeZigZag32(-2)); + Assert.AreEqual(0x7FFFFFFEu, WritingPrimitives.EncodeZigZag32(0x3FFFFFFF)); + Assert.AreEqual(0x7FFFFFFFu, WritingPrimitives.EncodeZigZag32(unchecked((int) 0xC0000000))); + Assert.AreEqual(0xFFFFFFFEu, WritingPrimitives.EncodeZigZag32(0x7FFFFFFF)); + Assert.AreEqual(0xFFFFFFFFu, WritingPrimitives.EncodeZigZag32(unchecked((int) 0x80000000))); + } + + [Test] + public void EncodeZigZag64() + { + Assert.AreEqual(0u, WritingPrimitives.EncodeZigZag64(0)); + Assert.AreEqual(1u, WritingPrimitives.EncodeZigZag64(-1)); + Assert.AreEqual(2u, WritingPrimitives.EncodeZigZag64(1)); + Assert.AreEqual(3u, WritingPrimitives.EncodeZigZag64(-2)); + Assert.AreEqual(0x000000007FFFFFFEuL, + WritingPrimitives.EncodeZigZag64(unchecked((long) 0x000000003FFFFFFFUL))); + Assert.AreEqual(0x000000007FFFFFFFuL, + WritingPrimitives.EncodeZigZag64(unchecked((long) 0xFFFFFFFFC0000000UL))); + Assert.AreEqual(0x00000000FFFFFFFEuL, + WritingPrimitives.EncodeZigZag64(unchecked((long) 0x000000007FFFFFFFUL))); + Assert.AreEqual(0x00000000FFFFFFFFuL, + WritingPrimitives.EncodeZigZag64(unchecked((long) 0xFFFFFFFF80000000UL))); + Assert.AreEqual(0xFFFFFFFFFFFFFFFEL, + WritingPrimitives.EncodeZigZag64(unchecked((long) 0x7FFFFFFFFFFFFFFFUL))); + Assert.AreEqual(0xFFFFFFFFFFFFFFFFL, + WritingPrimitives.EncodeZigZag64(unchecked((long) 0x8000000000000000UL))); + } + + [Test] + public void RoundTripZigZag32() + { + // Some easier-to-verify round-trip tests. The inputs (other than 0, 1, -1) + // were chosen semi-randomly via keyboard bashing. + Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(0))); + Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(1))); + Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(-1))); + Assert.AreEqual(14927, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(14927))); + Assert.AreEqual(-3612, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(-3612))); + } + + [Test] + public void RoundTripZigZag64() + { + Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(0))); + Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(1))); + Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-1))); + Assert.AreEqual(14927, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(14927))); + Assert.AreEqual(-3612, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-3612))); + + Assert.AreEqual(856912304801416L, + ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(856912304801416L))); + Assert.AreEqual(-75123905439571256L, + ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-75123905439571256L))); + } + + [Test] + public void TestNegativeEnumNoTag() + { + Assert.AreEqual(10, CodedOutputStream.ComputeInt32Size(-2)); + Assert.AreEqual(10, CodedOutputStream.ComputeEnumSize((int) SampleEnum.NegativeValue)); + + byte[] bytes = new byte[10]; + CodedOutputStream output = new CodedOutputStream(bytes); + output.WriteEnum((int) SampleEnum.NegativeValue); + + Assert.AreEqual(0, output.SpaceLeft); + Assert.AreEqual("FE-FF-FF-FF-FF-FF-FF-FF-FF-01", BitConverter.ToString(bytes)); + } + + [Test] + public void TestCodedInputOutputPosition() + { + byte[] content = new byte[110]; + for (int i = 0; i < content.Length; i++) + content[i] = (byte)i; + + byte[] child = new byte[120]; + { + MemoryStream ms = new MemoryStream(child); + CodedOutputStream cout = new CodedOutputStream(ms, 20); + // Field 11: numeric value: 500 + cout.WriteTag(11, WireFormat.WireType.Varint); + Assert.AreEqual(1, cout.Position); + cout.WriteInt32(500); + Assert.AreEqual(3, cout.Position); + //Field 12: length delimited 120 bytes + cout.WriteTag(12, WireFormat.WireType.LengthDelimited); + Assert.AreEqual(4, cout.Position); + cout.WriteBytes(ByteString.CopyFrom(content)); + Assert.AreEqual(115, cout.Position); + // Field 13: fixed numeric value: 501 + cout.WriteTag(13, WireFormat.WireType.Fixed32); + Assert.AreEqual(116, cout.Position); + cout.WriteSFixed32(501); + Assert.AreEqual(120, cout.Position); + cout.Flush(); + } + + byte[] bytes = new byte[130]; + { + CodedOutputStream cout = new CodedOutputStream(bytes); + // Field 1: numeric value: 500 + cout.WriteTag(1, WireFormat.WireType.Varint); + Assert.AreEqual(1, cout.Position); + cout.WriteInt32(500); + Assert.AreEqual(3, cout.Position); + //Field 2: length delimited 120 bytes + cout.WriteTag(2, WireFormat.WireType.LengthDelimited); + Assert.AreEqual(4, cout.Position); + cout.WriteBytes(ByteString.CopyFrom(child)); + Assert.AreEqual(125, cout.Position); + // Field 3: fixed numeric value: 500 + cout.WriteTag(3, WireFormat.WireType.Fixed32); + Assert.AreEqual(126, cout.Position); + cout.WriteSFixed32(501); + Assert.AreEqual(130, cout.Position); + cout.Flush(); + } + // Now test Input stream: + { + CodedInputStream cin = new CodedInputStream(new MemoryStream(bytes), new byte[50], 0, 0, false); + Assert.AreEqual(0, cin.Position); + // Field 1: + uint tag = cin.ReadTag(); + Assert.AreEqual(1, tag >> 3); + Assert.AreEqual(1, cin.Position); + Assert.AreEqual(500, cin.ReadInt32()); + Assert.AreEqual(3, cin.Position); + //Field 2: + tag = cin.ReadTag(); + Assert.AreEqual(2, tag >> 3); + Assert.AreEqual(4, cin.Position); + int childlen = cin.ReadLength(); + Assert.AreEqual(120, childlen); + Assert.AreEqual(5, cin.Position); + int oldlimit = cin.PushLimit((int)childlen); + Assert.AreEqual(5, cin.Position); + // Now we are reading child message + { + // Field 11: numeric value: 500 + tag = cin.ReadTag(); + Assert.AreEqual(11, tag >> 3); + Assert.AreEqual(6, cin.Position); + Assert.AreEqual(500, cin.ReadInt32()); + Assert.AreEqual(8, cin.Position); + //Field 12: length delimited 120 bytes + tag = cin.ReadTag(); + Assert.AreEqual(12, tag >> 3); + Assert.AreEqual(9, cin.Position); + ByteString bstr = cin.ReadBytes(); + Assert.AreEqual(110, bstr.Length); + Assert.AreEqual((byte) 109, bstr[109]); + Assert.AreEqual(120, cin.Position); + // Field 13: fixed numeric value: 501 + tag = cin.ReadTag(); + Assert.AreEqual(13, tag >> 3); + // ROK - Previously broken here, this returned 126 failing to account for bufferSizeAfterLimit + Assert.AreEqual(121, cin.Position); + Assert.AreEqual(501, cin.ReadSFixed32()); + Assert.AreEqual(125, cin.Position); + Assert.IsTrue(cin.IsAtEnd); + } + cin.PopLimit(oldlimit); + Assert.AreEqual(125, cin.Position); + // Field 3: fixed numeric value: 501 + tag = cin.ReadTag(); + Assert.AreEqual(3, tag >> 3); + Assert.AreEqual(126, cin.Position); + Assert.AreEqual(501, cin.ReadSFixed32()); + Assert.AreEqual(130, cin.Position); + Assert.IsTrue(cin.IsAtEnd); + } + } + + [Test] + public void Dispose_DisposesUnderlyingStream() + { + var memoryStream = new MemoryStream(); + Assert.IsTrue(memoryStream.CanWrite); + using (var cos = new CodedOutputStream(memoryStream)) + { + cos.WriteRawBytes(new byte[] {0}); + Assert.AreEqual(0, memoryStream.Position); // Not flushed yet + } + Assert.AreEqual(1, memoryStream.ToArray().Length); // Flushed data from CodedOutputStream to MemoryStream + Assert.IsFalse(memoryStream.CanWrite); // Disposed + } + + [Test] + public void Dispose_WithLeaveOpen() + { + var memoryStream = new MemoryStream(); + Assert.IsTrue(memoryStream.CanWrite); + using (var cos = new CodedOutputStream(memoryStream, true)) + { + cos.WriteRawBytes(new byte[] {0}); + Assert.AreEqual(0, memoryStream.Position); // Not flushed yet + } + Assert.AreEqual(1, memoryStream.Position); // Flushed data from CodedOutputStream to MemoryStream + Assert.IsTrue(memoryStream.CanWrite); // We left the stream open + } + } } \ No newline at end of file diff --git a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/DeprecatedMemberTest.cs b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/DeprecatedMemberTest.cs index 34d5b9f98cbb..fd041e01716d 100644 --- a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/DeprecatedMemberTest.cs +++ b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/DeprecatedMemberTest.cs @@ -1,55 +1,55 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2015 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.Reflection; -using Google.Protobuf.TestProtos; -using NUnit.Framework; - -namespace Google.Protobuf -{ - public class DeprecatedMemberTest - { - private static void AssertIsDeprecated(MemberInfo member) - { - Assert.NotNull(member); - Assert.IsTrue(member.IsDefined(typeof(ObsoleteAttribute), false), "Member not obsolete: " + member); - } - - [Test] - public void TestDepreatedPrimitiveValue() - { - AssertIsDeprecated(typeof(TestDeprecatedFields).GetProperty("DeprecatedInt32")); - } - - } -} +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.Reflection; +using Google.Protobuf.TestProtos; +using NUnit.Framework; + +namespace Google.Protobuf +{ + public class DeprecatedMemberTest + { + private static void AssertIsDeprecated(MemberInfo member) + { + Assert.NotNull(member); + Assert.IsTrue(member.IsDefined(typeof(ObsoleteAttribute), false), "Member not obsolete: " + member); + } + + [Test] + public void TestDepreatedPrimitiveValue() + { + AssertIsDeprecated(typeof(TestDeprecatedFields).GetProperty("DeprecatedInt32")); + } + + } +} diff --git a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/GeneratedMessageTest.cs b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/GeneratedMessageTest.cs index 429c51ff91d3..61f3abb46a5a 100644 --- a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/GeneratedMessageTest.cs +++ b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/GeneratedMessageTest.cs @@ -1,725 +1,725 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2015 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.IO; -using Google.Protobuf.TestProtos; -using NUnit.Framework; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Google.Protobuf.WellKnownTypes; - -namespace Google.Protobuf -{ - /// - /// Tests around the generated TestAllTypes message. - /// - public class GeneratedMessageTest - { - [Test] - public void EmptyMessageFieldDistinctFromMissingMessageField() - { - // This demonstrates what we're really interested in... - var message1 = new TestAllTypes { SingleForeignMessage = new ForeignMessage() }; - var message2 = new TestAllTypes(); // SingleForeignMessage is null - EqualityTester.AssertInequality(message1, message2); - } - - [Test] - public void DefaultValues() - { - // Single fields - var message = new TestAllTypes(); - Assert.AreEqual(false, message.SingleBool); - Assert.AreEqual(ByteString.Empty, message.SingleBytes); - Assert.AreEqual(0.0, message.SingleDouble); - Assert.AreEqual(0, message.SingleFixed32); - Assert.AreEqual(0L, message.SingleFixed64); - Assert.AreEqual(0.0f, message.SingleFloat); - Assert.AreEqual(ForeignEnum.ForeignUnspecified, message.SingleForeignEnum); - Assert.IsNull(message.SingleForeignMessage); - Assert.AreEqual(ImportEnum.Unspecified, message.SingleImportEnum); - Assert.IsNull(message.SingleImportMessage); - Assert.AreEqual(0, message.SingleInt32); - Assert.AreEqual(0L, message.SingleInt64); - Assert.AreEqual(TestAllTypes.Types.NestedEnum.Unspecified, message.SingleNestedEnum); - Assert.IsNull(message.SingleNestedMessage); - Assert.IsNull(message.SinglePublicImportMessage); - Assert.AreEqual(0, message.SingleSfixed32); - Assert.AreEqual(0L, message.SingleSfixed64); - Assert.AreEqual(0, message.SingleSint32); - Assert.AreEqual(0L, message.SingleSint64); - Assert.AreEqual("", message.SingleString); - Assert.AreEqual(0U, message.SingleUint32); - Assert.AreEqual(0UL, message.SingleUint64); - - // Repeated fields - Assert.AreEqual(0, message.RepeatedBool.Count); - Assert.AreEqual(0, message.RepeatedBytes.Count); - Assert.AreEqual(0, message.RepeatedDouble.Count); - Assert.AreEqual(0, message.RepeatedFixed32.Count); - Assert.AreEqual(0, message.RepeatedFixed64.Count); - Assert.AreEqual(0, message.RepeatedFloat.Count); - Assert.AreEqual(0, message.RepeatedForeignEnum.Count); - Assert.AreEqual(0, message.RepeatedForeignMessage.Count); - Assert.AreEqual(0, message.RepeatedImportEnum.Count); - Assert.AreEqual(0, message.RepeatedImportMessage.Count); - Assert.AreEqual(0, message.RepeatedNestedEnum.Count); - Assert.AreEqual(0, message.RepeatedNestedMessage.Count); - Assert.AreEqual(0, message.RepeatedPublicImportMessage.Count); - Assert.AreEqual(0, message.RepeatedSfixed32.Count); - Assert.AreEqual(0, message.RepeatedSfixed64.Count); - Assert.AreEqual(0, message.RepeatedSint32.Count); - Assert.AreEqual(0, message.RepeatedSint64.Count); - Assert.AreEqual(0, message.RepeatedString.Count); - Assert.AreEqual(0, message.RepeatedUint32.Count); - Assert.AreEqual(0, message.RepeatedUint64.Count); - - // Oneof fields - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); - Assert.AreEqual(0, message.OneofUint32); - Assert.AreEqual("", message.OneofString); - Assert.AreEqual(ByteString.Empty, message.OneofBytes); - Assert.IsNull(message.OneofNestedMessage); - } - - [Test] - public void NullStringAndBytesRejected() - { - var message = new TestAllTypes(); - Assert.Throws(() => message.SingleString = null); - Assert.Throws(() => message.OneofString = null); - Assert.Throws(() => message.SingleBytes = null); - Assert.Throws(() => message.OneofBytes = null); - } - - [Test] - public void RoundTrip_Empty() - { - var message = new TestAllTypes(); - // Without setting any values, there's nothing to write. - byte[] bytes = message.ToByteArray(); - Assert.AreEqual(0, bytes.Length); - TestAllTypes parsed = TestAllTypes.Parser.ParseFrom(bytes); - Assert.AreEqual(message, parsed); - } - - [Test] - public void RoundTrip_SingleValues() - { - var message = new TestAllTypes - { - SingleBool = true, - SingleBytes = ByteString.CopyFrom(1, 2, 3, 4), - SingleDouble = 23.5, - SingleFixed32 = 23, - SingleFixed64 = 1234567890123, - SingleFloat = 12.25f, - SingleForeignEnum = ForeignEnum.ForeignBar, - SingleForeignMessage = new ForeignMessage { C = 10 }, - SingleImportEnum = ImportEnum.ImportBaz, - SingleImportMessage = new ImportMessage { D = 20 }, - SingleInt32 = 100, - SingleInt64 = 3210987654321, - SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, - SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 }, - SinglePublicImportMessage = new PublicImportMessage { E = 54 }, - SingleSfixed32 = -123, - SingleSfixed64 = -12345678901234, - SingleSint32 = -456, - SingleSint64 = -12345678901235, - SingleString = "test", - SingleUint32 = uint.MaxValue, - SingleUint64 = ulong.MaxValue - }; - - byte[] bytes = message.ToByteArray(); - TestAllTypes parsed = TestAllTypes.Parser.ParseFrom(bytes); - Assert.AreEqual(message, parsed); - } - - [Test] - public void RoundTrip_RepeatedValues() - { - var message = new TestAllTypes - { - RepeatedBool = { true, false }, - RepeatedBytes = { ByteString.CopyFrom(1, 2, 3, 4), ByteString.CopyFrom(5, 6) }, - RepeatedDouble = { -12.25, 23.5 }, - RepeatedFixed32 = { uint.MaxValue, 23 }, - RepeatedFixed64 = { ulong.MaxValue, 1234567890123 }, - RepeatedFloat = { 100f, 12.25f }, - RepeatedForeignEnum = { ForeignEnum.ForeignFoo, ForeignEnum.ForeignBar }, - RepeatedForeignMessage = { new ForeignMessage(), new ForeignMessage { C = 10 } }, - RepeatedImportEnum = { ImportEnum.ImportBaz, ImportEnum.Unspecified }, - RepeatedImportMessage = { new ImportMessage { D = 20 }, new ImportMessage { D = 25 } }, - RepeatedInt32 = { 100, 200 }, - RepeatedInt64 = { 3210987654321, long.MaxValue }, - RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg }, - RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 35 }, new TestAllTypes.Types.NestedMessage { Bb = 10 } }, - RepeatedPublicImportMessage = { new PublicImportMessage { E = 54 }, new PublicImportMessage { E = -1 } }, - RepeatedSfixed32 = { -123, 123 }, - RepeatedSfixed64 = { -12345678901234, 12345678901234 }, - RepeatedSint32 = { -456, 100 }, - RepeatedSint64 = { -12345678901235, 123 }, - RepeatedString = { "foo", "bar" }, - RepeatedUint32 = { uint.MaxValue, uint.MinValue }, - RepeatedUint64 = { ulong.MaxValue, uint.MinValue } - }; - - byte[] bytes = message.ToByteArray(); - TestAllTypes parsed = TestAllTypes.Parser.ParseFrom(bytes); - Assert.AreEqual(message, parsed); - } - - // Note that not every map within map_unittest_proto3 is used. They all go through very - // similar code paths. The fact that all maps are present is validation that we have codecs - // for every type. - [Test] - public void RoundTrip_Maps() - { - var message = new TestMap - { - MapBoolBool = { - { false, true }, - { true, false } - }, - MapInt32Bytes = { - { 5, ByteString.CopyFrom(6, 7, 8) }, - { 25, ByteString.CopyFrom(1, 2, 3, 4, 5) }, - { 10, ByteString.Empty } - }, - MapInt32ForeignMessage = { - { 0, new ForeignMessage { C = 10 } }, - { 5, new ForeignMessage() }, - }, - MapInt32Enum = { - { 1, MapEnum.Bar }, - { 2000, MapEnum.Foo } - } - }; - - byte[] bytes = message.ToByteArray(); - TestMap parsed = TestMap.Parser.ParseFrom(bytes); - Assert.AreEqual(message, parsed); - } - - [Test] - public void MapWithEmptyEntry() - { - var message = new TestMap - { - MapInt32Bytes = { { 0, ByteString.Empty } } - }; - - byte[] bytes = message.ToByteArray(); - Assert.AreEqual(2, bytes.Length); // Tag for field entry (1 byte), length of entry (0; 1 byte) - - var parsed = TestMap.Parser.ParseFrom(bytes); - Assert.AreEqual(1, parsed.MapInt32Bytes.Count); - Assert.AreEqual(ByteString.Empty, parsed.MapInt32Bytes[0]); - } - - [Test] - public void MapWithOnlyValue() - { - // Hand-craft the stream to contain a single entry with just a value. - var memoryStream = new MemoryStream(); - var output = new CodedOutputStream(memoryStream); - output.WriteTag(TestMap.MapInt32ForeignMessageFieldNumber, WireFormat.WireType.LengthDelimited); - var nestedMessage = new ForeignMessage { C = 20 }; - // Size of the entry (tag, size written by WriteMessage, data written by WriteMessage) - output.WriteLength(2 + nestedMessage.CalculateSize()); - output.WriteTag(2, WireFormat.WireType.LengthDelimited); - output.WriteMessage(nestedMessage); - output.Flush(); - - var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray()); - Assert.AreEqual(nestedMessage, parsed.MapInt32ForeignMessage[0]); - } - - [Test] - public void MapWithOnlyKey_PrimitiveValue() - { - // Hand-craft the stream to contain a single entry with just a key. - var memoryStream = new MemoryStream(); - var output = new CodedOutputStream(memoryStream); - output.WriteTag(TestMap.MapInt32DoubleFieldNumber, WireFormat.WireType.LengthDelimited); - int key = 10; - output.WriteLength(1 + CodedOutputStream.ComputeInt32Size(key)); - output.WriteTag(1, WireFormat.WireType.Varint); - output.WriteInt32(key); - output.Flush(); - - var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray()); - Assert.AreEqual(0.0, parsed.MapInt32Double[key]); - } - - [Test] - public void MapWithOnlyKey_MessageValue() - { - // Hand-craft the stream to contain a single entry with just a key. - var memoryStream = new MemoryStream(); - var output = new CodedOutputStream(memoryStream); - output.WriteTag(TestMap.MapInt32ForeignMessageFieldNumber, WireFormat.WireType.LengthDelimited); - int key = 10; - output.WriteLength(1 + CodedOutputStream.ComputeInt32Size(key)); - output.WriteTag(1, WireFormat.WireType.Varint); - output.WriteInt32(key); - output.Flush(); - - var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray()); - Assert.AreEqual(new ForeignMessage(), parsed.MapInt32ForeignMessage[key]); - } - - [Test] - public void MapIgnoresExtraFieldsWithinEntryMessages() - { - // Hand-craft the stream to contain a single entry with three fields - var memoryStream = new MemoryStream(); - var output = new CodedOutputStream(memoryStream); - - output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); - - var key = 10; // Field 1 - var value = 20; // Field 2 - var extra = 30; // Field 3 - - // Each field can be represented in a single byte, with a single byte tag. - // Total message size: 6 bytes. - output.WriteLength(6); - output.WriteTag(1, WireFormat.WireType.Varint); - output.WriteInt32(key); - output.WriteTag(2, WireFormat.WireType.Varint); - output.WriteInt32(value); - output.WriteTag(3, WireFormat.WireType.Varint); - output.WriteInt32(extra); - output.Flush(); - - var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray()); - Assert.AreEqual(value, parsed.MapInt32Int32[key]); - } - - [Test] - public void MapFieldOrderIsIrrelevant() - { - var memoryStream = new MemoryStream(); - var output = new CodedOutputStream(memoryStream); - - output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); - - var key = 10; - var value = 20; - - // Each field can be represented in a single byte, with a single byte tag. - // Total message size: 4 bytes. - output.WriteLength(4); - output.WriteTag(2, WireFormat.WireType.Varint); - output.WriteInt32(value); - output.WriteTag(1, WireFormat.WireType.Varint); - output.WriteInt32(key); - output.Flush(); - - var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray()); - Assert.AreEqual(value, parsed.MapInt32Int32[key]); - } - - [Test] - public void MapNonContiguousEntries() - { - var memoryStream = new MemoryStream(); - var output = new CodedOutputStream(memoryStream); - - // Message structure: - // Entry for MapInt32Int32 - // Entry for MapStringString - // Entry for MapInt32Int32 - - // First entry - var key1 = 10; - var value1 = 20; - output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); - output.WriteLength(4); - output.WriteTag(1, WireFormat.WireType.Varint); - output.WriteInt32(key1); - output.WriteTag(2, WireFormat.WireType.Varint); - output.WriteInt32(value1); - - // Second entry - var key2 = "a"; - var value2 = "b"; - output.WriteTag(TestMap.MapStringStringFieldNumber, WireFormat.WireType.LengthDelimited); - output.WriteLength(6); // 3 bytes per entry: tag, size, character - output.WriteTag(1, WireFormat.WireType.LengthDelimited); - output.WriteString(key2); - output.WriteTag(2, WireFormat.WireType.LengthDelimited); - output.WriteString(value2); - - // Third entry - var key3 = 15; - var value3 = 25; - output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); - output.WriteLength(4); - output.WriteTag(1, WireFormat.WireType.Varint); - output.WriteInt32(key3); - output.WriteTag(2, WireFormat.WireType.Varint); - output.WriteInt32(value3); - - output.Flush(); - var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray()); - var expected = new TestMap - { - MapInt32Int32 = { { key1, value1 }, { key3, value3 } }, - MapStringString = { { key2, value2 } } - }; - Assert.AreEqual(expected, parsed); - } - - [Test] - public void DuplicateKeys_LastEntryWins() - { - var memoryStream = new MemoryStream(); - var output = new CodedOutputStream(memoryStream); - - var key = 10; - var value1 = 20; - var value2 = 30; - - // First entry - output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); - output.WriteLength(4); - output.WriteTag(1, WireFormat.WireType.Varint); - output.WriteInt32(key); - output.WriteTag(2, WireFormat.WireType.Varint); - output.WriteInt32(value1); - - // Second entry - same key, different value - output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); - output.WriteLength(4); - output.WriteTag(1, WireFormat.WireType.Varint); - output.WriteInt32(key); - output.WriteTag(2, WireFormat.WireType.Varint); - output.WriteInt32(value2); - output.Flush(); - - var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray()); - Assert.AreEqual(value2, parsed.MapInt32Int32[key]); - } - - [Test] - public void CloneSingleNonMessageValues() - { - var original = new TestAllTypes - { - SingleBool = true, - SingleBytes = ByteString.CopyFrom(1, 2, 3, 4), - SingleDouble = 23.5, - SingleFixed32 = 23, - SingleFixed64 = 1234567890123, - SingleFloat = 12.25f, - SingleInt32 = 100, - SingleInt64 = 3210987654321, - SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, - SingleSfixed32 = -123, - SingleSfixed64 = -12345678901234, - SingleSint32 = -456, - SingleSint64 = -12345678901235, - SingleString = "test", - SingleUint32 = uint.MaxValue, - SingleUint64 = ulong.MaxValue - }; - var clone = original.Clone(); - Assert.AreNotSame(original, clone); - Assert.AreEqual(original, clone); - // Just as a single example - clone.SingleInt32 = 150; - Assert.AreNotEqual(original, clone); - } - - [Test] - public void CloneRepeatedNonMessageValues() - { - var original = new TestAllTypes - { - RepeatedBool = { true, false }, - RepeatedBytes = { ByteString.CopyFrom(1, 2, 3, 4), ByteString.CopyFrom(5, 6) }, - RepeatedDouble = { -12.25, 23.5 }, - RepeatedFixed32 = { uint.MaxValue, 23 }, - RepeatedFixed64 = { ulong.MaxValue, 1234567890123 }, - RepeatedFloat = { 100f, 12.25f }, - RepeatedInt32 = { 100, 200 }, - RepeatedInt64 = { 3210987654321, long.MaxValue }, - RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg }, - RepeatedSfixed32 = { -123, 123 }, - RepeatedSfixed64 = { -12345678901234, 12345678901234 }, - RepeatedSint32 = { -456, 100 }, - RepeatedSint64 = { -12345678901235, 123 }, - RepeatedString = { "foo", "bar" }, - RepeatedUint32 = { uint.MaxValue, uint.MinValue }, - RepeatedUint64 = { ulong.MaxValue, uint.MinValue } - }; - - var clone = original.Clone(); - Assert.AreNotSame(original, clone); - Assert.AreEqual(original, clone); - // Just as a single example - clone.RepeatedDouble.Add(25.5); - Assert.AreNotEqual(original, clone); - } - - [Test] - public void CloneSingleMessageField() - { - var original = new TestAllTypes - { - SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } - }; - - var clone = original.Clone(); - Assert.AreNotSame(original, clone); - Assert.AreNotSame(original.SingleNestedMessage, clone.SingleNestedMessage); - Assert.AreEqual(original, clone); - - clone.SingleNestedMessage.Bb = 30; - Assert.AreNotEqual(original, clone); - } - - [Test] - public void CloneRepeatedMessageField() - { - var original = new TestAllTypes - { - RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 20 } } - }; - - var clone = original.Clone(); - Assert.AreNotSame(original, clone); - Assert.AreNotSame(original.RepeatedNestedMessage, clone.RepeatedNestedMessage); - Assert.AreNotSame(original.RepeatedNestedMessage[0], clone.RepeatedNestedMessage[0]); - Assert.AreEqual(original, clone); - - clone.RepeatedNestedMessage[0].Bb = 30; - Assert.AreNotEqual(original, clone); - } - - [Test] - public void CloneOneofField() - { - var original = new TestAllTypes - { - OneofNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } - }; - - var clone = original.Clone(); - Assert.AreNotSame(original, clone); - Assert.AreEqual(original, clone); - - // We should have cloned the message - original.OneofNestedMessage.Bb = 30; - Assert.AreNotEqual(original, clone); - } - - [Test] - public void OneofProperties() - { - // Switch the oneof case between each of the different options, and check everything behaves - // as expected in each case. - var message = new TestAllTypes(); - Assert.AreEqual("", message.OneofString); - Assert.AreEqual(0, message.OneofUint32); - Assert.AreEqual(ByteString.Empty, message.OneofBytes); - Assert.IsNull(message.OneofNestedMessage); - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); - - message.OneofString = "sample"; - Assert.AreEqual("sample", message.OneofString); - Assert.AreEqual(0, message.OneofUint32); - Assert.AreEqual(ByteString.Empty, message.OneofBytes); - Assert.IsNull(message.OneofNestedMessage); - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofString, message.OneofFieldCase); - - var bytes = ByteString.CopyFrom(1, 2, 3); - message.OneofBytes = bytes; - Assert.AreEqual("", message.OneofString); - Assert.AreEqual(0, message.OneofUint32); - Assert.AreEqual(bytes, message.OneofBytes); - Assert.IsNull(message.OneofNestedMessage); - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofBytes, message.OneofFieldCase); - - message.OneofUint32 = 20; - Assert.AreEqual("", message.OneofString); - Assert.AreEqual(20, message.OneofUint32); - Assert.AreEqual(ByteString.Empty, message.OneofBytes); - Assert.IsNull(message.OneofNestedMessage); - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message.OneofFieldCase); - - var nestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 25 }; - message.OneofNestedMessage = nestedMessage; - Assert.AreEqual("", message.OneofString); - Assert.AreEqual(0, message.OneofUint32); - Assert.AreEqual(ByteString.Empty, message.OneofBytes); - Assert.AreEqual(nestedMessage, message.OneofNestedMessage); - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofNestedMessage, message.OneofFieldCase); - - message.ClearOneofField(); - Assert.AreEqual("", message.OneofString); - Assert.AreEqual(0, message.OneofUint32); - Assert.AreEqual(ByteString.Empty, message.OneofBytes); - Assert.IsNull(message.OneofNestedMessage); - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); - } - - [Test] - public void Oneof_DefaultValuesNotEqual() - { - var message1 = new TestAllTypes { OneofString = "" }; - var message2 = new TestAllTypes { OneofUint32 = 0 }; - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofString, message1.OneofFieldCase); - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase); - Assert.AreNotEqual(message1, message2); - } - - [Test] - public void OneofSerialization_NonDefaultValue() - { - var message = new TestAllTypes(); - message.OneofString = "this would take a bit of space"; - message.OneofUint32 = 10; - var bytes = message.ToByteArray(); - Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - no string! - - var message2 = TestAllTypes.Parser.ParseFrom(bytes); - Assert.AreEqual(message, message2); - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase); - } - - [Test] - public void OneofSerialization_DefaultValue() - { - var message = new TestAllTypes(); - message.OneofString = "this would take a bit of space"; - message.OneofUint32 = 0; // This is the default value for UInt32; normally wouldn't be serialized - var bytes = message.ToByteArray(); - Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - it's still serialized - - var message2 = TestAllTypes.Parser.ParseFrom(bytes); - Assert.AreEqual(message, message2); - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase); - } - - [Test] - public void DiscardUnknownFields_RealDataStillRead() - { - var message = SampleMessages.CreateFullTestAllTypes(); - var stream = new MemoryStream(); - var output = new CodedOutputStream(stream); - var unusedFieldNumber = 23456; - Assert.IsFalse(TestAllTypes.Descriptor.Fields.InDeclarationOrder().Select(x => x.FieldNumber).Contains(unusedFieldNumber)); - output.WriteTag(unusedFieldNumber, WireFormat.WireType.LengthDelimited); - output.WriteString("ignore me"); - message.WriteTo(output); - output.Flush(); - - stream.Position = 0; - var parsed = TestAllTypes.Parser.ParseFrom(stream); - // TODO(jieluo): Add test back after DiscardUnknownFields is supported - // Assert.AreEqual(message, parsed); - } - - [Test] - public void DiscardUnknownFields_AllTypes() - { - // Simple way of ensuring we can skip all kinds of fields. - var data = SampleMessages.CreateFullTestAllTypes().ToByteArray(); - var empty = Empty.Parser.ParseFrom(data); - // TODO(jieluo): Add test back after DiscardUnknownField is supported. - // Assert.AreEqual(new Empty(), empty); - } - - // This was originally seen as a conformance test failure. - [Test] - public void TruncatedMessageFieldThrows() - { - // 130, 3 is the message tag - // 1 is the data length - but there's no data. - var data = new byte[] { 130, 3, 1 }; - Assert.Throws(() => TestAllTypes.Parser.ParseFrom(data)); - } - - /// - /// Demonstrates current behaviour with an extraneous end group tag - see issue 688 - /// for details; we may want to change this. - /// - [Test] - public void ExtraEndGroupThrows() - { - var message = SampleMessages.CreateFullTestAllTypes(); - var stream = new MemoryStream(); - var output = new CodedOutputStream(stream); - - output.WriteTag(TestAllTypes.SingleFixed32FieldNumber, WireFormat.WireType.Fixed32); - output.WriteFixed32(123); - output.WriteTag(100, WireFormat.WireType.EndGroup); - - output.Flush(); - - stream.Position = 0; - Assert.Throws(() => TestAllTypes.Parser.ParseFrom(stream)); - } - - [Test] - public void CustomDiagnosticMessage_DirectToStringCall() - { - var message = new ForeignMessage { C = 31 }; - Assert.AreEqual("{ \"c\": 31, \"@cInHex\": \"1f\" }", message.ToString()); - Assert.AreEqual("{ \"c\": 31 }", JsonFormatter.Default.Format(message)); - } - - [Test] - public void CustomDiagnosticMessage_Nested() - { - var message = new TestAllTypes { SingleForeignMessage = new ForeignMessage { C = 16 } }; - Assert.AreEqual("{ \"singleForeignMessage\": { \"c\": 16, \"@cInHex\": \"10\" } }", message.ToString()); - Assert.AreEqual("{ \"singleForeignMessage\": { \"c\": 16 } }", JsonFormatter.Default.Format(message)); - } - - [Test] - public void CustomDiagnosticMessage_DirectToTextWriterCall() - { - var message = new ForeignMessage { C = 31 }; - var writer = new StringWriter(); - JsonFormatter.Default.Format(message, writer); - Assert.AreEqual("{ \"c\": 31 }", writer.ToString()); - } - } -} +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.IO; +using Google.Protobuf.TestProtos; +using NUnit.Framework; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Google.Protobuf.WellKnownTypes; + +namespace Google.Protobuf +{ + /// + /// Tests around the generated TestAllTypes message. + /// + public class GeneratedMessageTest + { + [Test] + public void EmptyMessageFieldDistinctFromMissingMessageField() + { + // This demonstrates what we're really interested in... + var message1 = new TestAllTypes { SingleForeignMessage = new ForeignMessage() }; + var message2 = new TestAllTypes(); // SingleForeignMessage is null + EqualityTester.AssertInequality(message1, message2); + } + + [Test] + public void DefaultValues() + { + // Single fields + var message = new TestAllTypes(); + Assert.AreEqual(false, message.SingleBool); + Assert.AreEqual(ByteString.Empty, message.SingleBytes); + Assert.AreEqual(0.0, message.SingleDouble); + Assert.AreEqual(0, message.SingleFixed32); + Assert.AreEqual(0L, message.SingleFixed64); + Assert.AreEqual(0.0f, message.SingleFloat); + Assert.AreEqual(ForeignEnum.ForeignUnspecified, message.SingleForeignEnum); + Assert.IsNull(message.SingleForeignMessage); + Assert.AreEqual(ImportEnum.Unspecified, message.SingleImportEnum); + Assert.IsNull(message.SingleImportMessage); + Assert.AreEqual(0, message.SingleInt32); + Assert.AreEqual(0L, message.SingleInt64); + Assert.AreEqual(TestAllTypes.Types.NestedEnum.Unspecified, message.SingleNestedEnum); + Assert.IsNull(message.SingleNestedMessage); + Assert.IsNull(message.SinglePublicImportMessage); + Assert.AreEqual(0, message.SingleSfixed32); + Assert.AreEqual(0L, message.SingleSfixed64); + Assert.AreEqual(0, message.SingleSint32); + Assert.AreEqual(0L, message.SingleSint64); + Assert.AreEqual("", message.SingleString); + Assert.AreEqual(0U, message.SingleUint32); + Assert.AreEqual(0UL, message.SingleUint64); + + // Repeated fields + Assert.AreEqual(0, message.RepeatedBool.Count); + Assert.AreEqual(0, message.RepeatedBytes.Count); + Assert.AreEqual(0, message.RepeatedDouble.Count); + Assert.AreEqual(0, message.RepeatedFixed32.Count); + Assert.AreEqual(0, message.RepeatedFixed64.Count); + Assert.AreEqual(0, message.RepeatedFloat.Count); + Assert.AreEqual(0, message.RepeatedForeignEnum.Count); + Assert.AreEqual(0, message.RepeatedForeignMessage.Count); + Assert.AreEqual(0, message.RepeatedImportEnum.Count); + Assert.AreEqual(0, message.RepeatedImportMessage.Count); + Assert.AreEqual(0, message.RepeatedNestedEnum.Count); + Assert.AreEqual(0, message.RepeatedNestedMessage.Count); + Assert.AreEqual(0, message.RepeatedPublicImportMessage.Count); + Assert.AreEqual(0, message.RepeatedSfixed32.Count); + Assert.AreEqual(0, message.RepeatedSfixed64.Count); + Assert.AreEqual(0, message.RepeatedSint32.Count); + Assert.AreEqual(0, message.RepeatedSint64.Count); + Assert.AreEqual(0, message.RepeatedString.Count); + Assert.AreEqual(0, message.RepeatedUint32.Count); + Assert.AreEqual(0, message.RepeatedUint64.Count); + + // Oneof fields + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); + Assert.AreEqual(0, message.OneofUint32); + Assert.AreEqual("", message.OneofString); + Assert.AreEqual(ByteString.Empty, message.OneofBytes); + Assert.IsNull(message.OneofNestedMessage); + } + + [Test] + public void NullStringAndBytesRejected() + { + var message = new TestAllTypes(); + Assert.Throws(() => message.SingleString = null); + Assert.Throws(() => message.OneofString = null); + Assert.Throws(() => message.SingleBytes = null); + Assert.Throws(() => message.OneofBytes = null); + } + + [Test] + public void RoundTrip_Empty() + { + var message = new TestAllTypes(); + // Without setting any values, there's nothing to write. + byte[] bytes = message.ToByteArray(); + Assert.AreEqual(0, bytes.Length); + TestAllTypes parsed = TestAllTypes.Parser.ParseFrom(bytes); + Assert.AreEqual(message, parsed); + } + + [Test] + public void RoundTrip_SingleValues() + { + var message = new TestAllTypes + { + SingleBool = true, + SingleBytes = ByteString.CopyFrom(1, 2, 3, 4), + SingleDouble = 23.5, + SingleFixed32 = 23, + SingleFixed64 = 1234567890123, + SingleFloat = 12.25f, + SingleForeignEnum = ForeignEnum.ForeignBar, + SingleForeignMessage = new ForeignMessage { C = 10 }, + SingleImportEnum = ImportEnum.ImportBaz, + SingleImportMessage = new ImportMessage { D = 20 }, + SingleInt32 = 100, + SingleInt64 = 3210987654321, + SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, + SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 }, + SinglePublicImportMessage = new PublicImportMessage { E = 54 }, + SingleSfixed32 = -123, + SingleSfixed64 = -12345678901234, + SingleSint32 = -456, + SingleSint64 = -12345678901235, + SingleString = "test", + SingleUint32 = uint.MaxValue, + SingleUint64 = ulong.MaxValue + }; + + byte[] bytes = message.ToByteArray(); + TestAllTypes parsed = TestAllTypes.Parser.ParseFrom(bytes); + Assert.AreEqual(message, parsed); + } + + [Test] + public void RoundTrip_RepeatedValues() + { + var message = new TestAllTypes + { + RepeatedBool = { true, false }, + RepeatedBytes = { ByteString.CopyFrom(1, 2, 3, 4), ByteString.CopyFrom(5, 6) }, + RepeatedDouble = { -12.25, 23.5 }, + RepeatedFixed32 = { uint.MaxValue, 23 }, + RepeatedFixed64 = { ulong.MaxValue, 1234567890123 }, + RepeatedFloat = { 100f, 12.25f }, + RepeatedForeignEnum = { ForeignEnum.ForeignFoo, ForeignEnum.ForeignBar }, + RepeatedForeignMessage = { new ForeignMessage(), new ForeignMessage { C = 10 } }, + RepeatedImportEnum = { ImportEnum.ImportBaz, ImportEnum.Unspecified }, + RepeatedImportMessage = { new ImportMessage { D = 20 }, new ImportMessage { D = 25 } }, + RepeatedInt32 = { 100, 200 }, + RepeatedInt64 = { 3210987654321, long.MaxValue }, + RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg }, + RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 35 }, new TestAllTypes.Types.NestedMessage { Bb = 10 } }, + RepeatedPublicImportMessage = { new PublicImportMessage { E = 54 }, new PublicImportMessage { E = -1 } }, + RepeatedSfixed32 = { -123, 123 }, + RepeatedSfixed64 = { -12345678901234, 12345678901234 }, + RepeatedSint32 = { -456, 100 }, + RepeatedSint64 = { -12345678901235, 123 }, + RepeatedString = { "foo", "bar" }, + RepeatedUint32 = { uint.MaxValue, uint.MinValue }, + RepeatedUint64 = { ulong.MaxValue, uint.MinValue } + }; + + byte[] bytes = message.ToByteArray(); + TestAllTypes parsed = TestAllTypes.Parser.ParseFrom(bytes); + Assert.AreEqual(message, parsed); + } + + // Note that not every map within map_unittest_proto3 is used. They all go through very + // similar code paths. The fact that all maps are present is validation that we have codecs + // for every type. + [Test] + public void RoundTrip_Maps() + { + var message = new TestMap + { + MapBoolBool = { + { false, true }, + { true, false } + }, + MapInt32Bytes = { + { 5, ByteString.CopyFrom(6, 7, 8) }, + { 25, ByteString.CopyFrom(1, 2, 3, 4, 5) }, + { 10, ByteString.Empty } + }, + MapInt32ForeignMessage = { + { 0, new ForeignMessage { C = 10 } }, + { 5, new ForeignMessage() }, + }, + MapInt32Enum = { + { 1, MapEnum.Bar }, + { 2000, MapEnum.Foo } + } + }; + + byte[] bytes = message.ToByteArray(); + TestMap parsed = TestMap.Parser.ParseFrom(bytes); + Assert.AreEqual(message, parsed); + } + + [Test] + public void MapWithEmptyEntry() + { + var message = new TestMap + { + MapInt32Bytes = { { 0, ByteString.Empty } } + }; + + byte[] bytes = message.ToByteArray(); + Assert.AreEqual(2, bytes.Length); // Tag for field entry (1 byte), length of entry (0; 1 byte) + + var parsed = TestMap.Parser.ParseFrom(bytes); + Assert.AreEqual(1, parsed.MapInt32Bytes.Count); + Assert.AreEqual(ByteString.Empty, parsed.MapInt32Bytes[0]); + } + + [Test] + public void MapWithOnlyValue() + { + // Hand-craft the stream to contain a single entry with just a value. + var memoryStream = new MemoryStream(); + var output = new CodedOutputStream(memoryStream); + output.WriteTag(TestMap.MapInt32ForeignMessageFieldNumber, WireFormat.WireType.LengthDelimited); + var nestedMessage = new ForeignMessage { C = 20 }; + // Size of the entry (tag, size written by WriteMessage, data written by WriteMessage) + output.WriteLength(2 + nestedMessage.CalculateSize()); + output.WriteTag(2, WireFormat.WireType.LengthDelimited); + output.WriteMessage(nestedMessage); + output.Flush(); + + var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray()); + Assert.AreEqual(nestedMessage, parsed.MapInt32ForeignMessage[0]); + } + + [Test] + public void MapWithOnlyKey_PrimitiveValue() + { + // Hand-craft the stream to contain a single entry with just a key. + var memoryStream = new MemoryStream(); + var output = new CodedOutputStream(memoryStream); + output.WriteTag(TestMap.MapInt32DoubleFieldNumber, WireFormat.WireType.LengthDelimited); + int key = 10; + output.WriteLength(1 + CodedOutputStream.ComputeInt32Size(key)); + output.WriteTag(1, WireFormat.WireType.Varint); + output.WriteInt32(key); + output.Flush(); + + var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray()); + Assert.AreEqual(0.0, parsed.MapInt32Double[key]); + } + + [Test] + public void MapWithOnlyKey_MessageValue() + { + // Hand-craft the stream to contain a single entry with just a key. + var memoryStream = new MemoryStream(); + var output = new CodedOutputStream(memoryStream); + output.WriteTag(TestMap.MapInt32ForeignMessageFieldNumber, WireFormat.WireType.LengthDelimited); + int key = 10; + output.WriteLength(1 + CodedOutputStream.ComputeInt32Size(key)); + output.WriteTag(1, WireFormat.WireType.Varint); + output.WriteInt32(key); + output.Flush(); + + var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray()); + Assert.AreEqual(new ForeignMessage(), parsed.MapInt32ForeignMessage[key]); + } + + [Test] + public void MapIgnoresExtraFieldsWithinEntryMessages() + { + // Hand-craft the stream to contain a single entry with three fields + var memoryStream = new MemoryStream(); + var output = new CodedOutputStream(memoryStream); + + output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); + + var key = 10; // Field 1 + var value = 20; // Field 2 + var extra = 30; // Field 3 + + // Each field can be represented in a single byte, with a single byte tag. + // Total message size: 6 bytes. + output.WriteLength(6); + output.WriteTag(1, WireFormat.WireType.Varint); + output.WriteInt32(key); + output.WriteTag(2, WireFormat.WireType.Varint); + output.WriteInt32(value); + output.WriteTag(3, WireFormat.WireType.Varint); + output.WriteInt32(extra); + output.Flush(); + + var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray()); + Assert.AreEqual(value, parsed.MapInt32Int32[key]); + } + + [Test] + public void MapFieldOrderIsIrrelevant() + { + var memoryStream = new MemoryStream(); + var output = new CodedOutputStream(memoryStream); + + output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); + + var key = 10; + var value = 20; + + // Each field can be represented in a single byte, with a single byte tag. + // Total message size: 4 bytes. + output.WriteLength(4); + output.WriteTag(2, WireFormat.WireType.Varint); + output.WriteInt32(value); + output.WriteTag(1, WireFormat.WireType.Varint); + output.WriteInt32(key); + output.Flush(); + + var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray()); + Assert.AreEqual(value, parsed.MapInt32Int32[key]); + } + + [Test] + public void MapNonContiguousEntries() + { + var memoryStream = new MemoryStream(); + var output = new CodedOutputStream(memoryStream); + + // Message structure: + // Entry for MapInt32Int32 + // Entry for MapStringString + // Entry for MapInt32Int32 + + // First entry + var key1 = 10; + var value1 = 20; + output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); + output.WriteLength(4); + output.WriteTag(1, WireFormat.WireType.Varint); + output.WriteInt32(key1); + output.WriteTag(2, WireFormat.WireType.Varint); + output.WriteInt32(value1); + + // Second entry + var key2 = "a"; + var value2 = "b"; + output.WriteTag(TestMap.MapStringStringFieldNumber, WireFormat.WireType.LengthDelimited); + output.WriteLength(6); // 3 bytes per entry: tag, size, character + output.WriteTag(1, WireFormat.WireType.LengthDelimited); + output.WriteString(key2); + output.WriteTag(2, WireFormat.WireType.LengthDelimited); + output.WriteString(value2); + + // Third entry + var key3 = 15; + var value3 = 25; + output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); + output.WriteLength(4); + output.WriteTag(1, WireFormat.WireType.Varint); + output.WriteInt32(key3); + output.WriteTag(2, WireFormat.WireType.Varint); + output.WriteInt32(value3); + + output.Flush(); + var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray()); + var expected = new TestMap + { + MapInt32Int32 = { { key1, value1 }, { key3, value3 } }, + MapStringString = { { key2, value2 } } + }; + Assert.AreEqual(expected, parsed); + } + + [Test] + public void DuplicateKeys_LastEntryWins() + { + var memoryStream = new MemoryStream(); + var output = new CodedOutputStream(memoryStream); + + var key = 10; + var value1 = 20; + var value2 = 30; + + // First entry + output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); + output.WriteLength(4); + output.WriteTag(1, WireFormat.WireType.Varint); + output.WriteInt32(key); + output.WriteTag(2, WireFormat.WireType.Varint); + output.WriteInt32(value1); + + // Second entry - same key, different value + output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); + output.WriteLength(4); + output.WriteTag(1, WireFormat.WireType.Varint); + output.WriteInt32(key); + output.WriteTag(2, WireFormat.WireType.Varint); + output.WriteInt32(value2); + output.Flush(); + + var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray()); + Assert.AreEqual(value2, parsed.MapInt32Int32[key]); + } + + [Test] + public void CloneSingleNonMessageValues() + { + var original = new TestAllTypes + { + SingleBool = true, + SingleBytes = ByteString.CopyFrom(1, 2, 3, 4), + SingleDouble = 23.5, + SingleFixed32 = 23, + SingleFixed64 = 1234567890123, + SingleFloat = 12.25f, + SingleInt32 = 100, + SingleInt64 = 3210987654321, + SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, + SingleSfixed32 = -123, + SingleSfixed64 = -12345678901234, + SingleSint32 = -456, + SingleSint64 = -12345678901235, + SingleString = "test", + SingleUint32 = uint.MaxValue, + SingleUint64 = ulong.MaxValue + }; + var clone = original.Clone(); + Assert.AreNotSame(original, clone); + Assert.AreEqual(original, clone); + // Just as a single example + clone.SingleInt32 = 150; + Assert.AreNotEqual(original, clone); + } + + [Test] + public void CloneRepeatedNonMessageValues() + { + var original = new TestAllTypes + { + RepeatedBool = { true, false }, + RepeatedBytes = { ByteString.CopyFrom(1, 2, 3, 4), ByteString.CopyFrom(5, 6) }, + RepeatedDouble = { -12.25, 23.5 }, + RepeatedFixed32 = { uint.MaxValue, 23 }, + RepeatedFixed64 = { ulong.MaxValue, 1234567890123 }, + RepeatedFloat = { 100f, 12.25f }, + RepeatedInt32 = { 100, 200 }, + RepeatedInt64 = { 3210987654321, long.MaxValue }, + RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg }, + RepeatedSfixed32 = { -123, 123 }, + RepeatedSfixed64 = { -12345678901234, 12345678901234 }, + RepeatedSint32 = { -456, 100 }, + RepeatedSint64 = { -12345678901235, 123 }, + RepeatedString = { "foo", "bar" }, + RepeatedUint32 = { uint.MaxValue, uint.MinValue }, + RepeatedUint64 = { ulong.MaxValue, uint.MinValue } + }; + + var clone = original.Clone(); + Assert.AreNotSame(original, clone); + Assert.AreEqual(original, clone); + // Just as a single example + clone.RepeatedDouble.Add(25.5); + Assert.AreNotEqual(original, clone); + } + + [Test] + public void CloneSingleMessageField() + { + var original = new TestAllTypes + { + SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } + }; + + var clone = original.Clone(); + Assert.AreNotSame(original, clone); + Assert.AreNotSame(original.SingleNestedMessage, clone.SingleNestedMessage); + Assert.AreEqual(original, clone); + + clone.SingleNestedMessage.Bb = 30; + Assert.AreNotEqual(original, clone); + } + + [Test] + public void CloneRepeatedMessageField() + { + var original = new TestAllTypes + { + RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 20 } } + }; + + var clone = original.Clone(); + Assert.AreNotSame(original, clone); + Assert.AreNotSame(original.RepeatedNestedMessage, clone.RepeatedNestedMessage); + Assert.AreNotSame(original.RepeatedNestedMessage[0], clone.RepeatedNestedMessage[0]); + Assert.AreEqual(original, clone); + + clone.RepeatedNestedMessage[0].Bb = 30; + Assert.AreNotEqual(original, clone); + } + + [Test] + public void CloneOneofField() + { + var original = new TestAllTypes + { + OneofNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } + }; + + var clone = original.Clone(); + Assert.AreNotSame(original, clone); + Assert.AreEqual(original, clone); + + // We should have cloned the message + original.OneofNestedMessage.Bb = 30; + Assert.AreNotEqual(original, clone); + } + + [Test] + public void OneofProperties() + { + // Switch the oneof case between each of the different options, and check everything behaves + // as expected in each case. + var message = new TestAllTypes(); + Assert.AreEqual("", message.OneofString); + Assert.AreEqual(0, message.OneofUint32); + Assert.AreEqual(ByteString.Empty, message.OneofBytes); + Assert.IsNull(message.OneofNestedMessage); + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); + + message.OneofString = "sample"; + Assert.AreEqual("sample", message.OneofString); + Assert.AreEqual(0, message.OneofUint32); + Assert.AreEqual(ByteString.Empty, message.OneofBytes); + Assert.IsNull(message.OneofNestedMessage); + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofString, message.OneofFieldCase); + + var bytes = ByteString.CopyFrom(1, 2, 3); + message.OneofBytes = bytes; + Assert.AreEqual("", message.OneofString); + Assert.AreEqual(0, message.OneofUint32); + Assert.AreEqual(bytes, message.OneofBytes); + Assert.IsNull(message.OneofNestedMessage); + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofBytes, message.OneofFieldCase); + + message.OneofUint32 = 20; + Assert.AreEqual("", message.OneofString); + Assert.AreEqual(20, message.OneofUint32); + Assert.AreEqual(ByteString.Empty, message.OneofBytes); + Assert.IsNull(message.OneofNestedMessage); + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message.OneofFieldCase); + + var nestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 25 }; + message.OneofNestedMessage = nestedMessage; + Assert.AreEqual("", message.OneofString); + Assert.AreEqual(0, message.OneofUint32); + Assert.AreEqual(ByteString.Empty, message.OneofBytes); + Assert.AreEqual(nestedMessage, message.OneofNestedMessage); + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofNestedMessage, message.OneofFieldCase); + + message.ClearOneofField(); + Assert.AreEqual("", message.OneofString); + Assert.AreEqual(0, message.OneofUint32); + Assert.AreEqual(ByteString.Empty, message.OneofBytes); + Assert.IsNull(message.OneofNestedMessage); + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); + } + + [Test] + public void Oneof_DefaultValuesNotEqual() + { + var message1 = new TestAllTypes { OneofString = "" }; + var message2 = new TestAllTypes { OneofUint32 = 0 }; + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofString, message1.OneofFieldCase); + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase); + Assert.AreNotEqual(message1, message2); + } + + [Test] + public void OneofSerialization_NonDefaultValue() + { + var message = new TestAllTypes(); + message.OneofString = "this would take a bit of space"; + message.OneofUint32 = 10; + var bytes = message.ToByteArray(); + Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - no string! + + var message2 = TestAllTypes.Parser.ParseFrom(bytes); + Assert.AreEqual(message, message2); + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase); + } + + [Test] + public void OneofSerialization_DefaultValue() + { + var message = new TestAllTypes(); + message.OneofString = "this would take a bit of space"; + message.OneofUint32 = 0; // This is the default value for UInt32; normally wouldn't be serialized + var bytes = message.ToByteArray(); + Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - it's still serialized + + var message2 = TestAllTypes.Parser.ParseFrom(bytes); + Assert.AreEqual(message, message2); + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase); + } + + [Test] + public void DiscardUnknownFields_RealDataStillRead() + { + var message = SampleMessages.CreateFullTestAllTypes(); + var stream = new MemoryStream(); + var output = new CodedOutputStream(stream); + var unusedFieldNumber = 23456; + Assert.IsFalse(TestAllTypes.Descriptor.Fields.InDeclarationOrder().Select(x => x.FieldNumber).Contains(unusedFieldNumber)); + output.WriteTag(unusedFieldNumber, WireFormat.WireType.LengthDelimited); + output.WriteString("ignore me"); + message.WriteTo(output); + output.Flush(); + + stream.Position = 0; + var parsed = TestAllTypes.Parser.ParseFrom(stream); + // TODO(jieluo): Add test back after DiscardUnknownFields is supported + // Assert.AreEqual(message, parsed); + } + + [Test] + public void DiscardUnknownFields_AllTypes() + { + // Simple way of ensuring we can skip all kinds of fields. + var data = SampleMessages.CreateFullTestAllTypes().ToByteArray(); + var empty = Empty.Parser.ParseFrom(data); + // TODO(jieluo): Add test back after DiscardUnknownField is supported. + // Assert.AreEqual(new Empty(), empty); + } + + // This was originally seen as a conformance test failure. + [Test] + public void TruncatedMessageFieldThrows() + { + // 130, 3 is the message tag + // 1 is the data length - but there's no data. + var data = new byte[] { 130, 3, 1 }; + Assert.Throws(() => TestAllTypes.Parser.ParseFrom(data)); + } + + /// + /// Demonstrates current behaviour with an extraneous end group tag - see issue 688 + /// for details; we may want to change this. + /// + [Test] + public void ExtraEndGroupThrows() + { + var message = SampleMessages.CreateFullTestAllTypes(); + var stream = new MemoryStream(); + var output = new CodedOutputStream(stream); + + output.WriteTag(TestAllTypes.SingleFixed32FieldNumber, WireFormat.WireType.Fixed32); + output.WriteFixed32(123); + output.WriteTag(100, WireFormat.WireType.EndGroup); + + output.Flush(); + + stream.Position = 0; + Assert.Throws(() => TestAllTypes.Parser.ParseFrom(stream)); + } + + [Test] + public void CustomDiagnosticMessage_DirectToStringCall() + { + var message = new ForeignMessage { C = 31 }; + Assert.AreEqual("{ \"c\": 31, \"@cInHex\": \"1f\" }", message.ToString()); + Assert.AreEqual("{ \"c\": 31 }", JsonFormatter.Default.Format(message)); + } + + [Test] + public void CustomDiagnosticMessage_Nested() + { + var message = new TestAllTypes { SingleForeignMessage = new ForeignMessage { C = 16 } }; + Assert.AreEqual("{ \"singleForeignMessage\": { \"c\": 16, \"@cInHex\": \"10\" } }", message.ToString()); + Assert.AreEqual("{ \"singleForeignMessage\": { \"c\": 16 } }", JsonFormatter.Default.Format(message)); + } + + [Test] + public void CustomDiagnosticMessage_DirectToTextWriterCall() + { + var message = new ForeignMessage { C = 31 }; + var writer = new StringWriter(); + JsonFormatter.Default.Format(message, writer); + Assert.AreEqual("{ \"c\": 31 }", writer.ToString()); + } + } +} diff --git a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/IssuesTest.cs b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/IssuesTest.cs index a38d6b08b568..b4022a21cf82 100644 --- a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/IssuesTest.cs +++ b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/IssuesTest.cs @@ -1,82 +1,82 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using Google.Protobuf.Reflection; -using UnitTest.Issues.TestProtos; -using NUnit.Framework; - - -namespace Google.Protobuf -{ - /// - /// Tests for issues which aren't easily compartmentalized into other unit tests. - /// - public class IssuesTest - { - // Issue 45 - [Test] - public void FieldCalledItem() - { - ItemField message = new ItemField { Item = 3 }; - FieldDescriptor field = ItemField.Descriptor.FindFieldByName("item"); - Assert.NotNull(field); - Assert.AreEqual(3, (int)field.Accessor.GetValue(message)); - } - - [Test] - public void ReservedNames() - { - var message = new ReservedNames { Types_ = 10, Descriptor_ = 20 }; - // Underscores aren't reflected in the JSON. - Assert.AreEqual("{ \"types\": 10, \"descriptor\": 20 }", message.ToString()); - } - - [Test] - public void JsonNameParseTest() - { - var settings = new JsonParser.Settings(10, TypeRegistry.FromFiles(UnittestIssuesReflection.Descriptor)); - var parser = new JsonParser(settings); - - // It is safe to use either original field name or explicitly specified json_name - Assert.AreEqual(new TestJsonName { Name = "test", Description = "test2", Guid = "test3" }, - parser.Parse("{ \"name\": \"test\", \"desc\": \"test2\", \"guid\": \"test3\" }")); - } - - [Test] - public void JsonNameFormatTest() - { - var message = new TestJsonName { Name = "test", Description = "test2", Guid = "test3" }; - Assert.AreEqual("{ \"name\": \"test\", \"desc\": \"test2\", \"exid\": \"test3\" }", - JsonFormatter.Default.Format(message)); - } - } -} +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using Google.Protobuf.Reflection; +using UnitTest.Issues.TestProtos; +using NUnit.Framework; + + +namespace Google.Protobuf +{ + /// + /// Tests for issues which aren't easily compartmentalized into other unit tests. + /// + public class IssuesTest + { + // Issue 45 + [Test] + public void FieldCalledItem() + { + ItemField message = new ItemField { Item = 3 }; + FieldDescriptor field = ItemField.Descriptor.FindFieldByName("item"); + Assert.NotNull(field); + Assert.AreEqual(3, (int)field.Accessor.GetValue(message)); + } + + [Test] + public void ReservedNames() + { + var message = new ReservedNames { Types_ = 10, Descriptor_ = 20 }; + // Underscores aren't reflected in the JSON. + Assert.AreEqual("{ \"types\": 10, \"descriptor\": 20 }", message.ToString()); + } + + [Test] + public void JsonNameParseTest() + { + var settings = new JsonParser.Settings(10, TypeRegistry.FromFiles(UnittestIssuesReflection.Descriptor)); + var parser = new JsonParser(settings); + + // It is safe to use either original field name or explicitly specified json_name + Assert.AreEqual(new TestJsonName { Name = "test", Description = "test2", Guid = "test3" }, + parser.Parse("{ \"name\": \"test\", \"desc\": \"test2\", \"guid\": \"test3\" }")); + } + + [Test] + public void JsonNameFormatTest() + { + var message = new TestJsonName { Name = "test", Description = "test2", Guid = "test3" }; + Assert.AreEqual("{ \"name\": \"test\", \"desc\": \"test2\", \"exid\": \"test3\" }", + JsonFormatter.Default.Format(message)); + } + } +} diff --git a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/TestCornerCases.cs b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/TestCornerCases.cs index 248f5fa913f2..859b49c2d637 100644 --- a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/TestCornerCases.cs +++ b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/TestCornerCases.cs @@ -1,62 +1,62 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using UnitTest.Issues.TestProtos; -using NUnit.Framework; - -namespace Google.Protobuf -{ - public class TestCornerCases - { - [Test] - public void TestRoundTripNegativeEnums() - { - NegativeEnumMessage msg = new NegativeEnumMessage - { - Value = NegativeEnum.MinusOne, - Values = { NegativeEnum.Zero, NegativeEnum.MinusOne, NegativeEnum.FiveBelow }, - PackedValues = { NegativeEnum.Zero, NegativeEnum.MinusOne, NegativeEnum.FiveBelow } - }; - - Assert.AreEqual(58, msg.CalculateSize()); - - byte[] bytes = new byte[58]; - CodedOutputStream output = new CodedOutputStream(bytes); - - msg.WriteTo(output); - Assert.AreEqual(0, output.SpaceLeft); - - NegativeEnumMessage copy = NegativeEnumMessage.Parser.ParseFrom(bytes); - Assert.AreEqual(msg, copy); - } - } -} +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using UnitTest.Issues.TestProtos; +using NUnit.Framework; + +namespace Google.Protobuf +{ + public class TestCornerCases + { + [Test] + public void TestRoundTripNegativeEnums() + { + NegativeEnumMessage msg = new NegativeEnumMessage + { + Value = NegativeEnum.MinusOne, + Values = { NegativeEnum.Zero, NegativeEnum.MinusOne, NegativeEnum.FiveBelow }, + PackedValues = { NegativeEnum.Zero, NegativeEnum.MinusOne, NegativeEnum.FiveBelow } + }; + + Assert.AreEqual(58, msg.CalculateSize()); + + byte[] bytes = new byte[58]; + CodedOutputStream output = new CodedOutputStream(bytes); + + msg.WriteTo(output); + Assert.AreEqual(0, output.SpaceLeft); + + NegativeEnumMessage copy = NegativeEnumMessage.Parser.ParseFrom(bytes); + Assert.AreEqual(msg, copy); + } + } +} diff --git a/csharp/src/AddressBook/AddPerson.cs b/csharp/src/AddressBook/AddPerson.cs index 62d1788d55a7..889d1d060c3b 100644 --- a/csharp/src/AddressBook/AddPerson.cs +++ b/csharp/src/AddressBook/AddPerson.cs @@ -1,132 +1,132 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.IO; - -namespace Google.Protobuf.Examples.AddressBook -{ - internal class AddPerson - { - /// - /// Builds a person based on user input - /// - private static Person PromptForAddress(TextReader input, TextWriter output) - { - Person person = new Person(); - - output.Write("Enter person ID: "); - person.Id = int.Parse(input.ReadLine()); - - output.Write("Enter name: "); - person.Name = input.ReadLine(); - - output.Write("Enter email address (blank for none): "); - string email = input.ReadLine(); - if (email.Length > 0) - { - person.Email = email; - } - - while (true) - { - output.Write("Enter a phone number (or leave blank to finish): "); - string number = input.ReadLine(); - if (number.Length == 0) - { - break; - } - - Person.Types.PhoneNumber phoneNumber = new Person.Types.PhoneNumber { Number = number }; - - output.Write("Is this a mobile, home, or work phone? "); - String type = input.ReadLine(); - switch (type) - { - case "mobile": - phoneNumber.Type = Person.Types.PhoneType.Mobile; - break; - case "home": - phoneNumber.Type = Person.Types.PhoneType.Home; - break; - case "work": - phoneNumber.Type = Person.Types.PhoneType.Work; - break; - default: - output.Write("Unknown phone type. Using default."); - break; - } - - person.Phones.Add(phoneNumber); - } - return person; - } - - /// - /// Entry point - loads an existing addressbook or creates a new one, - /// then writes it back to the file. - /// - public static int Main(string[] args) - { - if (args.Length != 1) - { - Console.Error.WriteLine("Usage: AddPerson ADDRESS_BOOK_FILE"); - return -1; - } - - AddressBook addressBook; - - if (File.Exists(args[0])) - { - using (Stream file = File.OpenRead(args[0])) - { - addressBook = AddressBook.Parser.ParseFrom(file); - } - } - else - { - Console.WriteLine("{0}: File not found. Creating a new file.", args[0]); - addressBook = new AddressBook(); - } - - // Add an address. - addressBook.People.Add(PromptForAddress(Console.In, Console.Out)); - - // Write the new address book back to disk. - using (Stream output = File.OpenWrite(args[0])) - { - addressBook.WriteTo(output); - } - return 0; - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.IO; + +namespace Google.Protobuf.Examples.AddressBook +{ + internal class AddPerson + { + /// + /// Builds a person based on user input + /// + private static Person PromptForAddress(TextReader input, TextWriter output) + { + Person person = new Person(); + + output.Write("Enter person ID: "); + person.Id = int.Parse(input.ReadLine()); + + output.Write("Enter name: "); + person.Name = input.ReadLine(); + + output.Write("Enter email address (blank for none): "); + string email = input.ReadLine(); + if (email.Length > 0) + { + person.Email = email; + } + + while (true) + { + output.Write("Enter a phone number (or leave blank to finish): "); + string number = input.ReadLine(); + if (number.Length == 0) + { + break; + } + + Person.Types.PhoneNumber phoneNumber = new Person.Types.PhoneNumber { Number = number }; + + output.Write("Is this a mobile, home, or work phone? "); + String type = input.ReadLine(); + switch (type) + { + case "mobile": + phoneNumber.Type = Person.Types.PhoneType.Mobile; + break; + case "home": + phoneNumber.Type = Person.Types.PhoneType.Home; + break; + case "work": + phoneNumber.Type = Person.Types.PhoneType.Work; + break; + default: + output.Write("Unknown phone type. Using default."); + break; + } + + person.Phones.Add(phoneNumber); + } + return person; + } + + /// + /// Entry point - loads an existing addressbook or creates a new one, + /// then writes it back to the file. + /// + public static int Main(string[] args) + { + if (args.Length != 1) + { + Console.Error.WriteLine("Usage: AddPerson ADDRESS_BOOK_FILE"); + return -1; + } + + AddressBook addressBook; + + if (File.Exists(args[0])) + { + using (Stream file = File.OpenRead(args[0])) + { + addressBook = AddressBook.Parser.ParseFrom(file); + } + } + else + { + Console.WriteLine("{0}: File not found. Creating a new file.", args[0]); + addressBook = new AddressBook(); + } + + // Add an address. + addressBook.People.Add(PromptForAddress(Console.In, Console.Out)); + + // Write the new address book back to disk. + using (Stream output = File.OpenWrite(args[0])) + { + addressBook.WriteTo(output); + } + return 0; + } + } } \ No newline at end of file diff --git a/csharp/src/AddressBook/ListPeople.cs b/csharp/src/AddressBook/ListPeople.cs index 3758c1bce5f8..fdcd64d26789 100644 --- a/csharp/src/AddressBook/ListPeople.cs +++ b/csharp/src/AddressBook/ListPeople.cs @@ -1,99 +1,99 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.IO; - -namespace Google.Protobuf.Examples.AddressBook -{ - internal class ListPeople - { - /// - /// Iterates though all people in the AddressBook and prints info about them. - /// - private static void Print(AddressBook addressBook) - { - foreach (Person person in addressBook.People) - { - Console.WriteLine("Person ID: {0}", person.Id); - Console.WriteLine(" Name: {0}", person.Name); - if (person.Email != "") - { - Console.WriteLine(" E-mail address: {0}", person.Email); - } - - foreach (Person.Types.PhoneNumber phoneNumber in person.Phones) - { - switch (phoneNumber.Type) - { - case Person.Types.PhoneType.Mobile: - Console.Write(" Mobile phone #: "); - break; - case Person.Types.PhoneType.Home: - Console.Write(" Home phone #: "); - break; - case Person.Types.PhoneType.Work: - Console.Write(" Work phone #: "); - break; - } - Console.WriteLine(phoneNumber.Number); - } - } - } - - /// - /// Entry point - loads the addressbook and then displays it. - /// - public static int Main(string[] args) - { - if (args.Length != 1) - { - Console.Error.WriteLine("Usage: ListPeople ADDRESS_BOOK_FILE"); - return 1; - } - - if (!File.Exists(args[0])) - { - Console.WriteLine("{0} doesn't exist. Add a person to create the file first.", args[0]); - return 0; - } - - // Read the existing address book. - using (Stream stream = File.OpenRead(args[0])) - { - AddressBook addressBook = AddressBook.Parser.ParseFrom(stream); - Print(addressBook); - } - return 0; - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.IO; + +namespace Google.Protobuf.Examples.AddressBook +{ + internal class ListPeople + { + /// + /// Iterates though all people in the AddressBook and prints info about them. + /// + private static void Print(AddressBook addressBook) + { + foreach (Person person in addressBook.People) + { + Console.WriteLine("Person ID: {0}", person.Id); + Console.WriteLine(" Name: {0}", person.Name); + if (person.Email != "") + { + Console.WriteLine(" E-mail address: {0}", person.Email); + } + + foreach (Person.Types.PhoneNumber phoneNumber in person.Phones) + { + switch (phoneNumber.Type) + { + case Person.Types.PhoneType.Mobile: + Console.Write(" Mobile phone #: "); + break; + case Person.Types.PhoneType.Home: + Console.Write(" Home phone #: "); + break; + case Person.Types.PhoneType.Work: + Console.Write(" Work phone #: "); + break; + } + Console.WriteLine(phoneNumber.Number); + } + } + } + + /// + /// Entry point - loads the addressbook and then displays it. + /// + public static int Main(string[] args) + { + if (args.Length != 1) + { + Console.Error.WriteLine("Usage: ListPeople ADDRESS_BOOK_FILE"); + return 1; + } + + if (!File.Exists(args[0])) + { + Console.WriteLine("{0} doesn't exist. Add a person to create the file first.", args[0]); + return 0; + } + + // Read the existing address book. + using (Stream stream = File.OpenRead(args[0])) + { + AddressBook addressBook = AddressBook.Parser.ParseFrom(stream); + Print(addressBook); + } + return 0; + } + } } \ No newline at end of file diff --git a/csharp/src/AddressBook/Program.cs b/csharp/src/AddressBook/Program.cs index de4867a0ce21..5bbe84cd527f 100644 --- a/csharp/src/AddressBook/Program.cs +++ b/csharp/src/AddressBook/Program.cs @@ -1,95 +1,95 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; - -namespace Google.Protobuf.Examples.AddressBook -{ - /// - /// Entry point. Repeatedly prompts user for an action to take, delegating actual behaviour - /// to individual actions. Each action has its own Main method, so that it can be used as an - /// individual complete program. - /// - internal class Program - { - private static int Main(string[] args) - { - if (args.Length > 1) - { - Console.Error.WriteLine("Usage: AddressBook [file]"); - Console.Error.WriteLine("If the filename isn't specified, \"addressbook.data\" is used instead."); - return 1; - } - string addressBookFile = args.Length > 0 ? args[0] : "addressbook.data"; - - bool stopping = false; - while (!stopping) - { - Console.WriteLine("Options:"); - Console.WriteLine(" L: List contents"); - Console.WriteLine(" A: Add new person"); - Console.WriteLine(" Q: Quit"); - Console.Write("Action? "); - Console.Out.Flush(); - char choice = Console.ReadKey().KeyChar; - Console.WriteLine(); - try - { - switch (choice) - { - case 'A': - case 'a': - AddPerson.Main(new string[] {addressBookFile}); - break; - case 'L': - case 'l': - ListPeople.Main(new string[] {addressBookFile}); - break; - case 'Q': - case 'q': - stopping = true; - break; - default: - Console.WriteLine("Unknown option: {0}", choice); - break; - } - } - catch (Exception e) - { - Console.WriteLine("Exception executing action: {0}", e); - } - Console.WriteLine(); - } - return 0; - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; + +namespace Google.Protobuf.Examples.AddressBook +{ + /// + /// Entry point. Repeatedly prompts user for an action to take, delegating actual behaviour + /// to individual actions. Each action has its own Main method, so that it can be used as an + /// individual complete program. + /// + internal class Program + { + private static int Main(string[] args) + { + if (args.Length > 1) + { + Console.Error.WriteLine("Usage: AddressBook [file]"); + Console.Error.WriteLine("If the filename isn't specified, \"addressbook.data\" is used instead."); + return 1; + } + string addressBookFile = args.Length > 0 ? args[0] : "addressbook.data"; + + bool stopping = false; + while (!stopping) + { + Console.WriteLine("Options:"); + Console.WriteLine(" L: List contents"); + Console.WriteLine(" A: Add new person"); + Console.WriteLine(" Q: Quit"); + Console.Write("Action? "); + Console.Out.Flush(); + char choice = Console.ReadKey().KeyChar; + Console.WriteLine(); + try + { + switch (choice) + { + case 'A': + case 'a': + AddPerson.Main(new string[] {addressBookFile}); + break; + case 'L': + case 'l': + ListPeople.Main(new string[] {addressBookFile}); + break; + case 'Q': + case 'q': + stopping = true; + break; + default: + Console.WriteLine("Unknown option: {0}", choice); + break; + } + } + catch (Exception e) + { + Console.WriteLine("Exception executing action: {0}", e); + } + Console.WriteLine(); + } + return 0; + } + } } \ No newline at end of file diff --git a/csharp/src/AddressBook/SampleUsage.cs b/csharp/src/AddressBook/SampleUsage.cs index 941d865aa48b..8f08f0f148d8 100644 --- a/csharp/src/AddressBook/SampleUsage.cs +++ b/csharp/src/AddressBook/SampleUsage.cs @@ -1,73 +1,73 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.IO; - -namespace Google.Protobuf.Examples.AddressBook -{ - internal class SampleUsage - { - private static void Main() - { - byte[] bytes; - // Create a new person - Person person = new Person - { - Id = 1, - Name = "Foo", - Email = "foo@bar", - Phones = { new Person.Types.PhoneNumber { Number = "555-1212" } } - }; - using (MemoryStream stream = new MemoryStream()) - { - // Save the person to a stream - person.WriteTo(stream); - bytes = stream.ToArray(); - } - Person copy = Person.Parser.ParseFrom(bytes); - - AddressBook book = new AddressBook - { - People = { copy } - }; - bytes = book.ToByteArray(); - // And read the address book back again - AddressBook restored = AddressBook.Parser.ParseFrom(bytes); - // The message performs a deep-comparison on equality: - if (restored.People.Count != 1 || !person.Equals(restored.People[0])) - { - throw new Exception("There is a bad person in here!"); - } - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.IO; + +namespace Google.Protobuf.Examples.AddressBook +{ + internal class SampleUsage + { + private static void Main() + { + byte[] bytes; + // Create a new person + Person person = new Person + { + Id = 1, + Name = "Foo", + Email = "foo@bar", + Phones = { new Person.Types.PhoneNumber { Number = "555-1212" } } + }; + using (MemoryStream stream = new MemoryStream()) + { + // Save the person to a stream + person.WriteTo(stream); + bytes = stream.ToArray(); + } + Person copy = Person.Parser.ParseFrom(bytes); + + AddressBook book = new AddressBook + { + People = { copy } + }; + bytes = book.ToByteArray(); + // And read the address book back again + AddressBook restored = AddressBook.Parser.ParseFrom(bytes); + // The message performs a deep-comparison on equality: + if (restored.People.Count != 1 || !person.Equals(restored.People[0])) + { + throw new Exception("There is a bad person in here!"); + } + } + } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf.JsonDump/Program.cs b/csharp/src/Google.Protobuf.JsonDump/Program.cs index 296b2f3f1ed5..56e32ad86e5c 100644 --- a/csharp/src/Google.Protobuf.JsonDump/Program.cs +++ b/csharp/src/Google.Protobuf.JsonDump/Program.cs @@ -1,73 +1,73 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.IO; -using System.Reflection; - -namespace Google.Protobuf.ProtoDump -{ - /// - /// Small utility to load a binary message and dump it in JSON format. - /// - internal class Program - { - private static int Main(string[] args) - { - if (args.Length != 2) - { - Console.Error.WriteLine("Usage: Google.Protobuf.JsonDump "); - Console.Error.WriteLine("The descriptor type name is the fully-qualified message name,"); - Console.Error.WriteLine("including assembly e.g. ProjectNamespace.Message,Company.Project"); - return 1; - } - Type type = Type.GetType(args[0]); - if (type == null) - { - Console.Error.WriteLine("Unable to load type {0}.", args[0]); - return 1; - } - if (!typeof(IMessage).GetTypeInfo().IsAssignableFrom(type)) - { - Console.Error.WriteLine("Type {0} doesn't implement IMessage.", args[0]); - return 1; - } - IMessage message = (IMessage) Activator.CreateInstance(type); - using (var input = File.OpenRead(args[1])) - { - message.MergeFrom(input); - } - Console.WriteLine(message); - return 0; - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.IO; +using System.Reflection; + +namespace Google.Protobuf.ProtoDump +{ + /// + /// Small utility to load a binary message and dump it in JSON format. + /// + internal class Program + { + private static int Main(string[] args) + { + if (args.Length != 2) + { + Console.Error.WriteLine("Usage: Google.Protobuf.JsonDump "); + Console.Error.WriteLine("The descriptor type name is the fully-qualified message name,"); + Console.Error.WriteLine("including assembly e.g. ProjectNamespace.Message,Company.Project"); + return 1; + } + Type type = Type.GetType(args[0]); + if (type == null) + { + Console.Error.WriteLine("Unable to load type {0}.", args[0]); + return 1; + } + if (!typeof(IMessage).GetTypeInfo().IsAssignableFrom(type)) + { + Console.Error.WriteLine("Type {0} doesn't implement IMessage.", args[0]); + return 1; + } + IMessage message = (IMessage) Activator.CreateInstance(type); + using (var input = File.OpenRead(args[1])) + { + message.MergeFrom(input); + } + Console.WriteLine(message); + return 0; + } + } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj b/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj index fb26b7c01e36..8d9d64b37e50 100644 --- a/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj +++ b/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj @@ -1,25 +1,25 @@ - - - - - net462;netstandard1.1;netstandard2.0 - 3.0 - ../../keys/Google.Protobuf.snk - true - False - - - - - - - - - - - - + + + + + net462;netstandard1.1;netstandard2.0 + 3.0 + ../../keys/Google.Protobuf.snk + true + False + + + + + + + + + + + + diff --git a/csharp/src/Google.Protobuf.Test/ByteStringTest.cs b/csharp/src/Google.Protobuf.Test/ByteStringTest.cs index 04d68b5bdcc6..4876e0979820 100644 --- a/csharp/src/Google.Protobuf.Test/ByteStringTest.cs +++ b/csharp/src/Google.Protobuf.Test/ByteStringTest.cs @@ -1,439 +1,439 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.Text; -using NUnit.Framework; -using System.IO; -using System.Collections.Generic; -using System.Collections; -using System.Linq; -using System.Buffers; -using System.Runtime.InteropServices; -using System.Threading; -using System.Runtime.CompilerServices; -#if !NET35 -using System.Threading.Tasks; -#endif - -namespace Google.Protobuf -{ - public class ByteStringTest - { - [Test] - public void Equality() - { - ByteString b1 = ByteString.CopyFrom(1, 2, 3); - ByteString b2 = ByteString.CopyFrom(1, 2, 3); - ByteString b3 = ByteString.CopyFrom(1, 2, 4); - ByteString b4 = ByteString.CopyFrom(1, 2, 3, 4); - EqualityTester.AssertEquality(b1, b1); - EqualityTester.AssertEquality(b1, b2); - EqualityTester.AssertInequality(b1, b3); - EqualityTester.AssertInequality(b1, b4); - EqualityTester.AssertInequality(b1, null); - EqualityTester.AssertEquality(ByteString.Empty, ByteString.Empty); -#pragma warning disable 1718 // Deliberately calling ==(b1, b1) and !=(b1, b1) - Assert.IsTrue(b1 == b1); - Assert.IsTrue(b1 == b2); - Assert.IsFalse(b1 == b3); - Assert.IsFalse(b1 == b4); - Assert.IsFalse(b1 == null); - Assert.IsTrue((ByteString) null == null); - Assert.IsFalse(b1 != b1); - Assert.IsFalse(b1 != b2); - Assert.IsTrue(ByteString.Empty == ByteString.Empty); -#pragma warning disable 1718 - Assert.IsTrue(b1 != b3); - Assert.IsTrue(b1 != b4); - Assert.IsTrue(b1 != null); - Assert.IsFalse((ByteString) null != null); - } - - [Test] - public void EmptyByteStringHasZeroSize() - { - Assert.AreEqual(0, ByteString.Empty.Length); - } - - [Test] - public void CopyFromStringWithExplicitEncoding() - { - ByteString bs = ByteString.CopyFrom("AB", Encoding.Unicode); - Assert.AreEqual(4, bs.Length); - Assert.AreEqual(65, bs[0]); - Assert.AreEqual(0, bs[1]); - Assert.AreEqual(66, bs[2]); - Assert.AreEqual(0, bs[3]); - } - - [Test] - public void IsEmptyWhenEmpty() - { - Assert.IsTrue(ByteString.CopyFromUtf8("").IsEmpty); - } - - [Test] - public void IsEmptyWhenNotEmpty() - { - Assert.IsFalse(ByteString.CopyFromUtf8("X").IsEmpty); - } - - [Test] - public void CopyFromByteArrayCopiesContents() - { - byte[] data = new byte[1]; - data[0] = 10; - ByteString bs = ByteString.CopyFrom(data); - Assert.AreEqual(10, bs[0]); - data[0] = 5; - Assert.AreEqual(10, bs[0]); - } - - [Test] - public void CopyFromReadOnlySpanCopiesContents() - { - byte[] data = new byte[1]; - data[0] = 10; - ReadOnlySpan byteSpan = data; - var bs = ByteString.CopyFrom(byteSpan); - Assert.AreEqual(10, bs[0]); - data[0] = 5; - Assert.AreEqual(10, bs[0]); - } - - [Test] - public void ToByteArrayCopiesContents() - { - ByteString bs = ByteString.CopyFromUtf8("Hello"); - byte[] data = bs.ToByteArray(); - Assert.AreEqual((byte)'H', data[0]); - Assert.AreEqual((byte)'H', bs[0]); - data[0] = 0; - Assert.AreEqual(0, data[0]); - Assert.AreEqual((byte)'H', bs[0]); - } - - [Test] - public void CopyFromUtf8UsesUtf8() - { - ByteString bs = ByteString.CopyFromUtf8("\u20ac"); - Assert.AreEqual(3, bs.Length); - Assert.AreEqual(0xe2, bs[0]); - Assert.AreEqual(0x82, bs[1]); - Assert.AreEqual(0xac, bs[2]); - } - - [Test] - public void CopyFromPortion() - { - byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6}; - ByteString bs = ByteString.CopyFrom(data, 2, 3); - Assert.AreEqual(3, bs.Length); - Assert.AreEqual(2, bs[0]); - Assert.AreEqual(3, bs[1]); - } - - [Test] - public void CopyTo() - { - byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6 }; - ByteString bs = ByteString.CopyFrom(data); - - byte[] dest = new byte[data.Length]; - bs.CopyTo(dest, 0); - - CollectionAssert.AreEqual(data, dest); - } - - [Test] - public void GetEnumerator() - { - byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6 }; - ByteString bs = ByteString.CopyFrom(data); - - IEnumerator genericEnumerator = bs.GetEnumerator(); - Assert.IsTrue(genericEnumerator.MoveNext()); - Assert.AreEqual(0, genericEnumerator.Current); - - IEnumerator enumerator = ((IEnumerable)bs).GetEnumerator(); - Assert.IsTrue(enumerator.MoveNext()); - Assert.AreEqual(0, enumerator.Current); - - // Call via LINQ - CollectionAssert.AreEqual(bs.Span.ToArray(), bs.ToArray()); - } - - [Test] - public void UnsafeWrap() - { - byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6 }; - ByteString bs = UnsafeByteOperations.UnsafeWrap(data.AsMemory(2, 3)); - ReadOnlySpan s = bs.Span; - - Assert.AreEqual(3, s.Length); - Assert.AreEqual(2, s[0]); - Assert.AreEqual(3, s[1]); - Assert.AreEqual(4, s[2]); - - // Check that the value is not a copy - data[2] = byte.MaxValue; - Assert.AreEqual(byte.MaxValue, s[0]); - } - - [Test] - public void CreateCodedInput_FromArraySegment() - { - byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6 }; - ByteString bs = UnsafeByteOperations.UnsafeWrap(data.AsMemory(2, 3)); - CodedInputStream codedInputStream = bs.CreateCodedInput(); - - byte[] bytes = codedInputStream.ReadRawBytes(3); - - Assert.AreEqual(3, bytes.Length); - Assert.AreEqual(2, bytes[0]); - Assert.AreEqual(3, bytes[1]); - Assert.AreEqual(4, bytes[2]); - Assert.IsTrue(codedInputStream.IsAtEnd); - } - - [Test] - public void WriteToStream() - { - byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6 }; - ByteString bs = ByteString.CopyFrom(data); - - MemoryStream ms = new MemoryStream(); - bs.WriteTo(ms); - - CollectionAssert.AreEqual(data, ms.ToArray()); - } - - [Test] - public void WriteToStream_Stackalloc() - { - byte[] data = Encoding.UTF8.GetBytes("Hello world"); - Span s = stackalloc byte[data.Length]; - data.CopyTo(s); - - MemoryStream ms = new MemoryStream(); - - using (UnmanagedMemoryManager manager = new UnmanagedMemoryManager(s)) - { - ByteString bs = ByteString.AttachBytes(manager.Memory); - - bs.WriteTo(ms); - } - - CollectionAssert.AreEqual(data, ms.ToArray()); - } - - [Test] - public void ToStringUtf8() - { - ByteString bs = ByteString.CopyFromUtf8("\u20ac"); - Assert.AreEqual("\u20ac", bs.ToStringUtf8()); - } - - [Test] - public void ToStringWithExplicitEncoding() - { - ByteString bs = ByteString.CopyFrom("\u20ac", Encoding.Unicode); - Assert.AreEqual("\u20ac", bs.ToString(Encoding.Unicode)); - } - - [Test] - public void ToString_Stackalloc() - { - byte[] data = Encoding.UTF8.GetBytes("Hello world"); - Span s = stackalloc byte[data.Length]; - data.CopyTo(s); - - using (UnmanagedMemoryManager manager = new UnmanagedMemoryManager(s)) - { - ByteString bs = ByteString.AttachBytes(manager.Memory); - - Assert.AreEqual("Hello world", bs.ToString(Encoding.UTF8)); - } - } - - [Test] - public void FromBase64_WithText() - { - byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6}; - string base64 = Convert.ToBase64String(data); - ByteString bs = ByteString.FromBase64(base64); - Assert.AreEqual(data, bs.ToByteArray()); - } - - [Test] - public void FromBase64_Empty() - { - // Optimization which also fixes issue 61. - Assert.AreSame(ByteString.Empty, ByteString.FromBase64("")); - } - - [Test] - public void ToBase64_Array() - { - ByteString bs = ByteString.CopyFrom(Encoding.UTF8.GetBytes("Hello world")); - - Assert.AreEqual("SGVsbG8gd29ybGQ=", bs.ToBase64()); - } - - [Test] - public void ToBase64_Stackalloc() - { - byte[] data = Encoding.UTF8.GetBytes("Hello world"); - Span s = stackalloc byte[data.Length]; - data.CopyTo(s); - - using (UnmanagedMemoryManager manager = new UnmanagedMemoryManager(s)) - { - ByteString bs = ByteString.AttachBytes(manager.Memory); - - Assert.AreEqual("SGVsbG8gd29ybGQ=", bs.ToBase64()); - } - } - - [Test] - public void FromStream_Seekable() - { - var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }); - // Consume the first byte, just to test that it's "from current position" - stream.ReadByte(); - var actual = ByteString.FromStream(stream); - ByteString expected = ByteString.CopyFrom(2, 3, 4, 5); - Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}"); - } - - [Test] - public void FromStream_NotSeekable() - { - var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }); - // Consume the first byte, just to test that it's "from current position" - stream.ReadByte(); - // Wrap the original stream in LimitedInputStream, which has CanSeek=false - var limitedStream = new LimitedInputStream(stream, 3); - var actual = ByteString.FromStream(limitedStream); - ByteString expected = ByteString.CopyFrom(2, 3, 4); - Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}"); - } - -#if !NET35 - [Test] - public async Task FromStreamAsync_Seekable() - { - var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }); - // Consume the first byte, just to test that it's "from current position" - stream.ReadByte(); - var actual = await ByteString.FromStreamAsync(stream); - ByteString expected = ByteString.CopyFrom(2, 3, 4, 5); - Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}"); - } - - [Test] - public async Task FromStreamAsync_NotSeekable() - { - var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }); - // Consume the first byte, just to test that it's "from current position" - stream.ReadByte(); - // Wrap the original stream in LimitedInputStream, which has CanSeek=false - var limitedStream = new LimitedInputStream(stream, 3); - var actual = await ByteString.FromStreamAsync(limitedStream); - ByteString expected = ByteString.CopyFrom(2, 3, 4); - Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}"); - } -#endif - - [Test] - public void GetHashCode_Regression() - { - // We used to have an awful hash algorithm where only the last four - // bytes were relevant. This is a regression test for - // https://github.com/protocolbuffers/protobuf/issues/2511 - - ByteString b1 = ByteString.CopyFrom(100, 1, 2, 3, 4); - ByteString b2 = ByteString.CopyFrom(200, 1, 2, 3, 4); - Assert.AreNotEqual(b1.GetHashCode(), b2.GetHashCode()); - } - - [Test] - public void GetContentsAsReadOnlySpan() - { - var byteString = ByteString.CopyFrom(1, 2, 3, 4, 5); - var copied = byteString.Span.ToArray(); - CollectionAssert.AreEqual(byteString, copied); - } - - [Test] - public void GetContentsAsReadOnlyMemory() - { - var byteString = ByteString.CopyFrom(1, 2, 3, 4, 5); - var copied = byteString.Memory.ToArray(); - CollectionAssert.AreEqual(byteString, copied); - } - - // Create Memory from non-array source. - // Use by ByteString tests that have optimized path for array backed Memory. - private sealed unsafe class UnmanagedMemoryManager : MemoryManager where T : unmanaged - { - private readonly T* _pointer; - private readonly int _length; - - public UnmanagedMemoryManager(Span span) - { - fixed (T* ptr = &MemoryMarshal.GetReference(span)) - { - _pointer = ptr; - _length = span.Length; - } - } - - public override Span GetSpan() => new Span(_pointer, _length); - - public override MemoryHandle Pin(int elementIndex = 0) - { - if (elementIndex < 0 || elementIndex >= _length) - { - throw new ArgumentOutOfRangeException(nameof(elementIndex)); - } - - return new MemoryHandle(_pointer + elementIndex); - } - - public override void Unpin() { } - - protected override void Dispose(bool disposing) { } - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.Text; +using NUnit.Framework; +using System.IO; +using System.Collections.Generic; +using System.Collections; +using System.Linq; +using System.Buffers; +using System.Runtime.InteropServices; +using System.Threading; +using System.Runtime.CompilerServices; +#if !NET35 +using System.Threading.Tasks; +#endif + +namespace Google.Protobuf +{ + public class ByteStringTest + { + [Test] + public void Equality() + { + ByteString b1 = ByteString.CopyFrom(1, 2, 3); + ByteString b2 = ByteString.CopyFrom(1, 2, 3); + ByteString b3 = ByteString.CopyFrom(1, 2, 4); + ByteString b4 = ByteString.CopyFrom(1, 2, 3, 4); + EqualityTester.AssertEquality(b1, b1); + EqualityTester.AssertEquality(b1, b2); + EqualityTester.AssertInequality(b1, b3); + EqualityTester.AssertInequality(b1, b4); + EqualityTester.AssertInequality(b1, null); + EqualityTester.AssertEquality(ByteString.Empty, ByteString.Empty); +#pragma warning disable 1718 // Deliberately calling ==(b1, b1) and !=(b1, b1) + Assert.IsTrue(b1 == b1); + Assert.IsTrue(b1 == b2); + Assert.IsFalse(b1 == b3); + Assert.IsFalse(b1 == b4); + Assert.IsFalse(b1 == null); + Assert.IsTrue((ByteString) null == null); + Assert.IsFalse(b1 != b1); + Assert.IsFalse(b1 != b2); + Assert.IsTrue(ByteString.Empty == ByteString.Empty); +#pragma warning disable 1718 + Assert.IsTrue(b1 != b3); + Assert.IsTrue(b1 != b4); + Assert.IsTrue(b1 != null); + Assert.IsFalse((ByteString) null != null); + } + + [Test] + public void EmptyByteStringHasZeroSize() + { + Assert.AreEqual(0, ByteString.Empty.Length); + } + + [Test] + public void CopyFromStringWithExplicitEncoding() + { + ByteString bs = ByteString.CopyFrom("AB", Encoding.Unicode); + Assert.AreEqual(4, bs.Length); + Assert.AreEqual(65, bs[0]); + Assert.AreEqual(0, bs[1]); + Assert.AreEqual(66, bs[2]); + Assert.AreEqual(0, bs[3]); + } + + [Test] + public void IsEmptyWhenEmpty() + { + Assert.IsTrue(ByteString.CopyFromUtf8("").IsEmpty); + } + + [Test] + public void IsEmptyWhenNotEmpty() + { + Assert.IsFalse(ByteString.CopyFromUtf8("X").IsEmpty); + } + + [Test] + public void CopyFromByteArrayCopiesContents() + { + byte[] data = new byte[1]; + data[0] = 10; + ByteString bs = ByteString.CopyFrom(data); + Assert.AreEqual(10, bs[0]); + data[0] = 5; + Assert.AreEqual(10, bs[0]); + } + + [Test] + public void CopyFromReadOnlySpanCopiesContents() + { + byte[] data = new byte[1]; + data[0] = 10; + ReadOnlySpan byteSpan = data; + var bs = ByteString.CopyFrom(byteSpan); + Assert.AreEqual(10, bs[0]); + data[0] = 5; + Assert.AreEqual(10, bs[0]); + } + + [Test] + public void ToByteArrayCopiesContents() + { + ByteString bs = ByteString.CopyFromUtf8("Hello"); + byte[] data = bs.ToByteArray(); + Assert.AreEqual((byte)'H', data[0]); + Assert.AreEqual((byte)'H', bs[0]); + data[0] = 0; + Assert.AreEqual(0, data[0]); + Assert.AreEqual((byte)'H', bs[0]); + } + + [Test] + public void CopyFromUtf8UsesUtf8() + { + ByteString bs = ByteString.CopyFromUtf8("\u20ac"); + Assert.AreEqual(3, bs.Length); + Assert.AreEqual(0xe2, bs[0]); + Assert.AreEqual(0x82, bs[1]); + Assert.AreEqual(0xac, bs[2]); + } + + [Test] + public void CopyFromPortion() + { + byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6}; + ByteString bs = ByteString.CopyFrom(data, 2, 3); + Assert.AreEqual(3, bs.Length); + Assert.AreEqual(2, bs[0]); + Assert.AreEqual(3, bs[1]); + } + + [Test] + public void CopyTo() + { + byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6 }; + ByteString bs = ByteString.CopyFrom(data); + + byte[] dest = new byte[data.Length]; + bs.CopyTo(dest, 0); + + CollectionAssert.AreEqual(data, dest); + } + + [Test] + public void GetEnumerator() + { + byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6 }; + ByteString bs = ByteString.CopyFrom(data); + + IEnumerator genericEnumerator = bs.GetEnumerator(); + Assert.IsTrue(genericEnumerator.MoveNext()); + Assert.AreEqual(0, genericEnumerator.Current); + + IEnumerator enumerator = ((IEnumerable)bs).GetEnumerator(); + Assert.IsTrue(enumerator.MoveNext()); + Assert.AreEqual(0, enumerator.Current); + + // Call via LINQ + CollectionAssert.AreEqual(bs.Span.ToArray(), bs.ToArray()); + } + + [Test] + public void UnsafeWrap() + { + byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6 }; + ByteString bs = UnsafeByteOperations.UnsafeWrap(data.AsMemory(2, 3)); + ReadOnlySpan s = bs.Span; + + Assert.AreEqual(3, s.Length); + Assert.AreEqual(2, s[0]); + Assert.AreEqual(3, s[1]); + Assert.AreEqual(4, s[2]); + + // Check that the value is not a copy + data[2] = byte.MaxValue; + Assert.AreEqual(byte.MaxValue, s[0]); + } + + [Test] + public void CreateCodedInput_FromArraySegment() + { + byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6 }; + ByteString bs = UnsafeByteOperations.UnsafeWrap(data.AsMemory(2, 3)); + CodedInputStream codedInputStream = bs.CreateCodedInput(); + + byte[] bytes = codedInputStream.ReadRawBytes(3); + + Assert.AreEqual(3, bytes.Length); + Assert.AreEqual(2, bytes[0]); + Assert.AreEqual(3, bytes[1]); + Assert.AreEqual(4, bytes[2]); + Assert.IsTrue(codedInputStream.IsAtEnd); + } + + [Test] + public void WriteToStream() + { + byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6 }; + ByteString bs = ByteString.CopyFrom(data); + + MemoryStream ms = new MemoryStream(); + bs.WriteTo(ms); + + CollectionAssert.AreEqual(data, ms.ToArray()); + } + + [Test] + public void WriteToStream_Stackalloc() + { + byte[] data = Encoding.UTF8.GetBytes("Hello world"); + Span s = stackalloc byte[data.Length]; + data.CopyTo(s); + + MemoryStream ms = new MemoryStream(); + + using (UnmanagedMemoryManager manager = new UnmanagedMemoryManager(s)) + { + ByteString bs = ByteString.AttachBytes(manager.Memory); + + bs.WriteTo(ms); + } + + CollectionAssert.AreEqual(data, ms.ToArray()); + } + + [Test] + public void ToStringUtf8() + { + ByteString bs = ByteString.CopyFromUtf8("\u20ac"); + Assert.AreEqual("\u20ac", bs.ToStringUtf8()); + } + + [Test] + public void ToStringWithExplicitEncoding() + { + ByteString bs = ByteString.CopyFrom("\u20ac", Encoding.Unicode); + Assert.AreEqual("\u20ac", bs.ToString(Encoding.Unicode)); + } + + [Test] + public void ToString_Stackalloc() + { + byte[] data = Encoding.UTF8.GetBytes("Hello world"); + Span s = stackalloc byte[data.Length]; + data.CopyTo(s); + + using (UnmanagedMemoryManager manager = new UnmanagedMemoryManager(s)) + { + ByteString bs = ByteString.AttachBytes(manager.Memory); + + Assert.AreEqual("Hello world", bs.ToString(Encoding.UTF8)); + } + } + + [Test] + public void FromBase64_WithText() + { + byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6}; + string base64 = Convert.ToBase64String(data); + ByteString bs = ByteString.FromBase64(base64); + Assert.AreEqual(data, bs.ToByteArray()); + } + + [Test] + public void FromBase64_Empty() + { + // Optimization which also fixes issue 61. + Assert.AreSame(ByteString.Empty, ByteString.FromBase64("")); + } + + [Test] + public void ToBase64_Array() + { + ByteString bs = ByteString.CopyFrom(Encoding.UTF8.GetBytes("Hello world")); + + Assert.AreEqual("SGVsbG8gd29ybGQ=", bs.ToBase64()); + } + + [Test] + public void ToBase64_Stackalloc() + { + byte[] data = Encoding.UTF8.GetBytes("Hello world"); + Span s = stackalloc byte[data.Length]; + data.CopyTo(s); + + using (UnmanagedMemoryManager manager = new UnmanagedMemoryManager(s)) + { + ByteString bs = ByteString.AttachBytes(manager.Memory); + + Assert.AreEqual("SGVsbG8gd29ybGQ=", bs.ToBase64()); + } + } + + [Test] + public void FromStream_Seekable() + { + var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }); + // Consume the first byte, just to test that it's "from current position" + stream.ReadByte(); + var actual = ByteString.FromStream(stream); + ByteString expected = ByteString.CopyFrom(2, 3, 4, 5); + Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}"); + } + + [Test] + public void FromStream_NotSeekable() + { + var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }); + // Consume the first byte, just to test that it's "from current position" + stream.ReadByte(); + // Wrap the original stream in LimitedInputStream, which has CanSeek=false + var limitedStream = new LimitedInputStream(stream, 3); + var actual = ByteString.FromStream(limitedStream); + ByteString expected = ByteString.CopyFrom(2, 3, 4); + Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}"); + } + +#if !NET35 + [Test] + public async Task FromStreamAsync_Seekable() + { + var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }); + // Consume the first byte, just to test that it's "from current position" + stream.ReadByte(); + var actual = await ByteString.FromStreamAsync(stream); + ByteString expected = ByteString.CopyFrom(2, 3, 4, 5); + Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}"); + } + + [Test] + public async Task FromStreamAsync_NotSeekable() + { + var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }); + // Consume the first byte, just to test that it's "from current position" + stream.ReadByte(); + // Wrap the original stream in LimitedInputStream, which has CanSeek=false + var limitedStream = new LimitedInputStream(stream, 3); + var actual = await ByteString.FromStreamAsync(limitedStream); + ByteString expected = ByteString.CopyFrom(2, 3, 4); + Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}"); + } +#endif + + [Test] + public void GetHashCode_Regression() + { + // We used to have an awful hash algorithm where only the last four + // bytes were relevant. This is a regression test for + // https://github.com/protocolbuffers/protobuf/issues/2511 + + ByteString b1 = ByteString.CopyFrom(100, 1, 2, 3, 4); + ByteString b2 = ByteString.CopyFrom(200, 1, 2, 3, 4); + Assert.AreNotEqual(b1.GetHashCode(), b2.GetHashCode()); + } + + [Test] + public void GetContentsAsReadOnlySpan() + { + var byteString = ByteString.CopyFrom(1, 2, 3, 4, 5); + var copied = byteString.Span.ToArray(); + CollectionAssert.AreEqual(byteString, copied); + } + + [Test] + public void GetContentsAsReadOnlyMemory() + { + var byteString = ByteString.CopyFrom(1, 2, 3, 4, 5); + var copied = byteString.Memory.ToArray(); + CollectionAssert.AreEqual(byteString, copied); + } + + // Create Memory from non-array source. + // Use by ByteString tests that have optimized path for array backed Memory. + private sealed unsafe class UnmanagedMemoryManager : MemoryManager where T : unmanaged + { + private readonly T* _pointer; + private readonly int _length; + + public UnmanagedMemoryManager(Span span) + { + fixed (T* ptr = &MemoryMarshal.GetReference(span)) + { + _pointer = ptr; + _length = span.Length; + } + } + + public override Span GetSpan() => new Span(_pointer, _length); + + public override MemoryHandle Pin(int elementIndex = 0) + { + if (elementIndex < 0 || elementIndex >= _length) + { + throw new ArgumentOutOfRangeException(nameof(elementIndex)); + } + + return new MemoryHandle(_pointer + elementIndex); + } + + public override void Unpin() { } + + protected override void Dispose(bool disposing) { } + } + } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs b/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs index 234155975aa6..b84a1b7ce65f 100644 --- a/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs +++ b/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs @@ -1,1008 +1,1008 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.Buffers; -using System.IO; -using Google.Protobuf.TestProtos; -using Proto2 = Google.Protobuf.TestProtos.Proto2; -using NUnit.Framework; - -namespace Google.Protobuf -{ - public class CodedInputStreamTest - { - /// - /// Helper to construct a byte array from a bunch of bytes. The inputs are - /// actually ints so that I can use hex notation and not get stupid errors - /// about precision. - /// - private static byte[] Bytes(params int[] bytesAsInts) - { - byte[] bytes = new byte[bytesAsInts.Length]; - for (int i = 0; i < bytesAsInts.Length; i++) - { - bytes[i] = (byte) bytesAsInts[i]; - } - return bytes; - } - - /// - /// Parses the given bytes using ReadRawVarint32() and ReadRawVarint64() - /// - private static void AssertReadVarint(byte[] data, ulong value) - { - CodedInputStream input = new CodedInputStream(data); - Assert.AreEqual((uint) value, input.ReadRawVarint32()); - Assert.IsTrue(input.IsAtEnd); - - input = new CodedInputStream(data); - Assert.AreEqual(value, input.ReadRawVarint64()); - Assert.IsTrue(input.IsAtEnd); - - AssertReadFromParseContext(new ReadOnlySequence(data), (ref ParseContext ctx) => - { - Assert.AreEqual((uint) value, ctx.ReadUInt32()); - }, true); - - AssertReadFromParseContext(new ReadOnlySequence(data), (ref ParseContext ctx) => - { - Assert.AreEqual(value, ctx.ReadUInt64()); - }, true); - - // Try different block sizes. - for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2) - { - input = new CodedInputStream(new SmallBlockInputStream(data, bufferSize)); - Assert.AreEqual((uint) value, input.ReadRawVarint32()); - - input = new CodedInputStream(new SmallBlockInputStream(data, bufferSize)); - Assert.AreEqual(value, input.ReadRawVarint64()); - Assert.IsTrue(input.IsAtEnd); - - AssertReadFromParseContext(ReadOnlySequenceFactory.CreateWithContent(data, bufferSize), (ref ParseContext ctx) => - { - Assert.AreEqual((uint) value, ctx.ReadUInt32()); - }, true); - - AssertReadFromParseContext(ReadOnlySequenceFactory.CreateWithContent(data, bufferSize), (ref ParseContext ctx) => - { - Assert.AreEqual(value, ctx.ReadUInt64()); - }, true); - } - - // Try reading directly from a MemoryStream. We want to verify that it - // doesn't read past the end of the input, so write an extra byte - this - // lets us test the position at the end. - MemoryStream memoryStream = new MemoryStream(); - memoryStream.Write(data, 0, data.Length); - memoryStream.WriteByte(0); - memoryStream.Position = 0; - Assert.AreEqual((uint) value, CodedInputStream.ReadRawVarint32(memoryStream)); - Assert.AreEqual(data.Length, memoryStream.Position); - } - - /// - /// Parses the given bytes using ReadRawVarint32() and ReadRawVarint64() and - /// expects them to fail with an InvalidProtocolBufferException whose - /// description matches the given one. - /// - private static void AssertReadVarintFailure(InvalidProtocolBufferException expected, byte[] data) - { - CodedInputStream input = new CodedInputStream(data); - var exception = Assert.Throws(() => input.ReadRawVarint32()); - Assert.AreEqual(expected.Message, exception.Message); - - input = new CodedInputStream(data); - exception = Assert.Throws(() => input.ReadRawVarint64()); - Assert.AreEqual(expected.Message, exception.Message); - - AssertReadFromParseContext(new ReadOnlySequence(data), (ref ParseContext ctx) => - { - try - { - ctx.ReadUInt32(); - Assert.Fail(); - } - catch (InvalidProtocolBufferException ex) - { - Assert.AreEqual(expected.Message, ex.Message); - } - }, false); - - AssertReadFromParseContext(new ReadOnlySequence(data), (ref ParseContext ctx) => - { - try - { - ctx.ReadUInt64(); - Assert.Fail(); - } - catch (InvalidProtocolBufferException ex) - { - Assert.AreEqual(expected.Message, ex.Message); - } - }, false); - - // Make sure we get the same error when reading directly from a Stream. - exception = Assert.Throws(() => CodedInputStream.ReadRawVarint32(new MemoryStream(data))); - Assert.AreEqual(expected.Message, exception.Message); - } - - private delegate void ParseContextAssertAction(ref ParseContext ctx); - - private static void AssertReadFromParseContext(ReadOnlySequence input, ParseContextAssertAction assertAction, bool assertIsAtEnd) - { - // Check as ReadOnlySequence - ParseContext.Initialize(input, out ParseContext parseCtx); - assertAction(ref parseCtx); - if (assertIsAtEnd) - { - Assert.IsTrue(SegmentedBufferHelper.IsAtEnd(ref parseCtx.buffer, ref parseCtx.state)); - } - - // Check as ReadOnlySpan - ParseContext.Initialize(input.ToArray().AsSpan(), out ParseContext spanParseContext); - assertAction(ref spanParseContext); - if (assertIsAtEnd) - { - Assert.IsTrue(SegmentedBufferHelper.IsAtEnd(ref spanParseContext.buffer, ref spanParseContext.state)); - } - } - - [Test] - public void ReadVarint() - { - AssertReadVarint(Bytes(0x00), 0); - AssertReadVarint(Bytes(0x01), 1); - AssertReadVarint(Bytes(0x7f), 127); - // 14882 - AssertReadVarint(Bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7)); - // 2961488830 - AssertReadVarint(Bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b), - (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | - (0x0bL << 28)); - - // 64-bit - // 7256456126 - AssertReadVarint(Bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b), - (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | - (0x1bL << 28)); - // 41256202580718336 - AssertReadVarint(Bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49), - (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | - (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49)); - // 11964378330978735131 - AssertReadVarint(Bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01), - (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | - (0x3bUL << 28) | (0x56UL << 35) | (0x00UL << 42) | - (0x05UL << 49) | (0x26UL << 56) | (0x01UL << 63)); - - // Failures - AssertReadVarintFailure( - InvalidProtocolBufferException.MalformedVarint(), - Bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x00)); - AssertReadVarintFailure( - InvalidProtocolBufferException.TruncatedMessage(), - Bytes(0x80)); - } - - /// - /// Parses the given bytes using ReadRawLittleEndian32() and checks - /// that the result matches the given value. - /// - private static void AssertReadLittleEndian32(byte[] data, uint value) - { - CodedInputStream input = new CodedInputStream(data); - Assert.AreEqual(value, input.ReadRawLittleEndian32()); - Assert.IsTrue(input.IsAtEnd); - - AssertReadFromParseContext(new ReadOnlySequence(data), (ref ParseContext ctx) => - { - Assert.AreEqual(value, ctx.ReadFixed32()); - }, true); - - // Try different block sizes. - for (int blockSize = 1; blockSize <= 16; blockSize *= 2) - { - input = new CodedInputStream( - new SmallBlockInputStream(data, blockSize)); - Assert.AreEqual(value, input.ReadRawLittleEndian32()); - Assert.IsTrue(input.IsAtEnd); - - AssertReadFromParseContext(ReadOnlySequenceFactory.CreateWithContent(data, blockSize), (ref ParseContext ctx) => - { - Assert.AreEqual(value, ctx.ReadFixed32()); - }, true); - } - } - - /// - /// Parses the given bytes using ReadRawLittleEndian64() and checks - /// that the result matches the given value. - /// - private static void AssertReadLittleEndian64(byte[] data, ulong value) - { - CodedInputStream input = new CodedInputStream(data); - Assert.AreEqual(value, input.ReadRawLittleEndian64()); - Assert.IsTrue(input.IsAtEnd); - - AssertReadFromParseContext(new ReadOnlySequence(data), (ref ParseContext ctx) => - { - Assert.AreEqual(value, ctx.ReadFixed64()); - }, true); - - // Try different block sizes. - for (int blockSize = 1; blockSize <= 16; blockSize *= 2) - { - input = new CodedInputStream( - new SmallBlockInputStream(data, blockSize)); - Assert.AreEqual(value, input.ReadRawLittleEndian64()); - Assert.IsTrue(input.IsAtEnd); - - AssertReadFromParseContext(ReadOnlySequenceFactory.CreateWithContent(data, blockSize), (ref ParseContext ctx) => - { - Assert.AreEqual(value, ctx.ReadFixed64()); - }, true); - } - } - - [Test] - public void ReadLittleEndian() - { - AssertReadLittleEndian32(Bytes(0x78, 0x56, 0x34, 0x12), 0x12345678); - AssertReadLittleEndian32(Bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0); - - AssertReadLittleEndian64(Bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12), - 0x123456789abcdef0L); - AssertReadLittleEndian64( - Bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef012345678UL); - } - - [Test] - public void DecodeZigZag32() - { - Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag32(0)); - Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag32(1)); - Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag32(2)); - Assert.AreEqual(-2, ParsingPrimitives.DecodeZigZag32(3)); - Assert.AreEqual(0x3FFFFFFF, ParsingPrimitives.DecodeZigZag32(0x7FFFFFFE)); - Assert.AreEqual(unchecked((int) 0xC0000000), ParsingPrimitives.DecodeZigZag32(0x7FFFFFFF)); - Assert.AreEqual(0x7FFFFFFF, ParsingPrimitives.DecodeZigZag32(0xFFFFFFFE)); - Assert.AreEqual(unchecked((int) 0x80000000), ParsingPrimitives.DecodeZigZag32(0xFFFFFFFF)); - } - - [Test] - public void DecodeZigZag64() - { - Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag64(0)); - Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag64(1)); - Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag64(2)); - Assert.AreEqual(-2, ParsingPrimitives.DecodeZigZag64(3)); - Assert.AreEqual(0x000000003FFFFFFFL, ParsingPrimitives.DecodeZigZag64(0x000000007FFFFFFEL)); - Assert.AreEqual(unchecked((long) 0xFFFFFFFFC0000000L), ParsingPrimitives.DecodeZigZag64(0x000000007FFFFFFFL)); - Assert.AreEqual(0x000000007FFFFFFFL, ParsingPrimitives.DecodeZigZag64(0x00000000FFFFFFFEL)); - Assert.AreEqual(unchecked((long) 0xFFFFFFFF80000000L), ParsingPrimitives.DecodeZigZag64(0x00000000FFFFFFFFL)); - Assert.AreEqual(0x7FFFFFFFFFFFFFFFL, ParsingPrimitives.DecodeZigZag64(0xFFFFFFFFFFFFFFFEL)); - Assert.AreEqual(unchecked((long) 0x8000000000000000L), ParsingPrimitives.DecodeZigZag64(0xFFFFFFFFFFFFFFFFL)); - } - - [Test] - public void ReadWholeMessage_VaryingBlockSizes() - { - TestAllTypes message = SampleMessages.CreateFullTestAllTypes(); - - byte[] rawBytes = message.ToByteArray(); - Assert.AreEqual(rawBytes.Length, message.CalculateSize()); - TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(rawBytes); - Assert.AreEqual(message, message2); - - // Try different block sizes. - for (int blockSize = 1; blockSize < 256; blockSize *= 2) - { - message2 = TestAllTypes.Parser.ParseFrom(new SmallBlockInputStream(rawBytes, blockSize)); - Assert.AreEqual(message, message2); - } - } - - [Test] - public void ReadWholeMessage_VaryingBlockSizes_FromSequence() - { - TestAllTypes message = SampleMessages.CreateFullTestAllTypes(); - - byte[] rawBytes = message.ToByteArray(); - Assert.AreEqual(rawBytes.Length, message.CalculateSize()); - TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(rawBytes); - Assert.AreEqual(message, message2); - - // Try different block sizes. - for (int blockSize = 1; blockSize < 256; blockSize *= 2) - { - message2 = TestAllTypes.Parser.ParseFrom(ReadOnlySequenceFactory.CreateWithContent(rawBytes, blockSize)); - Assert.AreEqual(message, message2); - } - } - - [Test] - public void ReadInt32Wrapper_VariableBlockSizes() - { - byte[] rawBytes = new byte[] { 202, 1, 11, 8, 254, 255, 255, 255, 255, 255, 255, 255, 255, 1 }; - - for (int blockSize = 1; blockSize <= rawBytes.Length; blockSize++) - { - ReadOnlySequence data = ReadOnlySequenceFactory.CreateWithContent(rawBytes, blockSize); - AssertReadFromParseContext(data, (ref ParseContext ctx) => - { - ctx.ReadTag(); - - var value = ParsingPrimitivesWrappers.ReadInt32Wrapper(ref ctx); - - Assert.AreEqual(-2, value); - }, true); - } - } - - [Test] - public void ReadHugeBlob() - { - // Allocate and initialize a 1MB blob. - byte[] blob = new byte[1 << 20]; - for (int i = 0; i < blob.Length; i++) - { - blob[i] = (byte) i; - } - - // Make a message containing it. - var message = new TestAllTypes { SingleBytes = ByteString.CopyFrom(blob) }; - - // Serialize and parse it. Make sure to parse from an InputStream, not - // directly from a ByteString, so that CodedInputStream uses buffered - // reading. - TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(message.ToByteString()); - - Assert.AreEqual(message, message2); - } - - [Test] - public void ReadMaliciouslyLargeBlob() - { - MemoryStream ms = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(ms); - - uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); - output.WriteRawVarint32(tag); - output.WriteRawVarint32(0x7FFFFFFF); - output.WriteRawBytes(new byte[32]); // Pad with a few random bytes. - output.Flush(); - ms.Position = 0; - - CodedInputStream input = new CodedInputStream(ms); - Assert.AreEqual(tag, input.ReadTag()); - - Assert.Throws(() => input.ReadBytes()); - } - - [Test] - public void ReadBlobGreaterThanCurrentLimit() - { - MemoryStream ms = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(ms); - uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); - output.WriteRawVarint32(tag); - output.WriteRawVarint32(4); - output.WriteRawBytes(new byte[4]); // Pad with a few random bytes. - output.Flush(); - ms.Position = 0; - - CodedInputStream input = new CodedInputStream(ms); - Assert.AreEqual(tag, input.ReadTag()); - - // Specify limit smaller than data length - input.PushLimit(3); - Assert.Throws(() => input.ReadBytes()); - - AssertReadFromParseContext(new ReadOnlySequence(ms.ToArray()), (ref ParseContext ctx) => - { - Assert.AreEqual(tag, ctx.ReadTag()); - SegmentedBufferHelper.PushLimit(ref ctx.state, 3); - try - { - ctx.ReadBytes(); - Assert.Fail(); - } - catch (InvalidProtocolBufferException) {} - }, true); - } - - [Test] - public void ReadStringGreaterThanCurrentLimit() - { - MemoryStream ms = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(ms); - uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); - output.WriteRawVarint32(tag); - output.WriteRawVarint32(4); - output.WriteRawBytes(new byte[4]); // Pad with a few random bytes. - output.Flush(); - ms.Position = 0; - - CodedInputStream input = new CodedInputStream(ms.ToArray()); - Assert.AreEqual(tag, input.ReadTag()); - - // Specify limit smaller than data length - input.PushLimit(3); - Assert.Throws(() => input.ReadString()); - - AssertReadFromParseContext(new ReadOnlySequence(ms.ToArray()), (ref ParseContext ctx) => - { - Assert.AreEqual(tag, ctx.ReadTag()); - SegmentedBufferHelper.PushLimit(ref ctx.state, 3); - try - { - ctx.ReadString(); - Assert.Fail(); - } - catch (InvalidProtocolBufferException) { } - }, true); - } - - // Representations of a tag for field 0 with various wire types - [Test] - [TestCase(0)] - [TestCase(1)] - [TestCase(2)] - [TestCase(3)] - [TestCase(4)] - [TestCase(5)] - public void ReadTag_ZeroFieldRejected(byte tag) - { - CodedInputStream cis = new CodedInputStream(new byte[] { tag }); - Assert.Throws(() => cis.ReadTag()); - } - - internal static TestRecursiveMessage MakeRecursiveMessage(int depth) - { - if (depth == 0) - { - return new TestRecursiveMessage { I = 5 }; - } - else - { - return new TestRecursiveMessage { A = MakeRecursiveMessage(depth - 1) }; - } - } - - internal static void AssertMessageDepth(TestRecursiveMessage message, int depth) - { - if (depth == 0) - { - Assert.IsNull(message.A); - Assert.AreEqual(5, message.I); - } - else - { - Assert.IsNotNull(message.A); - AssertMessageDepth(message.A, depth - 1); - } - } - - [Test] - public void MaliciousRecursion() - { - ByteString atRecursiveLimit = MakeRecursiveMessage(CodedInputStream.DefaultRecursionLimit).ToByteString(); - ByteString beyondRecursiveLimit = MakeRecursiveMessage(CodedInputStream.DefaultRecursionLimit + 1).ToByteString(); - - AssertMessageDepth(TestRecursiveMessage.Parser.ParseFrom(atRecursiveLimit), CodedInputStream.DefaultRecursionLimit); - - Assert.Throws(() => TestRecursiveMessage.Parser.ParseFrom(beyondRecursiveLimit)); - - CodedInputStream input = CodedInputStream.CreateWithLimits(new MemoryStream(atRecursiveLimit.ToByteArray()), 1000000, CodedInputStream.DefaultRecursionLimit - 1); - Assert.Throws(() => TestRecursiveMessage.Parser.ParseFrom(input)); - } - - private static byte[] MakeMaliciousRecursionUnknownFieldsPayload(int recursionDepth) - { - // generate recursively nested groups that will be parsed as unknown fields - int unknownFieldNumber = 14; // an unused field number - MemoryStream ms = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(ms); - for (int i = 0; i < recursionDepth; i++) - { - output.WriteTag(WireFormat.MakeTag(unknownFieldNumber, WireFormat.WireType.StartGroup)); - } - for (int i = 0; i < recursionDepth; i++) - { - output.WriteTag(WireFormat.MakeTag(unknownFieldNumber, WireFormat.WireType.EndGroup)); - } - output.Flush(); - return ms.ToArray(); - } - - [Test] - public void MaliciousRecursion_UnknownFields() - { - byte[] payloadAtRecursiveLimit = MakeMaliciousRecursionUnknownFieldsPayload(CodedInputStream.DefaultRecursionLimit); - byte[] payloadBeyondRecursiveLimit = MakeMaliciousRecursionUnknownFieldsPayload(CodedInputStream.DefaultRecursionLimit + 1); - - Assert.DoesNotThrow(() => TestRecursiveMessage.Parser.ParseFrom(payloadAtRecursiveLimit)); - Assert.Throws(() => TestRecursiveMessage.Parser.ParseFrom(payloadBeyondRecursiveLimit)); - } - - [Test] - public void ReadGroup_WrongEndGroupTag() - { - int groupFieldNumber = Proto2.TestAllTypes.OptionalGroupFieldNumber; - - // write Proto2.TestAllTypes with "optional_group" set, but use wrong EndGroup closing tag - MemoryStream ms = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(ms); - output.WriteTag(WireFormat.MakeTag(groupFieldNumber, WireFormat.WireType.StartGroup)); - output.WriteGroup(new Proto2.TestAllTypes.Types.OptionalGroup { A = 12345 }); - // end group with different field number - output.WriteTag(WireFormat.MakeTag(groupFieldNumber + 1, WireFormat.WireType.EndGroup)); - output.Flush(); - var payload = ms.ToArray(); - - Assert.Throws(() => Proto2.TestAllTypes.Parser.ParseFrom(payload)); - } - - [Test] - public void ReadGroup_UnknownFields_WrongEndGroupTag() - { - MemoryStream ms = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(ms); - output.WriteTag(WireFormat.MakeTag(14, WireFormat.WireType.StartGroup)); - // end group with different field number - output.WriteTag(WireFormat.MakeTag(15, WireFormat.WireType.EndGroup)); - output.Flush(); - var payload = ms.ToArray(); - - Assert.Throws(() => TestRecursiveMessage.Parser.ParseFrom(payload)); - } - - [Test] - public void SizeLimit() - { - // Have to use a Stream rather than ByteString.CreateCodedInput as SizeLimit doesn't - // apply to the latter case. - MemoryStream ms = new MemoryStream(SampleMessages.CreateFullTestAllTypes().ToByteArray()); - CodedInputStream input = CodedInputStream.CreateWithLimits(ms, 16, 100); - Assert.Throws(() => TestAllTypes.Parser.ParseFrom(input)); - } - - /// - /// Tests that if we read an string that contains invalid UTF-8, no exception - /// is thrown. Instead, the invalid bytes are replaced with the Unicode - /// "replacement character" U+FFFD. - /// - [Test] - public void ReadInvalidUtf8() - { - MemoryStream ms = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(ms); - - uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); - output.WriteRawVarint32(tag); - output.WriteRawVarint32(1); - output.WriteRawBytes(new byte[] {0x80}); - output.Flush(); - ms.Position = 0; - - CodedInputStream input = new CodedInputStream(ms); - - Assert.AreEqual(tag, input.ReadTag()); - string text = input.ReadString(); - Assert.AreEqual('\ufffd', text[0]); - } - - [Test] - public void ReadNegativeSizedStringThrowsInvalidProtocolBufferException() - { - MemoryStream ms = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(ms); - - uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); - output.WriteRawVarint32(tag); - output.WriteLength(-1); - output.Flush(); - ms.Position = 0; - - CodedInputStream input = new CodedInputStream(ms); - - Assert.AreEqual(tag, input.ReadTag()); - Assert.Throws(() => input.ReadString()); - } - - [Test] - public void ReadNegativeSizedBytesThrowsInvalidProtocolBufferException() - { - MemoryStream ms = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(ms); - - uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); - output.WriteRawVarint32(tag); - output.WriteLength(-1); - output.Flush(); - ms.Position = 0; - - CodedInputStream input = new CodedInputStream(ms); - - Assert.AreEqual(tag, input.ReadTag()); - Assert.Throws(() => input.ReadBytes()); - } - - /// - /// A stream which limits the number of bytes it reads at a time. - /// We use this to make sure that CodedInputStream doesn't screw up when - /// reading in small blocks. - /// - private sealed class SmallBlockInputStream : MemoryStream - { - private readonly int blockSize; - - public SmallBlockInputStream(byte[] data, int blockSize) - : base(data) - { - this.blockSize = blockSize; - } - - public override int Read(byte[] buffer, int offset, int count) - { - return base.Read(buffer, offset, Math.Min(count, blockSize)); - } - } - - [Test] - public void TestNegativeEnum() - { - byte[] bytes = { 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01 }; - CodedInputStream input = new CodedInputStream(bytes); - Assert.AreEqual((int)SampleEnum.NegativeValue, input.ReadEnum()); - Assert.IsTrue(input.IsAtEnd); - } - - //Issue 71: CodedInputStream.ReadBytes go to slow path unnecessarily - [Test] - public void TestSlowPathAvoidance() - { - using (var ms = new MemoryStream()) - { - CodedOutputStream output = new CodedOutputStream(ms); - output.WriteTag(1, WireFormat.WireType.LengthDelimited); - output.WriteBytes(ByteString.CopyFrom(new byte[100])); - output.WriteTag(2, WireFormat.WireType.LengthDelimited); - output.WriteBytes(ByteString.CopyFrom(new byte[100])); - output.Flush(); - - ms.Position = 0; - CodedInputStream input = new CodedInputStream(ms, new byte[ms.Length / 2], 0, 0, false); - - uint tag = input.ReadTag(); - Assert.AreEqual(1, WireFormat.GetTagFieldNumber(tag)); - Assert.AreEqual(100, input.ReadBytes().Length); - - tag = input.ReadTag(); - Assert.AreEqual(2, WireFormat.GetTagFieldNumber(tag)); - Assert.AreEqual(100, input.ReadBytes().Length); - } - } - - [Test] - public void MaximumFieldNumber() - { - MemoryStream ms = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(ms); - - int fieldNumber = 0x1FFFFFFF; - uint tag = WireFormat.MakeTag(fieldNumber, WireFormat.WireType.LengthDelimited); - output.WriteRawVarint32(tag); - output.WriteString("field 1"); - output.Flush(); - ms.Position = 0; - - CodedInputStream input = new CodedInputStream(ms); - - Assert.AreEqual(tag, input.ReadTag()); - Assert.AreEqual(fieldNumber, WireFormat.GetTagFieldNumber(tag)); - } - - [Test] - public void Tag0Throws() - { - var input = new CodedInputStream(new byte[] { 0 }); - Assert.Throws(() => input.ReadTag()); - } - - [Test] - public void SkipGroup() - { - // Create an output stream with a group in: - // Field 1: string "field 1" - // Field 2: group containing: - // Field 1: fixed int32 value 100 - // Field 2: string "ignore me" - // Field 3: nested group containing - // Field 1: fixed int64 value 1000 - // Field 3: string "field 3" - var stream = new MemoryStream(); - var output = new CodedOutputStream(stream); - output.WriteTag(1, WireFormat.WireType.LengthDelimited); - output.WriteString("field 1"); - - // The outer group... - output.WriteTag(2, WireFormat.WireType.StartGroup); - output.WriteTag(1, WireFormat.WireType.Fixed32); - output.WriteFixed32(100); - output.WriteTag(2, WireFormat.WireType.LengthDelimited); - output.WriteString("ignore me"); - // The nested group... - output.WriteTag(3, WireFormat.WireType.StartGroup); - output.WriteTag(1, WireFormat.WireType.Fixed64); - output.WriteFixed64(1000); - // Note: Not sure the field number is relevant for end group... - output.WriteTag(3, WireFormat.WireType.EndGroup); - - // End the outer group - output.WriteTag(2, WireFormat.WireType.EndGroup); - - output.WriteTag(3, WireFormat.WireType.LengthDelimited); - output.WriteString("field 3"); - output.Flush(); - stream.Position = 0; - - // Now act like a generated client - var input = new CodedInputStream(stream); - Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited), input.ReadTag()); - Assert.AreEqual("field 1", input.ReadString()); - Assert.AreEqual(WireFormat.MakeTag(2, WireFormat.WireType.StartGroup), input.ReadTag()); - input.SkipLastField(); // Should consume the whole group, including the nested one. - Assert.AreEqual(WireFormat.MakeTag(3, WireFormat.WireType.LengthDelimited), input.ReadTag()); - Assert.AreEqual("field 3", input.ReadString()); - } - - [Test] - public void SkipGroup_WrongEndGroupTag() - { - // Create an output stream with: - // Field 1: string "field 1" - // Start group 2 - // Field 3: fixed int32 - // End group 4 (should give an error) - var stream = new MemoryStream(); - var output = new CodedOutputStream(stream); - output.WriteTag(1, WireFormat.WireType.LengthDelimited); - output.WriteString("field 1"); - - // The outer group... - output.WriteTag(2, WireFormat.WireType.StartGroup); - output.WriteTag(3, WireFormat.WireType.Fixed32); - output.WriteFixed32(100); - output.WriteTag(4, WireFormat.WireType.EndGroup); - output.Flush(); - stream.Position = 0; - - // Now act like a generated client - var input = new CodedInputStream(stream); - Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited), input.ReadTag()); - Assert.AreEqual("field 1", input.ReadString()); - Assert.AreEqual(WireFormat.MakeTag(2, WireFormat.WireType.StartGroup), input.ReadTag()); - Assert.Throws(input.SkipLastField); - } - - [Test] - public void RogueEndGroupTag() - { - // If we have an end-group tag without a leading start-group tag, generated - // code will just call SkipLastField... so that should fail. - - var stream = new MemoryStream(); - var output = new CodedOutputStream(stream); - output.WriteTag(1, WireFormat.WireType.EndGroup); - output.Flush(); - stream.Position = 0; - - var input = new CodedInputStream(stream); - Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.EndGroup), input.ReadTag()); - Assert.Throws(input.SkipLastField); - } - - [Test] - public void EndOfStreamReachedWhileSkippingGroup() - { - var stream = new MemoryStream(); - var output = new CodedOutputStream(stream); - output.WriteTag(1, WireFormat.WireType.StartGroup); - output.WriteTag(2, WireFormat.WireType.StartGroup); - output.WriteTag(2, WireFormat.WireType.EndGroup); - - output.Flush(); - stream.Position = 0; - - // Now act like a generated client - var input = new CodedInputStream(stream); - input.ReadTag(); - Assert.Throws(input.SkipLastField); - } - - [Test] - public void RecursionLimitAppliedWhileSkippingGroup() - { - var stream = new MemoryStream(); - var output = new CodedOutputStream(stream); - for (int i = 0; i < CodedInputStream.DefaultRecursionLimit + 1; i++) - { - output.WriteTag(1, WireFormat.WireType.StartGroup); - } - for (int i = 0; i < CodedInputStream.DefaultRecursionLimit + 1; i++) - { - output.WriteTag(1, WireFormat.WireType.EndGroup); - } - output.Flush(); - stream.Position = 0; - - // Now act like a generated client - var input = new CodedInputStream(stream); - Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.StartGroup), input.ReadTag()); - Assert.Throws(input.SkipLastField); - } - - [Test] - public void Construction_Invalid() - { - Assert.Throws(() => new CodedInputStream((byte[]) null)); - Assert.Throws(() => new CodedInputStream(null, 0, 0)); - Assert.Throws(() => new CodedInputStream((Stream) null)); - Assert.Throws(() => new CodedInputStream(new byte[10], 100, 0)); - Assert.Throws(() => new CodedInputStream(new byte[10], 5, 10)); - } - - [Test] - public void CreateWithLimits_InvalidLimits() - { - var stream = new MemoryStream(); - Assert.Throws(() => CodedInputStream.CreateWithLimits(stream, 0, 1)); - Assert.Throws(() => CodedInputStream.CreateWithLimits(stream, 1, 0)); - } - - [Test] - public void Dispose_DisposesUnderlyingStream() - { - var memoryStream = new MemoryStream(); - Assert.IsTrue(memoryStream.CanRead); - using (var cis = new CodedInputStream(memoryStream)) - { - } - Assert.IsFalse(memoryStream.CanRead); // Disposed - } - - [Test] - public void Dispose_WithLeaveOpen() - { - var memoryStream = new MemoryStream(); - Assert.IsTrue(memoryStream.CanRead); - using (var cis = new CodedInputStream(memoryStream, true)) - { - } - Assert.IsTrue(memoryStream.CanRead); // We left the stream open - } - - [Test] - public void Dispose_FromByteArray() - { - var stream = new CodedInputStream(new byte[10]); - stream.Dispose(); - } - - [Test] - public void TestParseMessagesCloseTo2G() - { - byte[] serializedMessage = GenerateBigSerializedMessage(); - // How many of these big messages do we need to take us near our 2GB limit? - int count = Int32.MaxValue / serializedMessage.Length; - // Now make a MemoryStream that will fake a near-2GB stream of messages by returning - // our big serialized message 'count' times. - using (RepeatingMemoryStream stream = new RepeatingMemoryStream(serializedMessage, count)) - { - Assert.DoesNotThrow(()=>TestAllTypes.Parser.ParseFrom(stream)); - } - } - - [Test] - public void TestParseMessagesOver2G() - { - byte[] serializedMessage = GenerateBigSerializedMessage(); - // How many of these big messages do we need to take us near our 2GB limit? - int count = Int32.MaxValue / serializedMessage.Length; - // Now add one to take us over the 2GB limit - count++; - // Now make a MemoryStream that will fake a near-2GB stream of messages by returning - // our big serialized message 'count' times. - using (RepeatingMemoryStream stream = new RepeatingMemoryStream(serializedMessage, count)) - { - Assert.Throws(() => TestAllTypes.Parser.ParseFrom(stream), - "Protocol message was too large. May be malicious. " + - "Use CodedInputStream.SetSizeLimit() to increase the size limit."); - } - } - - /// A serialized big message - private static byte[] GenerateBigSerializedMessage() - { - byte[] value = new byte[16 * 1024 * 1024]; - TestAllTypes message = SampleMessages.CreateFullTestAllTypes(); - message.SingleBytes = ByteString.CopyFrom(value); - return message.ToByteArray(); - } - - /// - /// A MemoryStream that repeats a byte arrays' content a number of times. - /// Simulates really large input without consuming loads of memory. Used above - /// to test the parsing behavior when the input size exceeds 2GB or close to it. - /// - private class RepeatingMemoryStream: MemoryStream - { - private readonly byte[] bytes; - private readonly int maxIterations; - private int index = 0; - - public RepeatingMemoryStream(byte[] bytes, int maxIterations) - { - this.bytes = bytes; - this.maxIterations = maxIterations; - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (bytes.Length == 0) - { - return 0; - } - int numBytesCopiedTotal = 0; - while (numBytesCopiedTotal < count && index < maxIterations) - { - int numBytesToCopy = Math.Min(bytes.Length - (int)Position, count); - Array.Copy(bytes, (int)Position, buffer, offset, numBytesToCopy); - numBytesCopiedTotal += numBytesToCopy; - offset += numBytesToCopy; - count -= numBytesCopiedTotal; - Position += numBytesToCopy; - if (Position >= bytes.Length) - { - Position = 0; - index++; - } - } - return numBytesCopiedTotal; - } - } - } -} +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.Buffers; +using System.IO; +using Google.Protobuf.TestProtos; +using Proto2 = Google.Protobuf.TestProtos.Proto2; +using NUnit.Framework; + +namespace Google.Protobuf +{ + public class CodedInputStreamTest + { + /// + /// Helper to construct a byte array from a bunch of bytes. The inputs are + /// actually ints so that I can use hex notation and not get stupid errors + /// about precision. + /// + private static byte[] Bytes(params int[] bytesAsInts) + { + byte[] bytes = new byte[bytesAsInts.Length]; + for (int i = 0; i < bytesAsInts.Length; i++) + { + bytes[i] = (byte) bytesAsInts[i]; + } + return bytes; + } + + /// + /// Parses the given bytes using ReadRawVarint32() and ReadRawVarint64() + /// + private static void AssertReadVarint(byte[] data, ulong value) + { + CodedInputStream input = new CodedInputStream(data); + Assert.AreEqual((uint) value, input.ReadRawVarint32()); + Assert.IsTrue(input.IsAtEnd); + + input = new CodedInputStream(data); + Assert.AreEqual(value, input.ReadRawVarint64()); + Assert.IsTrue(input.IsAtEnd); + + AssertReadFromParseContext(new ReadOnlySequence(data), (ref ParseContext ctx) => + { + Assert.AreEqual((uint) value, ctx.ReadUInt32()); + }, true); + + AssertReadFromParseContext(new ReadOnlySequence(data), (ref ParseContext ctx) => + { + Assert.AreEqual(value, ctx.ReadUInt64()); + }, true); + + // Try different block sizes. + for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2) + { + input = new CodedInputStream(new SmallBlockInputStream(data, bufferSize)); + Assert.AreEqual((uint) value, input.ReadRawVarint32()); + + input = new CodedInputStream(new SmallBlockInputStream(data, bufferSize)); + Assert.AreEqual(value, input.ReadRawVarint64()); + Assert.IsTrue(input.IsAtEnd); + + AssertReadFromParseContext(ReadOnlySequenceFactory.CreateWithContent(data, bufferSize), (ref ParseContext ctx) => + { + Assert.AreEqual((uint) value, ctx.ReadUInt32()); + }, true); + + AssertReadFromParseContext(ReadOnlySequenceFactory.CreateWithContent(data, bufferSize), (ref ParseContext ctx) => + { + Assert.AreEqual(value, ctx.ReadUInt64()); + }, true); + } + + // Try reading directly from a MemoryStream. We want to verify that it + // doesn't read past the end of the input, so write an extra byte - this + // lets us test the position at the end. + MemoryStream memoryStream = new MemoryStream(); + memoryStream.Write(data, 0, data.Length); + memoryStream.WriteByte(0); + memoryStream.Position = 0; + Assert.AreEqual((uint) value, CodedInputStream.ReadRawVarint32(memoryStream)); + Assert.AreEqual(data.Length, memoryStream.Position); + } + + /// + /// Parses the given bytes using ReadRawVarint32() and ReadRawVarint64() and + /// expects them to fail with an InvalidProtocolBufferException whose + /// description matches the given one. + /// + private static void AssertReadVarintFailure(InvalidProtocolBufferException expected, byte[] data) + { + CodedInputStream input = new CodedInputStream(data); + var exception = Assert.Throws(() => input.ReadRawVarint32()); + Assert.AreEqual(expected.Message, exception.Message); + + input = new CodedInputStream(data); + exception = Assert.Throws(() => input.ReadRawVarint64()); + Assert.AreEqual(expected.Message, exception.Message); + + AssertReadFromParseContext(new ReadOnlySequence(data), (ref ParseContext ctx) => + { + try + { + ctx.ReadUInt32(); + Assert.Fail(); + } + catch (InvalidProtocolBufferException ex) + { + Assert.AreEqual(expected.Message, ex.Message); + } + }, false); + + AssertReadFromParseContext(new ReadOnlySequence(data), (ref ParseContext ctx) => + { + try + { + ctx.ReadUInt64(); + Assert.Fail(); + } + catch (InvalidProtocolBufferException ex) + { + Assert.AreEqual(expected.Message, ex.Message); + } + }, false); + + // Make sure we get the same error when reading directly from a Stream. + exception = Assert.Throws(() => CodedInputStream.ReadRawVarint32(new MemoryStream(data))); + Assert.AreEqual(expected.Message, exception.Message); + } + + private delegate void ParseContextAssertAction(ref ParseContext ctx); + + private static void AssertReadFromParseContext(ReadOnlySequence input, ParseContextAssertAction assertAction, bool assertIsAtEnd) + { + // Check as ReadOnlySequence + ParseContext.Initialize(input, out ParseContext parseCtx); + assertAction(ref parseCtx); + if (assertIsAtEnd) + { + Assert.IsTrue(SegmentedBufferHelper.IsAtEnd(ref parseCtx.buffer, ref parseCtx.state)); + } + + // Check as ReadOnlySpan + ParseContext.Initialize(input.ToArray().AsSpan(), out ParseContext spanParseContext); + assertAction(ref spanParseContext); + if (assertIsAtEnd) + { + Assert.IsTrue(SegmentedBufferHelper.IsAtEnd(ref spanParseContext.buffer, ref spanParseContext.state)); + } + } + + [Test] + public void ReadVarint() + { + AssertReadVarint(Bytes(0x00), 0); + AssertReadVarint(Bytes(0x01), 1); + AssertReadVarint(Bytes(0x7f), 127); + // 14882 + AssertReadVarint(Bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7)); + // 2961488830 + AssertReadVarint(Bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b), + (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | + (0x0bL << 28)); + + // 64-bit + // 7256456126 + AssertReadVarint(Bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b), + (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | + (0x1bL << 28)); + // 41256202580718336 + AssertReadVarint(Bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49), + (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | + (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49)); + // 11964378330978735131 + AssertReadVarint(Bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01), + (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | + (0x3bUL << 28) | (0x56UL << 35) | (0x00UL << 42) | + (0x05UL << 49) | (0x26UL << 56) | (0x01UL << 63)); + + // Failures + AssertReadVarintFailure( + InvalidProtocolBufferException.MalformedVarint(), + Bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x00)); + AssertReadVarintFailure( + InvalidProtocolBufferException.TruncatedMessage(), + Bytes(0x80)); + } + + /// + /// Parses the given bytes using ReadRawLittleEndian32() and checks + /// that the result matches the given value. + /// + private static void AssertReadLittleEndian32(byte[] data, uint value) + { + CodedInputStream input = new CodedInputStream(data); + Assert.AreEqual(value, input.ReadRawLittleEndian32()); + Assert.IsTrue(input.IsAtEnd); + + AssertReadFromParseContext(new ReadOnlySequence(data), (ref ParseContext ctx) => + { + Assert.AreEqual(value, ctx.ReadFixed32()); + }, true); + + // Try different block sizes. + for (int blockSize = 1; blockSize <= 16; blockSize *= 2) + { + input = new CodedInputStream( + new SmallBlockInputStream(data, blockSize)); + Assert.AreEqual(value, input.ReadRawLittleEndian32()); + Assert.IsTrue(input.IsAtEnd); + + AssertReadFromParseContext(ReadOnlySequenceFactory.CreateWithContent(data, blockSize), (ref ParseContext ctx) => + { + Assert.AreEqual(value, ctx.ReadFixed32()); + }, true); + } + } + + /// + /// Parses the given bytes using ReadRawLittleEndian64() and checks + /// that the result matches the given value. + /// + private static void AssertReadLittleEndian64(byte[] data, ulong value) + { + CodedInputStream input = new CodedInputStream(data); + Assert.AreEqual(value, input.ReadRawLittleEndian64()); + Assert.IsTrue(input.IsAtEnd); + + AssertReadFromParseContext(new ReadOnlySequence(data), (ref ParseContext ctx) => + { + Assert.AreEqual(value, ctx.ReadFixed64()); + }, true); + + // Try different block sizes. + for (int blockSize = 1; blockSize <= 16; blockSize *= 2) + { + input = new CodedInputStream( + new SmallBlockInputStream(data, blockSize)); + Assert.AreEqual(value, input.ReadRawLittleEndian64()); + Assert.IsTrue(input.IsAtEnd); + + AssertReadFromParseContext(ReadOnlySequenceFactory.CreateWithContent(data, blockSize), (ref ParseContext ctx) => + { + Assert.AreEqual(value, ctx.ReadFixed64()); + }, true); + } + } + + [Test] + public void ReadLittleEndian() + { + AssertReadLittleEndian32(Bytes(0x78, 0x56, 0x34, 0x12), 0x12345678); + AssertReadLittleEndian32(Bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0); + + AssertReadLittleEndian64(Bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12), + 0x123456789abcdef0L); + AssertReadLittleEndian64( + Bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef012345678UL); + } + + [Test] + public void DecodeZigZag32() + { + Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag32(0)); + Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag32(1)); + Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag32(2)); + Assert.AreEqual(-2, ParsingPrimitives.DecodeZigZag32(3)); + Assert.AreEqual(0x3FFFFFFF, ParsingPrimitives.DecodeZigZag32(0x7FFFFFFE)); + Assert.AreEqual(unchecked((int) 0xC0000000), ParsingPrimitives.DecodeZigZag32(0x7FFFFFFF)); + Assert.AreEqual(0x7FFFFFFF, ParsingPrimitives.DecodeZigZag32(0xFFFFFFFE)); + Assert.AreEqual(unchecked((int) 0x80000000), ParsingPrimitives.DecodeZigZag32(0xFFFFFFFF)); + } + + [Test] + public void DecodeZigZag64() + { + Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag64(0)); + Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag64(1)); + Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag64(2)); + Assert.AreEqual(-2, ParsingPrimitives.DecodeZigZag64(3)); + Assert.AreEqual(0x000000003FFFFFFFL, ParsingPrimitives.DecodeZigZag64(0x000000007FFFFFFEL)); + Assert.AreEqual(unchecked((long) 0xFFFFFFFFC0000000L), ParsingPrimitives.DecodeZigZag64(0x000000007FFFFFFFL)); + Assert.AreEqual(0x000000007FFFFFFFL, ParsingPrimitives.DecodeZigZag64(0x00000000FFFFFFFEL)); + Assert.AreEqual(unchecked((long) 0xFFFFFFFF80000000L), ParsingPrimitives.DecodeZigZag64(0x00000000FFFFFFFFL)); + Assert.AreEqual(0x7FFFFFFFFFFFFFFFL, ParsingPrimitives.DecodeZigZag64(0xFFFFFFFFFFFFFFFEL)); + Assert.AreEqual(unchecked((long) 0x8000000000000000L), ParsingPrimitives.DecodeZigZag64(0xFFFFFFFFFFFFFFFFL)); + } + + [Test] + public void ReadWholeMessage_VaryingBlockSizes() + { + TestAllTypes message = SampleMessages.CreateFullTestAllTypes(); + + byte[] rawBytes = message.ToByteArray(); + Assert.AreEqual(rawBytes.Length, message.CalculateSize()); + TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(rawBytes); + Assert.AreEqual(message, message2); + + // Try different block sizes. + for (int blockSize = 1; blockSize < 256; blockSize *= 2) + { + message2 = TestAllTypes.Parser.ParseFrom(new SmallBlockInputStream(rawBytes, blockSize)); + Assert.AreEqual(message, message2); + } + } + + [Test] + public void ReadWholeMessage_VaryingBlockSizes_FromSequence() + { + TestAllTypes message = SampleMessages.CreateFullTestAllTypes(); + + byte[] rawBytes = message.ToByteArray(); + Assert.AreEqual(rawBytes.Length, message.CalculateSize()); + TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(rawBytes); + Assert.AreEqual(message, message2); + + // Try different block sizes. + for (int blockSize = 1; blockSize < 256; blockSize *= 2) + { + message2 = TestAllTypes.Parser.ParseFrom(ReadOnlySequenceFactory.CreateWithContent(rawBytes, blockSize)); + Assert.AreEqual(message, message2); + } + } + + [Test] + public void ReadInt32Wrapper_VariableBlockSizes() + { + byte[] rawBytes = new byte[] { 202, 1, 11, 8, 254, 255, 255, 255, 255, 255, 255, 255, 255, 1 }; + + for (int blockSize = 1; blockSize <= rawBytes.Length; blockSize++) + { + ReadOnlySequence data = ReadOnlySequenceFactory.CreateWithContent(rawBytes, blockSize); + AssertReadFromParseContext(data, (ref ParseContext ctx) => + { + ctx.ReadTag(); + + var value = ParsingPrimitivesWrappers.ReadInt32Wrapper(ref ctx); + + Assert.AreEqual(-2, value); + }, true); + } + } + + [Test] + public void ReadHugeBlob() + { + // Allocate and initialize a 1MB blob. + byte[] blob = new byte[1 << 20]; + for (int i = 0; i < blob.Length; i++) + { + blob[i] = (byte) i; + } + + // Make a message containing it. + var message = new TestAllTypes { SingleBytes = ByteString.CopyFrom(blob) }; + + // Serialize and parse it. Make sure to parse from an InputStream, not + // directly from a ByteString, so that CodedInputStream uses buffered + // reading. + TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(message.ToByteString()); + + Assert.AreEqual(message, message2); + } + + [Test] + public void ReadMaliciouslyLargeBlob() + { + MemoryStream ms = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(ms); + + uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); + output.WriteRawVarint32(tag); + output.WriteRawVarint32(0x7FFFFFFF); + output.WriteRawBytes(new byte[32]); // Pad with a few random bytes. + output.Flush(); + ms.Position = 0; + + CodedInputStream input = new CodedInputStream(ms); + Assert.AreEqual(tag, input.ReadTag()); + + Assert.Throws(() => input.ReadBytes()); + } + + [Test] + public void ReadBlobGreaterThanCurrentLimit() + { + MemoryStream ms = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(ms); + uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); + output.WriteRawVarint32(tag); + output.WriteRawVarint32(4); + output.WriteRawBytes(new byte[4]); // Pad with a few random bytes. + output.Flush(); + ms.Position = 0; + + CodedInputStream input = new CodedInputStream(ms); + Assert.AreEqual(tag, input.ReadTag()); + + // Specify limit smaller than data length + input.PushLimit(3); + Assert.Throws(() => input.ReadBytes()); + + AssertReadFromParseContext(new ReadOnlySequence(ms.ToArray()), (ref ParseContext ctx) => + { + Assert.AreEqual(tag, ctx.ReadTag()); + SegmentedBufferHelper.PushLimit(ref ctx.state, 3); + try + { + ctx.ReadBytes(); + Assert.Fail(); + } + catch (InvalidProtocolBufferException) {} + }, true); + } + + [Test] + public void ReadStringGreaterThanCurrentLimit() + { + MemoryStream ms = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(ms); + uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); + output.WriteRawVarint32(tag); + output.WriteRawVarint32(4); + output.WriteRawBytes(new byte[4]); // Pad with a few random bytes. + output.Flush(); + ms.Position = 0; + + CodedInputStream input = new CodedInputStream(ms.ToArray()); + Assert.AreEqual(tag, input.ReadTag()); + + // Specify limit smaller than data length + input.PushLimit(3); + Assert.Throws(() => input.ReadString()); + + AssertReadFromParseContext(new ReadOnlySequence(ms.ToArray()), (ref ParseContext ctx) => + { + Assert.AreEqual(tag, ctx.ReadTag()); + SegmentedBufferHelper.PushLimit(ref ctx.state, 3); + try + { + ctx.ReadString(); + Assert.Fail(); + } + catch (InvalidProtocolBufferException) { } + }, true); + } + + // Representations of a tag for field 0 with various wire types + [Test] + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + [TestCase(3)] + [TestCase(4)] + [TestCase(5)] + public void ReadTag_ZeroFieldRejected(byte tag) + { + CodedInputStream cis = new CodedInputStream(new byte[] { tag }); + Assert.Throws(() => cis.ReadTag()); + } + + internal static TestRecursiveMessage MakeRecursiveMessage(int depth) + { + if (depth == 0) + { + return new TestRecursiveMessage { I = 5 }; + } + else + { + return new TestRecursiveMessage { A = MakeRecursiveMessage(depth - 1) }; + } + } + + internal static void AssertMessageDepth(TestRecursiveMessage message, int depth) + { + if (depth == 0) + { + Assert.IsNull(message.A); + Assert.AreEqual(5, message.I); + } + else + { + Assert.IsNotNull(message.A); + AssertMessageDepth(message.A, depth - 1); + } + } + + [Test] + public void MaliciousRecursion() + { + ByteString atRecursiveLimit = MakeRecursiveMessage(CodedInputStream.DefaultRecursionLimit).ToByteString(); + ByteString beyondRecursiveLimit = MakeRecursiveMessage(CodedInputStream.DefaultRecursionLimit + 1).ToByteString(); + + AssertMessageDepth(TestRecursiveMessage.Parser.ParseFrom(atRecursiveLimit), CodedInputStream.DefaultRecursionLimit); + + Assert.Throws(() => TestRecursiveMessage.Parser.ParseFrom(beyondRecursiveLimit)); + + CodedInputStream input = CodedInputStream.CreateWithLimits(new MemoryStream(atRecursiveLimit.ToByteArray()), 1000000, CodedInputStream.DefaultRecursionLimit - 1); + Assert.Throws(() => TestRecursiveMessage.Parser.ParseFrom(input)); + } + + private static byte[] MakeMaliciousRecursionUnknownFieldsPayload(int recursionDepth) + { + // generate recursively nested groups that will be parsed as unknown fields + int unknownFieldNumber = 14; // an unused field number + MemoryStream ms = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(ms); + for (int i = 0; i < recursionDepth; i++) + { + output.WriteTag(WireFormat.MakeTag(unknownFieldNumber, WireFormat.WireType.StartGroup)); + } + for (int i = 0; i < recursionDepth; i++) + { + output.WriteTag(WireFormat.MakeTag(unknownFieldNumber, WireFormat.WireType.EndGroup)); + } + output.Flush(); + return ms.ToArray(); + } + + [Test] + public void MaliciousRecursion_UnknownFields() + { + byte[] payloadAtRecursiveLimit = MakeMaliciousRecursionUnknownFieldsPayload(CodedInputStream.DefaultRecursionLimit); + byte[] payloadBeyondRecursiveLimit = MakeMaliciousRecursionUnknownFieldsPayload(CodedInputStream.DefaultRecursionLimit + 1); + + Assert.DoesNotThrow(() => TestRecursiveMessage.Parser.ParseFrom(payloadAtRecursiveLimit)); + Assert.Throws(() => TestRecursiveMessage.Parser.ParseFrom(payloadBeyondRecursiveLimit)); + } + + [Test] + public void ReadGroup_WrongEndGroupTag() + { + int groupFieldNumber = Proto2.TestAllTypes.OptionalGroupFieldNumber; + + // write Proto2.TestAllTypes with "optional_group" set, but use wrong EndGroup closing tag + MemoryStream ms = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(ms); + output.WriteTag(WireFormat.MakeTag(groupFieldNumber, WireFormat.WireType.StartGroup)); + output.WriteGroup(new Proto2.TestAllTypes.Types.OptionalGroup { A = 12345 }); + // end group with different field number + output.WriteTag(WireFormat.MakeTag(groupFieldNumber + 1, WireFormat.WireType.EndGroup)); + output.Flush(); + var payload = ms.ToArray(); + + Assert.Throws(() => Proto2.TestAllTypes.Parser.ParseFrom(payload)); + } + + [Test] + public void ReadGroup_UnknownFields_WrongEndGroupTag() + { + MemoryStream ms = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(ms); + output.WriteTag(WireFormat.MakeTag(14, WireFormat.WireType.StartGroup)); + // end group with different field number + output.WriteTag(WireFormat.MakeTag(15, WireFormat.WireType.EndGroup)); + output.Flush(); + var payload = ms.ToArray(); + + Assert.Throws(() => TestRecursiveMessage.Parser.ParseFrom(payload)); + } + + [Test] + public void SizeLimit() + { + // Have to use a Stream rather than ByteString.CreateCodedInput as SizeLimit doesn't + // apply to the latter case. + MemoryStream ms = new MemoryStream(SampleMessages.CreateFullTestAllTypes().ToByteArray()); + CodedInputStream input = CodedInputStream.CreateWithLimits(ms, 16, 100); + Assert.Throws(() => TestAllTypes.Parser.ParseFrom(input)); + } + + /// + /// Tests that if we read an string that contains invalid UTF-8, no exception + /// is thrown. Instead, the invalid bytes are replaced with the Unicode + /// "replacement character" U+FFFD. + /// + [Test] + public void ReadInvalidUtf8() + { + MemoryStream ms = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(ms); + + uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); + output.WriteRawVarint32(tag); + output.WriteRawVarint32(1); + output.WriteRawBytes(new byte[] {0x80}); + output.Flush(); + ms.Position = 0; + + CodedInputStream input = new CodedInputStream(ms); + + Assert.AreEqual(tag, input.ReadTag()); + string text = input.ReadString(); + Assert.AreEqual('\ufffd', text[0]); + } + + [Test] + public void ReadNegativeSizedStringThrowsInvalidProtocolBufferException() + { + MemoryStream ms = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(ms); + + uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); + output.WriteRawVarint32(tag); + output.WriteLength(-1); + output.Flush(); + ms.Position = 0; + + CodedInputStream input = new CodedInputStream(ms); + + Assert.AreEqual(tag, input.ReadTag()); + Assert.Throws(() => input.ReadString()); + } + + [Test] + public void ReadNegativeSizedBytesThrowsInvalidProtocolBufferException() + { + MemoryStream ms = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(ms); + + uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited); + output.WriteRawVarint32(tag); + output.WriteLength(-1); + output.Flush(); + ms.Position = 0; + + CodedInputStream input = new CodedInputStream(ms); + + Assert.AreEqual(tag, input.ReadTag()); + Assert.Throws(() => input.ReadBytes()); + } + + /// + /// A stream which limits the number of bytes it reads at a time. + /// We use this to make sure that CodedInputStream doesn't screw up when + /// reading in small blocks. + /// + private sealed class SmallBlockInputStream : MemoryStream + { + private readonly int blockSize; + + public SmallBlockInputStream(byte[] data, int blockSize) + : base(data) + { + this.blockSize = blockSize; + } + + public override int Read(byte[] buffer, int offset, int count) + { + return base.Read(buffer, offset, Math.Min(count, blockSize)); + } + } + + [Test] + public void TestNegativeEnum() + { + byte[] bytes = { 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01 }; + CodedInputStream input = new CodedInputStream(bytes); + Assert.AreEqual((int)SampleEnum.NegativeValue, input.ReadEnum()); + Assert.IsTrue(input.IsAtEnd); + } + + //Issue 71: CodedInputStream.ReadBytes go to slow path unnecessarily + [Test] + public void TestSlowPathAvoidance() + { + using (var ms = new MemoryStream()) + { + CodedOutputStream output = new CodedOutputStream(ms); + output.WriteTag(1, WireFormat.WireType.LengthDelimited); + output.WriteBytes(ByteString.CopyFrom(new byte[100])); + output.WriteTag(2, WireFormat.WireType.LengthDelimited); + output.WriteBytes(ByteString.CopyFrom(new byte[100])); + output.Flush(); + + ms.Position = 0; + CodedInputStream input = new CodedInputStream(ms, new byte[ms.Length / 2], 0, 0, false); + + uint tag = input.ReadTag(); + Assert.AreEqual(1, WireFormat.GetTagFieldNumber(tag)); + Assert.AreEqual(100, input.ReadBytes().Length); + + tag = input.ReadTag(); + Assert.AreEqual(2, WireFormat.GetTagFieldNumber(tag)); + Assert.AreEqual(100, input.ReadBytes().Length); + } + } + + [Test] + public void MaximumFieldNumber() + { + MemoryStream ms = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(ms); + + int fieldNumber = 0x1FFFFFFF; + uint tag = WireFormat.MakeTag(fieldNumber, WireFormat.WireType.LengthDelimited); + output.WriteRawVarint32(tag); + output.WriteString("field 1"); + output.Flush(); + ms.Position = 0; + + CodedInputStream input = new CodedInputStream(ms); + + Assert.AreEqual(tag, input.ReadTag()); + Assert.AreEqual(fieldNumber, WireFormat.GetTagFieldNumber(tag)); + } + + [Test] + public void Tag0Throws() + { + var input = new CodedInputStream(new byte[] { 0 }); + Assert.Throws(() => input.ReadTag()); + } + + [Test] + public void SkipGroup() + { + // Create an output stream with a group in: + // Field 1: string "field 1" + // Field 2: group containing: + // Field 1: fixed int32 value 100 + // Field 2: string "ignore me" + // Field 3: nested group containing + // Field 1: fixed int64 value 1000 + // Field 3: string "field 3" + var stream = new MemoryStream(); + var output = new CodedOutputStream(stream); + output.WriteTag(1, WireFormat.WireType.LengthDelimited); + output.WriteString("field 1"); + + // The outer group... + output.WriteTag(2, WireFormat.WireType.StartGroup); + output.WriteTag(1, WireFormat.WireType.Fixed32); + output.WriteFixed32(100); + output.WriteTag(2, WireFormat.WireType.LengthDelimited); + output.WriteString("ignore me"); + // The nested group... + output.WriteTag(3, WireFormat.WireType.StartGroup); + output.WriteTag(1, WireFormat.WireType.Fixed64); + output.WriteFixed64(1000); + // Note: Not sure the field number is relevant for end group... + output.WriteTag(3, WireFormat.WireType.EndGroup); + + // End the outer group + output.WriteTag(2, WireFormat.WireType.EndGroup); + + output.WriteTag(3, WireFormat.WireType.LengthDelimited); + output.WriteString("field 3"); + output.Flush(); + stream.Position = 0; + + // Now act like a generated client + var input = new CodedInputStream(stream); + Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited), input.ReadTag()); + Assert.AreEqual("field 1", input.ReadString()); + Assert.AreEqual(WireFormat.MakeTag(2, WireFormat.WireType.StartGroup), input.ReadTag()); + input.SkipLastField(); // Should consume the whole group, including the nested one. + Assert.AreEqual(WireFormat.MakeTag(3, WireFormat.WireType.LengthDelimited), input.ReadTag()); + Assert.AreEqual("field 3", input.ReadString()); + } + + [Test] + public void SkipGroup_WrongEndGroupTag() + { + // Create an output stream with: + // Field 1: string "field 1" + // Start group 2 + // Field 3: fixed int32 + // End group 4 (should give an error) + var stream = new MemoryStream(); + var output = new CodedOutputStream(stream); + output.WriteTag(1, WireFormat.WireType.LengthDelimited); + output.WriteString("field 1"); + + // The outer group... + output.WriteTag(2, WireFormat.WireType.StartGroup); + output.WriteTag(3, WireFormat.WireType.Fixed32); + output.WriteFixed32(100); + output.WriteTag(4, WireFormat.WireType.EndGroup); + output.Flush(); + stream.Position = 0; + + // Now act like a generated client + var input = new CodedInputStream(stream); + Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited), input.ReadTag()); + Assert.AreEqual("field 1", input.ReadString()); + Assert.AreEqual(WireFormat.MakeTag(2, WireFormat.WireType.StartGroup), input.ReadTag()); + Assert.Throws(input.SkipLastField); + } + + [Test] + public void RogueEndGroupTag() + { + // If we have an end-group tag without a leading start-group tag, generated + // code will just call SkipLastField... so that should fail. + + var stream = new MemoryStream(); + var output = new CodedOutputStream(stream); + output.WriteTag(1, WireFormat.WireType.EndGroup); + output.Flush(); + stream.Position = 0; + + var input = new CodedInputStream(stream); + Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.EndGroup), input.ReadTag()); + Assert.Throws(input.SkipLastField); + } + + [Test] + public void EndOfStreamReachedWhileSkippingGroup() + { + var stream = new MemoryStream(); + var output = new CodedOutputStream(stream); + output.WriteTag(1, WireFormat.WireType.StartGroup); + output.WriteTag(2, WireFormat.WireType.StartGroup); + output.WriteTag(2, WireFormat.WireType.EndGroup); + + output.Flush(); + stream.Position = 0; + + // Now act like a generated client + var input = new CodedInputStream(stream); + input.ReadTag(); + Assert.Throws(input.SkipLastField); + } + + [Test] + public void RecursionLimitAppliedWhileSkippingGroup() + { + var stream = new MemoryStream(); + var output = new CodedOutputStream(stream); + for (int i = 0; i < CodedInputStream.DefaultRecursionLimit + 1; i++) + { + output.WriteTag(1, WireFormat.WireType.StartGroup); + } + for (int i = 0; i < CodedInputStream.DefaultRecursionLimit + 1; i++) + { + output.WriteTag(1, WireFormat.WireType.EndGroup); + } + output.Flush(); + stream.Position = 0; + + // Now act like a generated client + var input = new CodedInputStream(stream); + Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.StartGroup), input.ReadTag()); + Assert.Throws(input.SkipLastField); + } + + [Test] + public void Construction_Invalid() + { + Assert.Throws(() => new CodedInputStream((byte[]) null)); + Assert.Throws(() => new CodedInputStream(null, 0, 0)); + Assert.Throws(() => new CodedInputStream((Stream) null)); + Assert.Throws(() => new CodedInputStream(new byte[10], 100, 0)); + Assert.Throws(() => new CodedInputStream(new byte[10], 5, 10)); + } + + [Test] + public void CreateWithLimits_InvalidLimits() + { + var stream = new MemoryStream(); + Assert.Throws(() => CodedInputStream.CreateWithLimits(stream, 0, 1)); + Assert.Throws(() => CodedInputStream.CreateWithLimits(stream, 1, 0)); + } + + [Test] + public void Dispose_DisposesUnderlyingStream() + { + var memoryStream = new MemoryStream(); + Assert.IsTrue(memoryStream.CanRead); + using (var cis = new CodedInputStream(memoryStream)) + { + } + Assert.IsFalse(memoryStream.CanRead); // Disposed + } + + [Test] + public void Dispose_WithLeaveOpen() + { + var memoryStream = new MemoryStream(); + Assert.IsTrue(memoryStream.CanRead); + using (var cis = new CodedInputStream(memoryStream, true)) + { + } + Assert.IsTrue(memoryStream.CanRead); // We left the stream open + } + + [Test] + public void Dispose_FromByteArray() + { + var stream = new CodedInputStream(new byte[10]); + stream.Dispose(); + } + + [Test] + public void TestParseMessagesCloseTo2G() + { + byte[] serializedMessage = GenerateBigSerializedMessage(); + // How many of these big messages do we need to take us near our 2GB limit? + int count = Int32.MaxValue / serializedMessage.Length; + // Now make a MemoryStream that will fake a near-2GB stream of messages by returning + // our big serialized message 'count' times. + using (RepeatingMemoryStream stream = new RepeatingMemoryStream(serializedMessage, count)) + { + Assert.DoesNotThrow(()=>TestAllTypes.Parser.ParseFrom(stream)); + } + } + + [Test] + public void TestParseMessagesOver2G() + { + byte[] serializedMessage = GenerateBigSerializedMessage(); + // How many of these big messages do we need to take us near our 2GB limit? + int count = Int32.MaxValue / serializedMessage.Length; + // Now add one to take us over the 2GB limit + count++; + // Now make a MemoryStream that will fake a near-2GB stream of messages by returning + // our big serialized message 'count' times. + using (RepeatingMemoryStream stream = new RepeatingMemoryStream(serializedMessage, count)) + { + Assert.Throws(() => TestAllTypes.Parser.ParseFrom(stream), + "Protocol message was too large. May be malicious. " + + "Use CodedInputStream.SetSizeLimit() to increase the size limit."); + } + } + + /// A serialized big message + private static byte[] GenerateBigSerializedMessage() + { + byte[] value = new byte[16 * 1024 * 1024]; + TestAllTypes message = SampleMessages.CreateFullTestAllTypes(); + message.SingleBytes = ByteString.CopyFrom(value); + return message.ToByteArray(); + } + + /// + /// A MemoryStream that repeats a byte arrays' content a number of times. + /// Simulates really large input without consuming loads of memory. Used above + /// to test the parsing behavior when the input size exceeds 2GB or close to it. + /// + private class RepeatingMemoryStream: MemoryStream + { + private readonly byte[] bytes; + private readonly int maxIterations; + private int index = 0; + + public RepeatingMemoryStream(byte[] bytes, int maxIterations) + { + this.bytes = bytes; + this.maxIterations = maxIterations; + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (bytes.Length == 0) + { + return 0; + } + int numBytesCopiedTotal = 0; + while (numBytesCopiedTotal < count && index < maxIterations) + { + int numBytesToCopy = Math.Min(bytes.Length - (int)Position, count); + Array.Copy(bytes, (int)Position, buffer, offset, numBytesToCopy); + numBytesCopiedTotal += numBytesToCopy; + offset += numBytesToCopy; + count -= numBytesCopiedTotal; + Position += numBytesToCopy; + if (Position >= bytes.Length) + { + Position = 0; + index++; + } + } + return numBytesCopiedTotal; + } + } + } +} diff --git a/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs b/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs index 14440098f136..13f83a2c3585 100644 --- a/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs +++ b/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs @@ -1,583 +1,583 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.IO; -using Google.Protobuf.TestProtos; -using Google.Protobuf.Buffers; -using NUnit.Framework; -using System.Text; - -namespace Google.Protobuf -{ - public class CodedOutputStreamTest - { - /// - /// Writes the given value using WriteRawVarint32() and WriteRawVarint64() and - /// checks that the result matches the given bytes - /// - private static void AssertWriteVarint(byte[] data, ulong value) - { - // Only do 32-bit write if the value fits in 32 bits. - if ((value >> 32) == 0) - { - // CodedOutputStream - MemoryStream rawOutput = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(rawOutput); - output.WriteRawVarint32((uint) value); - output.Flush(); - Assert.AreEqual(data, rawOutput.ToArray()); - - // IBufferWriter - var bufferWriter = new TestArrayBufferWriter(); - WriteContext.Initialize(bufferWriter, out WriteContext ctx); - ctx.WriteUInt32((uint) value); - ctx.Flush(); - Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray()); - - // Also try computing size. - Assert.AreEqual(data.Length, CodedOutputStream.ComputeRawVarint32Size((uint) value)); - } - - { - // CodedOutputStream - MemoryStream rawOutput = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(rawOutput); - output.WriteRawVarint64(value); - output.Flush(); - Assert.AreEqual(data, rawOutput.ToArray()); - - // IBufferWriter - var bufferWriter = new TestArrayBufferWriter(); - WriteContext.Initialize(bufferWriter, out WriteContext ctx); - ctx.WriteUInt64(value); - ctx.Flush(); - Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray()); - - // Also try computing size. - Assert.AreEqual(data.Length, CodedOutputStream.ComputeRawVarint64Size(value)); - } - - // Try different buffer sizes. - for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2) - { - // Only do 32-bit write if the value fits in 32 bits. - if ((value >> 32) == 0) - { - MemoryStream rawOutput = new MemoryStream(); - CodedOutputStream output = - new CodedOutputStream(rawOutput, bufferSize); - output.WriteRawVarint32((uint) value); - output.Flush(); - Assert.AreEqual(data, rawOutput.ToArray()); - - var bufferWriter = new TestArrayBufferWriter(); - bufferWriter.MaxGrowBy = bufferSize; - WriteContext.Initialize(bufferWriter, out WriteContext ctx); - ctx.WriteUInt32((uint) value); - ctx.Flush(); - Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray()); - } - - { - MemoryStream rawOutput = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(rawOutput, bufferSize); - output.WriteRawVarint64(value); - output.Flush(); - Assert.AreEqual(data, rawOutput.ToArray()); - - var bufferWriter = new TestArrayBufferWriter(); - bufferWriter.MaxGrowBy = bufferSize; - WriteContext.Initialize(bufferWriter, out WriteContext ctx); - ctx.WriteUInt64(value); - ctx.Flush(); - Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray()); - } - - } - } - - /// - /// Tests WriteRawVarint32() and WriteRawVarint64() - /// - [Test] - public void WriteVarint() - { - AssertWriteVarint(new byte[] {0x00}, 0); - AssertWriteVarint(new byte[] {0x01}, 1); - AssertWriteVarint(new byte[] {0x7f}, 127); - // 14882 - AssertWriteVarint(new byte[] {0xa2, 0x74}, (0x22 << 0) | (0x74 << 7)); - // 2961488830 - AssertWriteVarint(new byte[] {0xbe, 0xf7, 0x92, 0x84, 0x0b}, - (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | - (0x0bL << 28)); - - // 64-bit - // 7256456126 - AssertWriteVarint(new byte[] {0xbe, 0xf7, 0x92, 0x84, 0x1b}, - (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | - (0x1bL << 28)); - // 41256202580718336 - AssertWriteVarint( - new byte[] {0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49}, - (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | - (0x43UL << 28) | (0x49L << 35) | (0x24UL << 42) | (0x49UL << 49)); - // 11964378330978735131 - AssertWriteVarint( - new byte[] {0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01}, - unchecked((ulong) - ((0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | - (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) | - (0x05L << 49) | (0x26L << 56) | (0x01L << 63)))); - } - - /// - /// Parses the given bytes using WriteRawLittleEndian32() and checks - /// that the result matches the given value. - /// - private static void AssertWriteLittleEndian32(byte[] data, uint value) - { - { - var rawOutput = new MemoryStream(); - var output = new CodedOutputStream(rawOutput); - output.WriteRawLittleEndian32(value); - output.Flush(); - Assert.AreEqual(data, rawOutput.ToArray()); - - var bufferWriter = new TestArrayBufferWriter(); - WriteContext.Initialize(bufferWriter, out WriteContext ctx); - ctx.WriteFixed32(value); - ctx.Flush(); - Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray()); - } - - // Try different buffer sizes. - for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2) - { - var rawOutput = new MemoryStream(); - var output = new CodedOutputStream(rawOutput, bufferSize); - output.WriteRawLittleEndian32(value); - output.Flush(); - Assert.AreEqual(data, rawOutput.ToArray()); - - var bufferWriter = new TestArrayBufferWriter(); - bufferWriter.MaxGrowBy = bufferSize; - WriteContext.Initialize(bufferWriter, out WriteContext ctx); - ctx.WriteFixed32(value); - ctx.Flush(); - Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray()); - } - } - - /// - /// Parses the given bytes using WriteRawLittleEndian64() and checks - /// that the result matches the given value. - /// - private static void AssertWriteLittleEndian64(byte[] data, ulong value) - { - { - var rawOutput = new MemoryStream(); - var output = new CodedOutputStream(rawOutput); - output.WriteRawLittleEndian64(value); - output.Flush(); - Assert.AreEqual(data, rawOutput.ToArray()); - - var bufferWriter = new TestArrayBufferWriter(); - WriteContext.Initialize(bufferWriter, out WriteContext ctx); - ctx.WriteFixed64(value); - ctx.Flush(); - Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray()); - } - - // Try different block sizes. - for (int blockSize = 1; blockSize <= 16; blockSize *= 2) - { - var rawOutput = new MemoryStream(); - var output = new CodedOutputStream(rawOutput, blockSize); - output.WriteRawLittleEndian64(value); - output.Flush(); - Assert.AreEqual(data, rawOutput.ToArray()); - - var bufferWriter = new TestArrayBufferWriter(); - bufferWriter.MaxGrowBy = blockSize; - WriteContext.Initialize(bufferWriter, out WriteContext ctx); - ctx.WriteFixed64(value); - ctx.Flush(); - Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray()); - } - } - - /// - /// Tests writeRawLittleEndian32() and writeRawLittleEndian64(). - /// - [Test] - public void WriteLittleEndian() - { - AssertWriteLittleEndian32(new byte[] {0x78, 0x56, 0x34, 0x12}, 0x12345678); - AssertWriteLittleEndian32(new byte[] {0xf0, 0xde, 0xbc, 0x9a}, 0x9abcdef0); - - AssertWriteLittleEndian64( - new byte[] {0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12}, - 0x123456789abcdef0L); - AssertWriteLittleEndian64( - new byte[] {0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a}, - 0x9abcdef012345678UL); - } - - [Test] - public void WriteWholeMessage_VaryingBlockSizes() - { - TestAllTypes message = SampleMessages.CreateFullTestAllTypes(); - - byte[] rawBytes = message.ToByteArray(); - - // Try different block sizes. - for (int blockSize = 1; blockSize < 256; blockSize *= 2) - { - MemoryStream rawOutput = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(rawOutput, blockSize); - message.WriteTo(output); - output.Flush(); - Assert.AreEqual(rawBytes, rawOutput.ToArray()); - - var bufferWriter = new TestArrayBufferWriter(); - bufferWriter.MaxGrowBy = blockSize; - message.WriteTo(bufferWriter); - Assert.AreEqual(rawBytes, bufferWriter.WrittenSpan.ToArray()); - } - } - - [Test] - public void WriteContext_WritesWithFlushes() - { - TestAllTypes message = SampleMessages.CreateFullTestAllTypes(); - - MemoryStream expectedOutput = new MemoryStream(); - CodedOutputStream output = new CodedOutputStream(expectedOutput); - output.WriteMessage(message); - output.Flush(); - byte[] expectedBytes1 = expectedOutput.ToArray(); - - output.WriteMessage(message); - output.Flush(); - byte[] expectedBytes2 = expectedOutput.ToArray(); - - var bufferWriter = new TestArrayBufferWriter(); - WriteContext.Initialize(bufferWriter, out WriteContext ctx); - ctx.WriteMessage(message); - ctx.Flush(); - Assert.AreEqual(expectedBytes1, bufferWriter.WrittenSpan.ToArray()); - - ctx.WriteMessage(message); - ctx.Flush(); - Assert.AreEqual(expectedBytes2, bufferWriter.WrittenSpan.ToArray()); - } - - [Test] - public void EncodeZigZag32() - { - Assert.AreEqual(0u, WritingPrimitives.EncodeZigZag32(0)); - Assert.AreEqual(1u, WritingPrimitives.EncodeZigZag32(-1)); - Assert.AreEqual(2u, WritingPrimitives.EncodeZigZag32(1)); - Assert.AreEqual(3u, WritingPrimitives.EncodeZigZag32(-2)); - Assert.AreEqual(0x7FFFFFFEu, WritingPrimitives.EncodeZigZag32(0x3FFFFFFF)); - Assert.AreEqual(0x7FFFFFFFu, WritingPrimitives.EncodeZigZag32(unchecked((int) 0xC0000000))); - Assert.AreEqual(0xFFFFFFFEu, WritingPrimitives.EncodeZigZag32(0x7FFFFFFF)); - Assert.AreEqual(0xFFFFFFFFu, WritingPrimitives.EncodeZigZag32(unchecked((int) 0x80000000))); - } - - [Test] - public void EncodeZigZag64() - { - Assert.AreEqual(0u, WritingPrimitives.EncodeZigZag64(0)); - Assert.AreEqual(1u, WritingPrimitives.EncodeZigZag64(-1)); - Assert.AreEqual(2u, WritingPrimitives.EncodeZigZag64(1)); - Assert.AreEqual(3u, WritingPrimitives.EncodeZigZag64(-2)); - Assert.AreEqual(0x000000007FFFFFFEuL, - WritingPrimitives.EncodeZigZag64(unchecked((long) 0x000000003FFFFFFFUL))); - Assert.AreEqual(0x000000007FFFFFFFuL, - WritingPrimitives.EncodeZigZag64(unchecked((long) 0xFFFFFFFFC0000000UL))); - Assert.AreEqual(0x00000000FFFFFFFEuL, - WritingPrimitives.EncodeZigZag64(unchecked((long) 0x000000007FFFFFFFUL))); - Assert.AreEqual(0x00000000FFFFFFFFuL, - WritingPrimitives.EncodeZigZag64(unchecked((long) 0xFFFFFFFF80000000UL))); - Assert.AreEqual(0xFFFFFFFFFFFFFFFEL, - WritingPrimitives.EncodeZigZag64(unchecked((long) 0x7FFFFFFFFFFFFFFFUL))); - Assert.AreEqual(0xFFFFFFFFFFFFFFFFL, - WritingPrimitives.EncodeZigZag64(unchecked((long) 0x8000000000000000UL))); - } - - [Test] - public void RoundTripZigZag32() - { - // Some easier-to-verify round-trip tests. The inputs (other than 0, 1, -1) - // were chosen semi-randomly via keyboard bashing. - Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(0))); - Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(1))); - Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(-1))); - Assert.AreEqual(14927, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(14927))); - Assert.AreEqual(-3612, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(-3612))); - } - - [Test] - public void RoundTripZigZag64() - { - Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(0))); - Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(1))); - Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-1))); - Assert.AreEqual(14927, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(14927))); - Assert.AreEqual(-3612, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-3612))); - - Assert.AreEqual(856912304801416L, - ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(856912304801416L))); - Assert.AreEqual(-75123905439571256L, - ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-75123905439571256L))); - } - - [Test] - public void TestNegativeEnumNoTag() - { - Assert.AreEqual(10, CodedOutputStream.ComputeInt32Size(-2)); - Assert.AreEqual(10, CodedOutputStream.ComputeEnumSize((int) SampleEnum.NegativeValue)); - - byte[] bytes = new byte[10]; - CodedOutputStream output = new CodedOutputStream(bytes); - output.WriteEnum((int) SampleEnum.NegativeValue); - - Assert.AreEqual(0, output.SpaceLeft); - Assert.AreEqual("FE-FF-FF-FF-FF-FF-FF-FF-FF-01", BitConverter.ToString(bytes)); - } - - [Test] - public void TestCodedInputOutputPosition() - { - byte[] content = new byte[110]; - for (int i = 0; i < content.Length; i++) - content[i] = (byte)i; - - byte[] child = new byte[120]; - { - MemoryStream ms = new MemoryStream(child); - CodedOutputStream cout = new CodedOutputStream(ms, 20); - // Field 11: numeric value: 500 - cout.WriteTag(11, WireFormat.WireType.Varint); - Assert.AreEqual(1, cout.Position); - cout.WriteInt32(500); - Assert.AreEqual(3, cout.Position); - //Field 12: length delimited 120 bytes - cout.WriteTag(12, WireFormat.WireType.LengthDelimited); - Assert.AreEqual(4, cout.Position); - cout.WriteBytes(ByteString.CopyFrom(content)); - Assert.AreEqual(115, cout.Position); - // Field 13: fixed numeric value: 501 - cout.WriteTag(13, WireFormat.WireType.Fixed32); - Assert.AreEqual(116, cout.Position); - cout.WriteSFixed32(501); - Assert.AreEqual(120, cout.Position); - cout.Flush(); - } - - byte[] bytes = new byte[130]; - { - CodedOutputStream cout = new CodedOutputStream(bytes); - // Field 1: numeric value: 500 - cout.WriteTag(1, WireFormat.WireType.Varint); - Assert.AreEqual(1, cout.Position); - cout.WriteInt32(500); - Assert.AreEqual(3, cout.Position); - //Field 2: length delimited 120 bytes - cout.WriteTag(2, WireFormat.WireType.LengthDelimited); - Assert.AreEqual(4, cout.Position); - cout.WriteBytes(ByteString.CopyFrom(child)); - Assert.AreEqual(125, cout.Position); - // Field 3: fixed numeric value: 500 - cout.WriteTag(3, WireFormat.WireType.Fixed32); - Assert.AreEqual(126, cout.Position); - cout.WriteSFixed32(501); - Assert.AreEqual(130, cout.Position); - cout.Flush(); - } - // Now test Input stream: - { - CodedInputStream cin = new CodedInputStream(new MemoryStream(bytes), new byte[50], 0, 0, false); - Assert.AreEqual(0, cin.Position); - // Field 1: - uint tag = cin.ReadTag(); - Assert.AreEqual(1, tag >> 3); - Assert.AreEqual(1, cin.Position); - Assert.AreEqual(500, cin.ReadInt32()); - Assert.AreEqual(3, cin.Position); - //Field 2: - tag = cin.ReadTag(); - Assert.AreEqual(2, tag >> 3); - Assert.AreEqual(4, cin.Position); - int childlen = cin.ReadLength(); - Assert.AreEqual(120, childlen); - Assert.AreEqual(5, cin.Position); - int oldlimit = cin.PushLimit((int)childlen); - Assert.AreEqual(5, cin.Position); - // Now we are reading child message - { - // Field 11: numeric value: 500 - tag = cin.ReadTag(); - Assert.AreEqual(11, tag >> 3); - Assert.AreEqual(6, cin.Position); - Assert.AreEqual(500, cin.ReadInt32()); - Assert.AreEqual(8, cin.Position); - //Field 12: length delimited 120 bytes - tag = cin.ReadTag(); - Assert.AreEqual(12, tag >> 3); - Assert.AreEqual(9, cin.Position); - ByteString bstr = cin.ReadBytes(); - Assert.AreEqual(110, bstr.Length); - Assert.AreEqual((byte) 109, bstr[109]); - Assert.AreEqual(120, cin.Position); - // Field 13: fixed numeric value: 501 - tag = cin.ReadTag(); - Assert.AreEqual(13, tag >> 3); - // ROK - Previously broken here, this returned 126 failing to account for bufferSizeAfterLimit - Assert.AreEqual(121, cin.Position); - Assert.AreEqual(501, cin.ReadSFixed32()); - Assert.AreEqual(125, cin.Position); - Assert.IsTrue(cin.IsAtEnd); - } - cin.PopLimit(oldlimit); - Assert.AreEqual(125, cin.Position); - // Field 3: fixed numeric value: 501 - tag = cin.ReadTag(); - Assert.AreEqual(3, tag >> 3); - Assert.AreEqual(126, cin.Position); - Assert.AreEqual(501, cin.ReadSFixed32()); - Assert.AreEqual(130, cin.Position); - Assert.IsTrue(cin.IsAtEnd); - } - } - - [Test] - public void Dispose_DisposesUnderlyingStream() - { - var memoryStream = new MemoryStream(); - Assert.IsTrue(memoryStream.CanWrite); - using (var cos = new CodedOutputStream(memoryStream)) - { - cos.WriteRawBytes(new byte[] {0}); - Assert.AreEqual(0, memoryStream.Position); // Not flushed yet - } - Assert.AreEqual(1, memoryStream.ToArray().Length); // Flushed data from CodedOutputStream to MemoryStream - Assert.IsFalse(memoryStream.CanWrite); // Disposed - } - - [Test] - public void Dispose_WithLeaveOpen() - { - var memoryStream = new MemoryStream(); - Assert.IsTrue(memoryStream.CanWrite); - using (var cos = new CodedOutputStream(memoryStream, true)) - { - cos.WriteRawBytes(new byte[] {0}); - Assert.AreEqual(0, memoryStream.Position); // Not flushed yet - } - Assert.AreEqual(1, memoryStream.Position); // Flushed data from CodedOutputStream to MemoryStream - Assert.IsTrue(memoryStream.CanWrite); // We left the stream open - } - - [Test] - public void Dispose_FromByteArray() - { - var stream = new CodedOutputStream(new byte[10]); - stream.Dispose(); - } - - [Test] - public void WriteString_AsciiSmall_MaxUtf8SizeExceedsBuffer() - { - var buffer = new byte[5]; - var output = new CodedOutputStream(buffer); - output.WriteString("ABC"); - - output.Flush(); - - // Verify written content - var input = new CodedInputStream(buffer); - Assert.AreEqual("ABC", input.ReadString()); - } - - [Test] - public void WriteStringsOfDifferentSizes_Ascii() - { - for (int i = 1; i <= 1024; i++) - { - var buffer = new byte[4096]; - var output = new CodedOutputStream(buffer); - var sb = new StringBuilder(); - for (int j = 0; j < i; j++) - { - sb.Append((j % 10).ToString()); // incrementing numbers, repeating - } - var s = sb.ToString(); - output.WriteString(s); - - output.Flush(); - - // Verify written content - var input = new CodedInputStream(buffer); - Assert.AreEqual(s, input.ReadString()); - } - } - - [Test] - public void WriteStringsOfDifferentSizes_Unicode() - { - for (int i = 1; i <= 1024; i++) - { - var buffer = new byte[4096]; - var output = new CodedOutputStream(buffer); - var sb = new StringBuilder(); - for (int j = 0; j < i; j++) - { - char c = (char)((j % 10) + 10112); - sb.Append(c.ToString()); // incrementing unicode numbers, repeating - } - var s = sb.ToString(); - output.WriteString(s); - - output.Flush(); - - // Verify written content - var input = new CodedInputStream(buffer); - - Assert.AreEqual(s, input.ReadString()); - } - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.IO; +using Google.Protobuf.TestProtos; +using Google.Protobuf.Buffers; +using NUnit.Framework; +using System.Text; + +namespace Google.Protobuf +{ + public class CodedOutputStreamTest + { + /// + /// Writes the given value using WriteRawVarint32() and WriteRawVarint64() and + /// checks that the result matches the given bytes + /// + private static void AssertWriteVarint(byte[] data, ulong value) + { + // Only do 32-bit write if the value fits in 32 bits. + if ((value >> 32) == 0) + { + // CodedOutputStream + MemoryStream rawOutput = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(rawOutput); + output.WriteRawVarint32((uint) value); + output.Flush(); + Assert.AreEqual(data, rawOutput.ToArray()); + + // IBufferWriter + var bufferWriter = new TestArrayBufferWriter(); + WriteContext.Initialize(bufferWriter, out WriteContext ctx); + ctx.WriteUInt32((uint) value); + ctx.Flush(); + Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray()); + + // Also try computing size. + Assert.AreEqual(data.Length, CodedOutputStream.ComputeRawVarint32Size((uint) value)); + } + + { + // CodedOutputStream + MemoryStream rawOutput = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(rawOutput); + output.WriteRawVarint64(value); + output.Flush(); + Assert.AreEqual(data, rawOutput.ToArray()); + + // IBufferWriter + var bufferWriter = new TestArrayBufferWriter(); + WriteContext.Initialize(bufferWriter, out WriteContext ctx); + ctx.WriteUInt64(value); + ctx.Flush(); + Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray()); + + // Also try computing size. + Assert.AreEqual(data.Length, CodedOutputStream.ComputeRawVarint64Size(value)); + } + + // Try different buffer sizes. + for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2) + { + // Only do 32-bit write if the value fits in 32 bits. + if ((value >> 32) == 0) + { + MemoryStream rawOutput = new MemoryStream(); + CodedOutputStream output = + new CodedOutputStream(rawOutput, bufferSize); + output.WriteRawVarint32((uint) value); + output.Flush(); + Assert.AreEqual(data, rawOutput.ToArray()); + + var bufferWriter = new TestArrayBufferWriter(); + bufferWriter.MaxGrowBy = bufferSize; + WriteContext.Initialize(bufferWriter, out WriteContext ctx); + ctx.WriteUInt32((uint) value); + ctx.Flush(); + Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray()); + } + + { + MemoryStream rawOutput = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(rawOutput, bufferSize); + output.WriteRawVarint64(value); + output.Flush(); + Assert.AreEqual(data, rawOutput.ToArray()); + + var bufferWriter = new TestArrayBufferWriter(); + bufferWriter.MaxGrowBy = bufferSize; + WriteContext.Initialize(bufferWriter, out WriteContext ctx); + ctx.WriteUInt64(value); + ctx.Flush(); + Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray()); + } + + } + } + + /// + /// Tests WriteRawVarint32() and WriteRawVarint64() + /// + [Test] + public void WriteVarint() + { + AssertWriteVarint(new byte[] {0x00}, 0); + AssertWriteVarint(new byte[] {0x01}, 1); + AssertWriteVarint(new byte[] {0x7f}, 127); + // 14882 + AssertWriteVarint(new byte[] {0xa2, 0x74}, (0x22 << 0) | (0x74 << 7)); + // 2961488830 + AssertWriteVarint(new byte[] {0xbe, 0xf7, 0x92, 0x84, 0x0b}, + (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | + (0x0bL << 28)); + + // 64-bit + // 7256456126 + AssertWriteVarint(new byte[] {0xbe, 0xf7, 0x92, 0x84, 0x1b}, + (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | + (0x1bL << 28)); + // 41256202580718336 + AssertWriteVarint( + new byte[] {0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49}, + (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | + (0x43UL << 28) | (0x49L << 35) | (0x24UL << 42) | (0x49UL << 49)); + // 11964378330978735131 + AssertWriteVarint( + new byte[] {0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01}, + unchecked((ulong) + ((0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | + (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) | + (0x05L << 49) | (0x26L << 56) | (0x01L << 63)))); + } + + /// + /// Parses the given bytes using WriteRawLittleEndian32() and checks + /// that the result matches the given value. + /// + private static void AssertWriteLittleEndian32(byte[] data, uint value) + { + { + var rawOutput = new MemoryStream(); + var output = new CodedOutputStream(rawOutput); + output.WriteRawLittleEndian32(value); + output.Flush(); + Assert.AreEqual(data, rawOutput.ToArray()); + + var bufferWriter = new TestArrayBufferWriter(); + WriteContext.Initialize(bufferWriter, out WriteContext ctx); + ctx.WriteFixed32(value); + ctx.Flush(); + Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray()); + } + + // Try different buffer sizes. + for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2) + { + var rawOutput = new MemoryStream(); + var output = new CodedOutputStream(rawOutput, bufferSize); + output.WriteRawLittleEndian32(value); + output.Flush(); + Assert.AreEqual(data, rawOutput.ToArray()); + + var bufferWriter = new TestArrayBufferWriter(); + bufferWriter.MaxGrowBy = bufferSize; + WriteContext.Initialize(bufferWriter, out WriteContext ctx); + ctx.WriteFixed32(value); + ctx.Flush(); + Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray()); + } + } + + /// + /// Parses the given bytes using WriteRawLittleEndian64() and checks + /// that the result matches the given value. + /// + private static void AssertWriteLittleEndian64(byte[] data, ulong value) + { + { + var rawOutput = new MemoryStream(); + var output = new CodedOutputStream(rawOutput); + output.WriteRawLittleEndian64(value); + output.Flush(); + Assert.AreEqual(data, rawOutput.ToArray()); + + var bufferWriter = new TestArrayBufferWriter(); + WriteContext.Initialize(bufferWriter, out WriteContext ctx); + ctx.WriteFixed64(value); + ctx.Flush(); + Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray()); + } + + // Try different block sizes. + for (int blockSize = 1; blockSize <= 16; blockSize *= 2) + { + var rawOutput = new MemoryStream(); + var output = new CodedOutputStream(rawOutput, blockSize); + output.WriteRawLittleEndian64(value); + output.Flush(); + Assert.AreEqual(data, rawOutput.ToArray()); + + var bufferWriter = new TestArrayBufferWriter(); + bufferWriter.MaxGrowBy = blockSize; + WriteContext.Initialize(bufferWriter, out WriteContext ctx); + ctx.WriteFixed64(value); + ctx.Flush(); + Assert.AreEqual(data, bufferWriter.WrittenSpan.ToArray()); + } + } + + /// + /// Tests writeRawLittleEndian32() and writeRawLittleEndian64(). + /// + [Test] + public void WriteLittleEndian() + { + AssertWriteLittleEndian32(new byte[] {0x78, 0x56, 0x34, 0x12}, 0x12345678); + AssertWriteLittleEndian32(new byte[] {0xf0, 0xde, 0xbc, 0x9a}, 0x9abcdef0); + + AssertWriteLittleEndian64( + new byte[] {0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12}, + 0x123456789abcdef0L); + AssertWriteLittleEndian64( + new byte[] {0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a}, + 0x9abcdef012345678UL); + } + + [Test] + public void WriteWholeMessage_VaryingBlockSizes() + { + TestAllTypes message = SampleMessages.CreateFullTestAllTypes(); + + byte[] rawBytes = message.ToByteArray(); + + // Try different block sizes. + for (int blockSize = 1; blockSize < 256; blockSize *= 2) + { + MemoryStream rawOutput = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(rawOutput, blockSize); + message.WriteTo(output); + output.Flush(); + Assert.AreEqual(rawBytes, rawOutput.ToArray()); + + var bufferWriter = new TestArrayBufferWriter(); + bufferWriter.MaxGrowBy = blockSize; + message.WriteTo(bufferWriter); + Assert.AreEqual(rawBytes, bufferWriter.WrittenSpan.ToArray()); + } + } + + [Test] + public void WriteContext_WritesWithFlushes() + { + TestAllTypes message = SampleMessages.CreateFullTestAllTypes(); + + MemoryStream expectedOutput = new MemoryStream(); + CodedOutputStream output = new CodedOutputStream(expectedOutput); + output.WriteMessage(message); + output.Flush(); + byte[] expectedBytes1 = expectedOutput.ToArray(); + + output.WriteMessage(message); + output.Flush(); + byte[] expectedBytes2 = expectedOutput.ToArray(); + + var bufferWriter = new TestArrayBufferWriter(); + WriteContext.Initialize(bufferWriter, out WriteContext ctx); + ctx.WriteMessage(message); + ctx.Flush(); + Assert.AreEqual(expectedBytes1, bufferWriter.WrittenSpan.ToArray()); + + ctx.WriteMessage(message); + ctx.Flush(); + Assert.AreEqual(expectedBytes2, bufferWriter.WrittenSpan.ToArray()); + } + + [Test] + public void EncodeZigZag32() + { + Assert.AreEqual(0u, WritingPrimitives.EncodeZigZag32(0)); + Assert.AreEqual(1u, WritingPrimitives.EncodeZigZag32(-1)); + Assert.AreEqual(2u, WritingPrimitives.EncodeZigZag32(1)); + Assert.AreEqual(3u, WritingPrimitives.EncodeZigZag32(-2)); + Assert.AreEqual(0x7FFFFFFEu, WritingPrimitives.EncodeZigZag32(0x3FFFFFFF)); + Assert.AreEqual(0x7FFFFFFFu, WritingPrimitives.EncodeZigZag32(unchecked((int) 0xC0000000))); + Assert.AreEqual(0xFFFFFFFEu, WritingPrimitives.EncodeZigZag32(0x7FFFFFFF)); + Assert.AreEqual(0xFFFFFFFFu, WritingPrimitives.EncodeZigZag32(unchecked((int) 0x80000000))); + } + + [Test] + public void EncodeZigZag64() + { + Assert.AreEqual(0u, WritingPrimitives.EncodeZigZag64(0)); + Assert.AreEqual(1u, WritingPrimitives.EncodeZigZag64(-1)); + Assert.AreEqual(2u, WritingPrimitives.EncodeZigZag64(1)); + Assert.AreEqual(3u, WritingPrimitives.EncodeZigZag64(-2)); + Assert.AreEqual(0x000000007FFFFFFEuL, + WritingPrimitives.EncodeZigZag64(unchecked((long) 0x000000003FFFFFFFUL))); + Assert.AreEqual(0x000000007FFFFFFFuL, + WritingPrimitives.EncodeZigZag64(unchecked((long) 0xFFFFFFFFC0000000UL))); + Assert.AreEqual(0x00000000FFFFFFFEuL, + WritingPrimitives.EncodeZigZag64(unchecked((long) 0x000000007FFFFFFFUL))); + Assert.AreEqual(0x00000000FFFFFFFFuL, + WritingPrimitives.EncodeZigZag64(unchecked((long) 0xFFFFFFFF80000000UL))); + Assert.AreEqual(0xFFFFFFFFFFFFFFFEL, + WritingPrimitives.EncodeZigZag64(unchecked((long) 0x7FFFFFFFFFFFFFFFUL))); + Assert.AreEqual(0xFFFFFFFFFFFFFFFFL, + WritingPrimitives.EncodeZigZag64(unchecked((long) 0x8000000000000000UL))); + } + + [Test] + public void RoundTripZigZag32() + { + // Some easier-to-verify round-trip tests. The inputs (other than 0, 1, -1) + // were chosen semi-randomly via keyboard bashing. + Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(0))); + Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(1))); + Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(-1))); + Assert.AreEqual(14927, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(14927))); + Assert.AreEqual(-3612, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(-3612))); + } + + [Test] + public void RoundTripZigZag64() + { + Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(0))); + Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(1))); + Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-1))); + Assert.AreEqual(14927, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(14927))); + Assert.AreEqual(-3612, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-3612))); + + Assert.AreEqual(856912304801416L, + ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(856912304801416L))); + Assert.AreEqual(-75123905439571256L, + ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-75123905439571256L))); + } + + [Test] + public void TestNegativeEnumNoTag() + { + Assert.AreEqual(10, CodedOutputStream.ComputeInt32Size(-2)); + Assert.AreEqual(10, CodedOutputStream.ComputeEnumSize((int) SampleEnum.NegativeValue)); + + byte[] bytes = new byte[10]; + CodedOutputStream output = new CodedOutputStream(bytes); + output.WriteEnum((int) SampleEnum.NegativeValue); + + Assert.AreEqual(0, output.SpaceLeft); + Assert.AreEqual("FE-FF-FF-FF-FF-FF-FF-FF-FF-01", BitConverter.ToString(bytes)); + } + + [Test] + public void TestCodedInputOutputPosition() + { + byte[] content = new byte[110]; + for (int i = 0; i < content.Length; i++) + content[i] = (byte)i; + + byte[] child = new byte[120]; + { + MemoryStream ms = new MemoryStream(child); + CodedOutputStream cout = new CodedOutputStream(ms, 20); + // Field 11: numeric value: 500 + cout.WriteTag(11, WireFormat.WireType.Varint); + Assert.AreEqual(1, cout.Position); + cout.WriteInt32(500); + Assert.AreEqual(3, cout.Position); + //Field 12: length delimited 120 bytes + cout.WriteTag(12, WireFormat.WireType.LengthDelimited); + Assert.AreEqual(4, cout.Position); + cout.WriteBytes(ByteString.CopyFrom(content)); + Assert.AreEqual(115, cout.Position); + // Field 13: fixed numeric value: 501 + cout.WriteTag(13, WireFormat.WireType.Fixed32); + Assert.AreEqual(116, cout.Position); + cout.WriteSFixed32(501); + Assert.AreEqual(120, cout.Position); + cout.Flush(); + } + + byte[] bytes = new byte[130]; + { + CodedOutputStream cout = new CodedOutputStream(bytes); + // Field 1: numeric value: 500 + cout.WriteTag(1, WireFormat.WireType.Varint); + Assert.AreEqual(1, cout.Position); + cout.WriteInt32(500); + Assert.AreEqual(3, cout.Position); + //Field 2: length delimited 120 bytes + cout.WriteTag(2, WireFormat.WireType.LengthDelimited); + Assert.AreEqual(4, cout.Position); + cout.WriteBytes(ByteString.CopyFrom(child)); + Assert.AreEqual(125, cout.Position); + // Field 3: fixed numeric value: 500 + cout.WriteTag(3, WireFormat.WireType.Fixed32); + Assert.AreEqual(126, cout.Position); + cout.WriteSFixed32(501); + Assert.AreEqual(130, cout.Position); + cout.Flush(); + } + // Now test Input stream: + { + CodedInputStream cin = new CodedInputStream(new MemoryStream(bytes), new byte[50], 0, 0, false); + Assert.AreEqual(0, cin.Position); + // Field 1: + uint tag = cin.ReadTag(); + Assert.AreEqual(1, tag >> 3); + Assert.AreEqual(1, cin.Position); + Assert.AreEqual(500, cin.ReadInt32()); + Assert.AreEqual(3, cin.Position); + //Field 2: + tag = cin.ReadTag(); + Assert.AreEqual(2, tag >> 3); + Assert.AreEqual(4, cin.Position); + int childlen = cin.ReadLength(); + Assert.AreEqual(120, childlen); + Assert.AreEqual(5, cin.Position); + int oldlimit = cin.PushLimit((int)childlen); + Assert.AreEqual(5, cin.Position); + // Now we are reading child message + { + // Field 11: numeric value: 500 + tag = cin.ReadTag(); + Assert.AreEqual(11, tag >> 3); + Assert.AreEqual(6, cin.Position); + Assert.AreEqual(500, cin.ReadInt32()); + Assert.AreEqual(8, cin.Position); + //Field 12: length delimited 120 bytes + tag = cin.ReadTag(); + Assert.AreEqual(12, tag >> 3); + Assert.AreEqual(9, cin.Position); + ByteString bstr = cin.ReadBytes(); + Assert.AreEqual(110, bstr.Length); + Assert.AreEqual((byte) 109, bstr[109]); + Assert.AreEqual(120, cin.Position); + // Field 13: fixed numeric value: 501 + tag = cin.ReadTag(); + Assert.AreEqual(13, tag >> 3); + // ROK - Previously broken here, this returned 126 failing to account for bufferSizeAfterLimit + Assert.AreEqual(121, cin.Position); + Assert.AreEqual(501, cin.ReadSFixed32()); + Assert.AreEqual(125, cin.Position); + Assert.IsTrue(cin.IsAtEnd); + } + cin.PopLimit(oldlimit); + Assert.AreEqual(125, cin.Position); + // Field 3: fixed numeric value: 501 + tag = cin.ReadTag(); + Assert.AreEqual(3, tag >> 3); + Assert.AreEqual(126, cin.Position); + Assert.AreEqual(501, cin.ReadSFixed32()); + Assert.AreEqual(130, cin.Position); + Assert.IsTrue(cin.IsAtEnd); + } + } + + [Test] + public void Dispose_DisposesUnderlyingStream() + { + var memoryStream = new MemoryStream(); + Assert.IsTrue(memoryStream.CanWrite); + using (var cos = new CodedOutputStream(memoryStream)) + { + cos.WriteRawBytes(new byte[] {0}); + Assert.AreEqual(0, memoryStream.Position); // Not flushed yet + } + Assert.AreEqual(1, memoryStream.ToArray().Length); // Flushed data from CodedOutputStream to MemoryStream + Assert.IsFalse(memoryStream.CanWrite); // Disposed + } + + [Test] + public void Dispose_WithLeaveOpen() + { + var memoryStream = new MemoryStream(); + Assert.IsTrue(memoryStream.CanWrite); + using (var cos = new CodedOutputStream(memoryStream, true)) + { + cos.WriteRawBytes(new byte[] {0}); + Assert.AreEqual(0, memoryStream.Position); // Not flushed yet + } + Assert.AreEqual(1, memoryStream.Position); // Flushed data from CodedOutputStream to MemoryStream + Assert.IsTrue(memoryStream.CanWrite); // We left the stream open + } + + [Test] + public void Dispose_FromByteArray() + { + var stream = new CodedOutputStream(new byte[10]); + stream.Dispose(); + } + + [Test] + public void WriteString_AsciiSmall_MaxUtf8SizeExceedsBuffer() + { + var buffer = new byte[5]; + var output = new CodedOutputStream(buffer); + output.WriteString("ABC"); + + output.Flush(); + + // Verify written content + var input = new CodedInputStream(buffer); + Assert.AreEqual("ABC", input.ReadString()); + } + + [Test] + public void WriteStringsOfDifferentSizes_Ascii() + { + for (int i = 1; i <= 1024; i++) + { + var buffer = new byte[4096]; + var output = new CodedOutputStream(buffer); + var sb = new StringBuilder(); + for (int j = 0; j < i; j++) + { + sb.Append((j % 10).ToString()); // incrementing numbers, repeating + } + var s = sb.ToString(); + output.WriteString(s); + + output.Flush(); + + // Verify written content + var input = new CodedInputStream(buffer); + Assert.AreEqual(s, input.ReadString()); + } + } + + [Test] + public void WriteStringsOfDifferentSizes_Unicode() + { + for (int i = 1; i <= 1024; i++) + { + var buffer = new byte[4096]; + var output = new CodedOutputStream(buffer); + var sb = new StringBuilder(); + for (int j = 0; j < i; j++) + { + char c = (char)((j % 10) + 10112); + sb.Append(c.ToString()); // incrementing unicode numbers, repeating + } + var s = sb.ToString(); + output.WriteString(s); + + output.Flush(); + + // Verify written content + var input = new CodedInputStream(buffer); + + Assert.AreEqual(s, input.ReadString()); + } + } + } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf.Test/DeprecatedMemberTest.cs b/csharp/src/Google.Protobuf.Test/DeprecatedMemberTest.cs index 34d5b9f98cbb..fd041e01716d 100644 --- a/csharp/src/Google.Protobuf.Test/DeprecatedMemberTest.cs +++ b/csharp/src/Google.Protobuf.Test/DeprecatedMemberTest.cs @@ -1,55 +1,55 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2015 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.Reflection; -using Google.Protobuf.TestProtos; -using NUnit.Framework; - -namespace Google.Protobuf -{ - public class DeprecatedMemberTest - { - private static void AssertIsDeprecated(MemberInfo member) - { - Assert.NotNull(member); - Assert.IsTrue(member.IsDefined(typeof(ObsoleteAttribute), false), "Member not obsolete: " + member); - } - - [Test] - public void TestDepreatedPrimitiveValue() - { - AssertIsDeprecated(typeof(TestDeprecatedFields).GetProperty("DeprecatedInt32")); - } - - } -} +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.Reflection; +using Google.Protobuf.TestProtos; +using NUnit.Framework; + +namespace Google.Protobuf +{ + public class DeprecatedMemberTest + { + private static void AssertIsDeprecated(MemberInfo member) + { + Assert.NotNull(member); + Assert.IsTrue(member.IsDefined(typeof(ObsoleteAttribute), false), "Member not obsolete: " + member); + } + + [Test] + public void TestDepreatedPrimitiveValue() + { + AssertIsDeprecated(typeof(TestDeprecatedFields).GetProperty("DeprecatedInt32")); + } + + } +} diff --git a/csharp/src/Google.Protobuf.Test/ExtensionSetTest.cs b/csharp/src/Google.Protobuf.Test/ExtensionSetTest.cs index d163810b6e0a..b2c24dd201fc 100644 --- a/csharp/src/Google.Protobuf.Test/ExtensionSetTest.cs +++ b/csharp/src/Google.Protobuf.Test/ExtensionSetTest.cs @@ -1,196 +1,196 @@ -using System; -using System.Collections; -using Google.Protobuf.TestProtos.Proto2; -using NUnit.Framework; - -using static Google.Protobuf.TestProtos.Proto2.UnittestExtensions; - -namespace Google.Protobuf -{ - public class ExtensionSetTest - { - [Test] - public void EmptyExtensionSet() - { - ExtensionSet extensions = new ExtensionSet(); - Assert.AreEqual(0, extensions.CalculateSize()); - } - - [Test] - public void MergeExtensionSet() - { - ExtensionSet extensions = null; - ExtensionSet.Set(ref extensions, OptionalBoolExtension, true); - - ExtensionSet other = null; - - Assert.IsFalse(ExtensionSet.Has(ref other, OptionalBoolExtension)); - ExtensionSet.MergeFrom(ref other, extensions); - Assert.IsTrue(ExtensionSet.Has(ref other, OptionalBoolExtension)); - } - - [Test] - public void TestMergeCodedInput() - { - var message = new TestAllExtensions(); - message.SetExtension(OptionalBoolExtension, true); - var serialized = message.ToByteArray(); - - MessageParsingHelpers.AssertWritingMessage(message); - - MessageParsingHelpers.AssertReadingMessage( - TestAllExtensions.Parser.WithExtensionRegistry(new ExtensionRegistry() { OptionalBoolExtension }), - serialized, - other => - { - Assert.AreEqual(message, other); - Assert.AreEqual(message.CalculateSize(), other.CalculateSize()); - }); - } - - [Test] - public void TestMergeMessage() - { - var message = new TestAllExtensions(); - message.SetExtension(OptionalBoolExtension, true); - - var other = new TestAllExtensions(); - - Assert.AreNotEqual(message, other); - Assert.AreNotEqual(message.CalculateSize(), other.CalculateSize()); - - other.MergeFrom(message); - - Assert.AreEqual(message, other); - Assert.AreEqual(message.CalculateSize(), other.CalculateSize()); - } - - [Test] - public void TryMergeFieldFrom_CodedInputStream() - { - var message = new TestAllExtensions(); - message.SetExtension(OptionalStringExtension, "abcd"); - - var input = new CodedInputStream(message.ToByteArray()); - input.ExtensionRegistry = new ExtensionRegistry() { OptionalStringExtension }; - input.ReadTag(); // TryMergeFieldFrom expects that a tag was just read and will inspect the LastTag value - - ExtensionSet extensionSet = null; - // test the legacy overload of TryMergeFieldFrom that takes a CodedInputStream - Assert.IsTrue(ExtensionSet.TryMergeFieldFrom(ref extensionSet, input)); - Assert.AreEqual("abcd", ExtensionSet.Get(ref extensionSet, OptionalStringExtension)); - } - - [Test] - public void GetSingle() - { - var extensionValue = new TestAllTypes.Types.NestedMessage() { Bb = 42 }; - var untypedExtension = new Extension(OptionalNestedMessageExtension.FieldNumber, codec: null); - var wrongTypedExtension = new Extension(OptionalNestedMessageExtension.FieldNumber, codec: null); - - var message = new TestAllExtensions(); - - var value1 = message.GetExtension(untypedExtension); - Assert.IsNull(value1); - - message.SetExtension(OptionalNestedMessageExtension, extensionValue); - var value2 = message.GetExtension(untypedExtension); - Assert.IsNotNull(value2); - - var valueBytes = ((IMessage)value2).ToByteArray(); - var parsedValue = TestProtos.Proto2.TestAllTypes.Types.NestedMessage.Parser.ParseFrom(valueBytes); - Assert.AreEqual(extensionValue, parsedValue); - - var ex = Assert.Throws(() => message.GetExtension(wrongTypedExtension)); - - var expectedMessage = "The stored extension value has a type of 'Google.Protobuf.TestProtos.Proto2.TestAllTypes+Types+NestedMessage, Google.Protobuf.Test.TestProtos, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604'. " + - "This a different from the requested type of 'Google.Protobuf.TestProtos.Proto2.TestAllTypes, Google.Protobuf.Test.TestProtos, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604'."; - Assert.AreEqual(expectedMessage, ex.Message); - } - - [Test] - public void GetRepeated() - { - var extensionValue = new TestAllTypes.Types.NestedMessage() { Bb = 42 }; - var untypedExtension = new Extension(RepeatedNestedMessageExtension.FieldNumber, codec: null); - var wrongTypedExtension = new RepeatedExtension(RepeatedNestedMessageExtension.FieldNumber, codec: null); - - var message = new TestAllExtensions(); - - var value1 = message.GetExtension(untypedExtension); - Assert.IsNull(value1); - - var repeatedField = message.GetOrInitializeExtension(RepeatedNestedMessageExtension); - repeatedField.Add(extensionValue); - - var value2 = message.GetExtension(untypedExtension); - Assert.IsNotNull(value2); - Assert.AreEqual(1, value2.Count); - - var valueBytes = ((IMessage)value2[0]).ToByteArray(); - var parsedValue = TestProtos.Proto2.TestAllTypes.Types.NestedMessage.Parser.ParseFrom(valueBytes); - Assert.AreEqual(extensionValue, parsedValue); - - var ex = Assert.Throws(() => message.GetExtension(wrongTypedExtension)); - - var expectedMessage = "The stored extension value has a type of 'Google.Protobuf.TestProtos.Proto2.TestAllTypes+Types+NestedMessage, Google.Protobuf.Test.TestProtos, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604'. " + - "This a different from the requested type of 'Google.Protobuf.TestProtos.Proto2.TestAllTypes, Google.Protobuf.Test.TestProtos, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604'."; - Assert.AreEqual(expectedMessage, ex.Message); - } - - [Test] - public void TestEquals() - { - var message = new TestAllExtensions(); - message.SetExtension(OptionalBoolExtension, true); - - var other = new TestAllExtensions(); - - Assert.AreNotEqual(message, other); - Assert.AreNotEqual(message.CalculateSize(), other.CalculateSize()); - - other.SetExtension(OptionalBoolExtension, true); - - Assert.AreEqual(message, other); - Assert.AreEqual(message.CalculateSize(), other.CalculateSize()); - } - - [Test] - public void TestHashCode() - { - var message = new TestAllExtensions(); - var hashCode = message.GetHashCode(); - - message.SetExtension(OptionalBoolExtension, true); - - Assert.AreNotEqual(hashCode, message.GetHashCode()); - } - - [Test] - public void TestClone() - { - var message = new TestAllExtensions(); - message.SetExtension(OptionalBoolExtension, true); - - var other = message.Clone(); - - Assert.AreEqual(message, other); - Assert.AreEqual(message.CalculateSize(), other.CalculateSize()); - } - - [Test] - public void TestDefaultValueRoundTrip() - { - var message = new TestAllExtensions(); - message.SetExtension(OptionalBoolExtension, false); - Assert.IsFalse(message.GetExtension(OptionalBoolExtension)); - Assert.IsTrue(message.HasExtension(OptionalBoolExtension)); - - var bytes = message.ToByteArray(); - var registry = new ExtensionRegistry { OptionalBoolExtension }; - var parsed = TestAllExtensions.Parser.WithExtensionRegistry(registry).ParseFrom(bytes); - Assert.IsFalse(parsed.GetExtension(OptionalBoolExtension)); - Assert.IsTrue(parsed.HasExtension(OptionalBoolExtension)); - } - } -} +using System; +using System.Collections; +using Google.Protobuf.TestProtos.Proto2; +using NUnit.Framework; + +using static Google.Protobuf.TestProtos.Proto2.UnittestExtensions; + +namespace Google.Protobuf +{ + public class ExtensionSetTest + { + [Test] + public void EmptyExtensionSet() + { + ExtensionSet extensions = new ExtensionSet(); + Assert.AreEqual(0, extensions.CalculateSize()); + } + + [Test] + public void MergeExtensionSet() + { + ExtensionSet extensions = null; + ExtensionSet.Set(ref extensions, OptionalBoolExtension, true); + + ExtensionSet other = null; + + Assert.IsFalse(ExtensionSet.Has(ref other, OptionalBoolExtension)); + ExtensionSet.MergeFrom(ref other, extensions); + Assert.IsTrue(ExtensionSet.Has(ref other, OptionalBoolExtension)); + } + + [Test] + public void TestMergeCodedInput() + { + var message = new TestAllExtensions(); + message.SetExtension(OptionalBoolExtension, true); + var serialized = message.ToByteArray(); + + MessageParsingHelpers.AssertWritingMessage(message); + + MessageParsingHelpers.AssertReadingMessage( + TestAllExtensions.Parser.WithExtensionRegistry(new ExtensionRegistry() { OptionalBoolExtension }), + serialized, + other => + { + Assert.AreEqual(message, other); + Assert.AreEqual(message.CalculateSize(), other.CalculateSize()); + }); + } + + [Test] + public void TestMergeMessage() + { + var message = new TestAllExtensions(); + message.SetExtension(OptionalBoolExtension, true); + + var other = new TestAllExtensions(); + + Assert.AreNotEqual(message, other); + Assert.AreNotEqual(message.CalculateSize(), other.CalculateSize()); + + other.MergeFrom(message); + + Assert.AreEqual(message, other); + Assert.AreEqual(message.CalculateSize(), other.CalculateSize()); + } + + [Test] + public void TryMergeFieldFrom_CodedInputStream() + { + var message = new TestAllExtensions(); + message.SetExtension(OptionalStringExtension, "abcd"); + + var input = new CodedInputStream(message.ToByteArray()); + input.ExtensionRegistry = new ExtensionRegistry() { OptionalStringExtension }; + input.ReadTag(); // TryMergeFieldFrom expects that a tag was just read and will inspect the LastTag value + + ExtensionSet extensionSet = null; + // test the legacy overload of TryMergeFieldFrom that takes a CodedInputStream + Assert.IsTrue(ExtensionSet.TryMergeFieldFrom(ref extensionSet, input)); + Assert.AreEqual("abcd", ExtensionSet.Get(ref extensionSet, OptionalStringExtension)); + } + + [Test] + public void GetSingle() + { + var extensionValue = new TestAllTypes.Types.NestedMessage() { Bb = 42 }; + var untypedExtension = new Extension(OptionalNestedMessageExtension.FieldNumber, codec: null); + var wrongTypedExtension = new Extension(OptionalNestedMessageExtension.FieldNumber, codec: null); + + var message = new TestAllExtensions(); + + var value1 = message.GetExtension(untypedExtension); + Assert.IsNull(value1); + + message.SetExtension(OptionalNestedMessageExtension, extensionValue); + var value2 = message.GetExtension(untypedExtension); + Assert.IsNotNull(value2); + + var valueBytes = ((IMessage)value2).ToByteArray(); + var parsedValue = TestProtos.Proto2.TestAllTypes.Types.NestedMessage.Parser.ParseFrom(valueBytes); + Assert.AreEqual(extensionValue, parsedValue); + + var ex = Assert.Throws(() => message.GetExtension(wrongTypedExtension)); + + var expectedMessage = "The stored extension value has a type of 'Google.Protobuf.TestProtos.Proto2.TestAllTypes+Types+NestedMessage, Google.Protobuf.Test.TestProtos, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604'. " + + "This a different from the requested type of 'Google.Protobuf.TestProtos.Proto2.TestAllTypes, Google.Protobuf.Test.TestProtos, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604'."; + Assert.AreEqual(expectedMessage, ex.Message); + } + + [Test] + public void GetRepeated() + { + var extensionValue = new TestAllTypes.Types.NestedMessage() { Bb = 42 }; + var untypedExtension = new Extension(RepeatedNestedMessageExtension.FieldNumber, codec: null); + var wrongTypedExtension = new RepeatedExtension(RepeatedNestedMessageExtension.FieldNumber, codec: null); + + var message = new TestAllExtensions(); + + var value1 = message.GetExtension(untypedExtension); + Assert.IsNull(value1); + + var repeatedField = message.GetOrInitializeExtension(RepeatedNestedMessageExtension); + repeatedField.Add(extensionValue); + + var value2 = message.GetExtension(untypedExtension); + Assert.IsNotNull(value2); + Assert.AreEqual(1, value2.Count); + + var valueBytes = ((IMessage)value2[0]).ToByteArray(); + var parsedValue = TestProtos.Proto2.TestAllTypes.Types.NestedMessage.Parser.ParseFrom(valueBytes); + Assert.AreEqual(extensionValue, parsedValue); + + var ex = Assert.Throws(() => message.GetExtension(wrongTypedExtension)); + + var expectedMessage = "The stored extension value has a type of 'Google.Protobuf.TestProtos.Proto2.TestAllTypes+Types+NestedMessage, Google.Protobuf.Test.TestProtos, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604'. " + + "This a different from the requested type of 'Google.Protobuf.TestProtos.Proto2.TestAllTypes, Google.Protobuf.Test.TestProtos, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604'."; + Assert.AreEqual(expectedMessage, ex.Message); + } + + [Test] + public void TestEquals() + { + var message = new TestAllExtensions(); + message.SetExtension(OptionalBoolExtension, true); + + var other = new TestAllExtensions(); + + Assert.AreNotEqual(message, other); + Assert.AreNotEqual(message.CalculateSize(), other.CalculateSize()); + + other.SetExtension(OptionalBoolExtension, true); + + Assert.AreEqual(message, other); + Assert.AreEqual(message.CalculateSize(), other.CalculateSize()); + } + + [Test] + public void TestHashCode() + { + var message = new TestAllExtensions(); + var hashCode = message.GetHashCode(); + + message.SetExtension(OptionalBoolExtension, true); + + Assert.AreNotEqual(hashCode, message.GetHashCode()); + } + + [Test] + public void TestClone() + { + var message = new TestAllExtensions(); + message.SetExtension(OptionalBoolExtension, true); + + var other = message.Clone(); + + Assert.AreEqual(message, other); + Assert.AreEqual(message.CalculateSize(), other.CalculateSize()); + } + + [Test] + public void TestDefaultValueRoundTrip() + { + var message = new TestAllExtensions(); + message.SetExtension(OptionalBoolExtension, false); + Assert.IsFalse(message.GetExtension(OptionalBoolExtension)); + Assert.IsTrue(message.HasExtension(OptionalBoolExtension)); + + var bytes = message.ToByteArray(); + var registry = new ExtensionRegistry { OptionalBoolExtension }; + var parsed = TestAllExtensions.Parser.WithExtensionRegistry(registry).ParseFrom(bytes); + Assert.IsFalse(parsed.GetExtension(OptionalBoolExtension)); + Assert.IsTrue(parsed.HasExtension(OptionalBoolExtension)); + } + } +} diff --git a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.Proto2.cs b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.Proto2.cs index 894d91412493..fa5f9277382d 100644 --- a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.Proto2.cs +++ b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.Proto2.cs @@ -1,397 +1,397 @@ -using Google.Protobuf.TestProtos.Proto2; -using Proto2 = Google.Protobuf.TestProtos.Proto2; -using NUnit.Framework; - -using static Google.Protobuf.TestProtos.Proto2.UnittestExtensions; - -namespace Google.Protobuf -{ - /// - /// Tests around the generated TestAllTypes message in unittest.proto - /// - public partial class GeneratedMessageTest - { - [Test] - public void DefaultProto2Values() - { - var message = new TestAllTypes(); - Assert.AreEqual(false, message.OptionalBool); - Assert.AreEqual(ByteString.Empty, message.OptionalBytes); - Assert.AreEqual(0.0, message.OptionalDouble); - Assert.AreEqual(0, message.OptionalFixed32); - Assert.AreEqual(0L, message.OptionalFixed64); - Assert.AreEqual(0.0f, message.OptionalFloat); - Assert.AreEqual(ForeignEnum.ForeignFoo, message.OptionalForeignEnum); - Assert.IsNull(message.OptionalForeignMessage); - Assert.AreEqual(ImportEnum.ImportFoo, message.OptionalImportEnum); - Assert.IsNull(message.OptionalImportMessage); - Assert.AreEqual(0, message.OptionalInt32); - Assert.AreEqual(0L, message.OptionalInt64); - Assert.AreEqual(Proto2.TestAllTypes.Types.NestedEnum.Foo, message.OptionalNestedEnum); - Assert.IsNull(message.OptionalNestedMessage); - Assert.IsNull(message.OptionalPublicImportMessage); - Assert.AreEqual(0, message.OptionalSfixed32); - Assert.AreEqual(0L, message.OptionalSfixed64); - Assert.AreEqual(0, message.OptionalSint32); - Assert.AreEqual(0L, message.OptionalSint64); - Assert.AreEqual("", message.OptionalString); - Assert.AreEqual(0U, message.OptionalUint32); - Assert.AreEqual(0UL, message.OptionalUint64); - - // Repeated fields - Assert.AreEqual(0, message.RepeatedBool.Count); - Assert.AreEqual(0, message.RepeatedBytes.Count); - Assert.AreEqual(0, message.RepeatedDouble.Count); - Assert.AreEqual(0, message.RepeatedFixed32.Count); - Assert.AreEqual(0, message.RepeatedFixed64.Count); - Assert.AreEqual(0, message.RepeatedFloat.Count); - Assert.AreEqual(0, message.RepeatedForeignEnum.Count); - Assert.AreEqual(0, message.RepeatedForeignMessage.Count); - Assert.AreEqual(0, message.RepeatedImportEnum.Count); - Assert.AreEqual(0, message.RepeatedImportMessage.Count); - Assert.AreEqual(0, message.RepeatedNestedEnum.Count); - Assert.AreEqual(0, message.RepeatedNestedMessage.Count); - Assert.AreEqual(0, message.RepeatedSfixed32.Count); - Assert.AreEqual(0, message.RepeatedSfixed64.Count); - Assert.AreEqual(0, message.RepeatedSint32.Count); - Assert.AreEqual(0, message.RepeatedSint64.Count); - Assert.AreEqual(0, message.RepeatedString.Count); - Assert.AreEqual(0, message.RepeatedUint32.Count); - Assert.AreEqual(0, message.RepeatedUint64.Count); - - // Oneof fields - Assert.AreEqual(Proto2.TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); - Assert.AreEqual(0, message.OneofUint32); - Assert.AreEqual("", message.OneofString); - Assert.AreEqual(ByteString.Empty, message.OneofBytes); - Assert.IsNull(message.OneofNestedMessage); - - Assert.AreEqual(true, message.DefaultBool); - Assert.AreEqual(ByteString.CopyFromUtf8("world"), message.DefaultBytes); - Assert.AreEqual("123", message.DefaultCord); - Assert.AreEqual(52e3, message.DefaultDouble); - Assert.AreEqual(47, message.DefaultFixed32); - Assert.AreEqual(48, message.DefaultFixed64); - Assert.AreEqual(51.5, message.DefaultFloat); - Assert.AreEqual(ForeignEnum.ForeignBar, message.DefaultForeignEnum); - Assert.AreEqual(ImportEnum.ImportBar, message.DefaultImportEnum); - Assert.AreEqual(41, message.DefaultInt32); - Assert.AreEqual(42, message.DefaultInt64); - Assert.AreEqual(Proto2.TestAllTypes.Types.NestedEnum.Bar, message.DefaultNestedEnum); - Assert.AreEqual(49, message.DefaultSfixed32); - Assert.AreEqual(-50, message.DefaultSfixed64); - Assert.AreEqual(-45, message.DefaultSint32); - Assert.AreEqual(46, message.DefaultSint64); - Assert.AreEqual("hello", message.DefaultString); - Assert.AreEqual("abc", message.DefaultStringPiece); - Assert.AreEqual(43, message.DefaultUint32); - Assert.AreEqual(44, message.DefaultUint64); - - Assert.False(message.HasDefaultBool); - Assert.False(message.HasDefaultBytes); - Assert.False(message.HasDefaultCord); - Assert.False(message.HasDefaultDouble); - Assert.False(message.HasDefaultFixed32); - Assert.False(message.HasDefaultFixed64); - Assert.False(message.HasDefaultFloat); - Assert.False(message.HasDefaultForeignEnum); - Assert.False(message.HasDefaultImportEnum); - Assert.False(message.HasDefaultInt32); - Assert.False(message.HasDefaultInt64); - Assert.False(message.HasDefaultNestedEnum); - Assert.False(message.HasDefaultSfixed32); - Assert.False(message.HasDefaultSfixed64); - Assert.False(message.HasDefaultSint32); - Assert.False(message.HasDefaultSint64); - Assert.False(message.HasDefaultString); - Assert.False(message.HasDefaultStringPiece); - Assert.False(message.HasDefaultUint32); - Assert.False(message.HasDefaultUint64); - } - - [Test] - public void DefaultExtensionValues() - { - var message = new TestAllExtensions(); - Assert.AreEqual(false, message.GetExtension(OptionalBoolExtension)); - Assert.AreEqual(ByteString.Empty, message.GetExtension(OptionalBytesExtension)); - Assert.AreEqual(0.0, message.GetExtension(OptionalDoubleExtension)); - Assert.AreEqual(0, message.GetExtension(OptionalFixed32Extension)); - Assert.AreEqual(0L, message.GetExtension(OptionalFixed64Extension)); - Assert.AreEqual(0.0f, message.GetExtension(OptionalFloatExtension)); - Assert.AreEqual(ForeignEnum.ForeignFoo, message.GetExtension(OptionalForeignEnumExtension)); - Assert.IsNull(message.GetExtension(OptionalForeignMessageExtension)); - Assert.AreEqual(ImportEnum.ImportFoo, message.GetExtension(OptionalImportEnumExtension)); - Assert.IsNull(message.GetExtension(OptionalImportMessageExtension)); - Assert.AreEqual(0, message.GetExtension(OptionalInt32Extension)); - Assert.AreEqual(0L, message.GetExtension(OptionalInt64Extension)); - Assert.AreEqual(Proto2.TestAllTypes.Types.NestedEnum.Foo, message.GetExtension(OptionalNestedEnumExtension)); - Assert.IsNull(message.GetExtension(OptionalNestedMessageExtension)); - Assert.IsNull(message.GetExtension(OptionalPublicImportMessageExtension)); - Assert.AreEqual(0, message.GetExtension(OptionalSfixed32Extension)); - Assert.AreEqual(0L, message.GetExtension(OptionalSfixed64Extension)); - Assert.AreEqual(0, message.GetExtension(OptionalSint32Extension)); - Assert.AreEqual(0L, message.GetExtension(OptionalSint64Extension)); - Assert.AreEqual("", message.GetExtension(OptionalStringExtension)); - Assert.AreEqual(0U, message.GetExtension(OptionalUint32Extension)); - Assert.AreEqual(0UL, message.GetExtension(OptionalUint64Extension)); - - // Repeated fields - Assert.IsNull(message.GetExtension(RepeatedBoolExtension)); - Assert.IsNull(message.GetExtension(RepeatedBytesExtension)); - Assert.IsNull(message.GetExtension(RepeatedDoubleExtension)); - Assert.IsNull(message.GetExtension(RepeatedFixed32Extension)); - Assert.IsNull(message.GetExtension(RepeatedFixed64Extension)); - Assert.IsNull(message.GetExtension(RepeatedFloatExtension)); - Assert.IsNull(message.GetExtension(RepeatedForeignEnumExtension)); - Assert.IsNull(message.GetExtension(RepeatedForeignMessageExtension)); - Assert.IsNull(message.GetExtension(RepeatedImportEnumExtension)); - Assert.IsNull(message.GetExtension(RepeatedImportMessageExtension)); - Assert.IsNull(message.GetExtension(RepeatedNestedEnumExtension)); - Assert.IsNull(message.GetExtension(RepeatedNestedMessageExtension)); - Assert.IsNull(message.GetExtension(RepeatedSfixed32Extension)); - Assert.IsNull(message.GetExtension(RepeatedSfixed64Extension)); - Assert.IsNull(message.GetExtension(RepeatedSint32Extension)); - Assert.IsNull(message.GetExtension(RepeatedSint64Extension)); - Assert.IsNull(message.GetExtension(RepeatedStringExtension)); - Assert.IsNull(message.GetExtension(RepeatedUint32Extension)); - Assert.IsNull(message.GetExtension(RepeatedUint64Extension)); - - // Oneof fields - Assert.AreEqual(0, message.GetExtension(OneofUint32Extension)); - Assert.AreEqual("", message.GetExtension(OneofStringExtension)); - Assert.AreEqual(ByteString.Empty, message.GetExtension(OneofBytesExtension)); - Assert.IsNull(message.GetExtension(OneofNestedMessageExtension)); - - Assert.AreEqual(true, message.GetExtension(DefaultBoolExtension)); - Assert.AreEqual(ByteString.CopyFromUtf8("world"), message.GetExtension(DefaultBytesExtension)); - Assert.AreEqual("123", message.GetExtension(DefaultCordExtension)); - Assert.AreEqual(52e3, message.GetExtension(DefaultDoubleExtension)); - Assert.AreEqual(47, message.GetExtension(DefaultFixed32Extension)); - Assert.AreEqual(48, message.GetExtension(DefaultFixed64Extension)); - Assert.AreEqual(51.5, message.GetExtension(DefaultFloatExtension)); - Assert.AreEqual(ForeignEnum.ForeignBar, message.GetExtension(DefaultForeignEnumExtension)); - Assert.AreEqual(ImportEnum.ImportBar, message.GetExtension(DefaultImportEnumExtension)); - Assert.AreEqual(41, message.GetExtension(DefaultInt32Extension)); - Assert.AreEqual(42, message.GetExtension(DefaultInt64Extension)); - Assert.AreEqual(Proto2.TestAllTypes.Types.NestedEnum.Bar, message.GetExtension(DefaultNestedEnumExtension)); - Assert.AreEqual(49, message.GetExtension(DefaultSfixed32Extension)); - Assert.AreEqual(-50, message.GetExtension(DefaultSfixed64Extension)); - Assert.AreEqual(-45, message.GetExtension(DefaultSint32Extension)); - Assert.AreEqual(46, message.GetExtension(DefaultSint64Extension)); - Assert.AreEqual("hello", message.GetExtension(DefaultStringExtension)); - Assert.AreEqual("abc", message.GetExtension(DefaultStringPieceExtension)); - Assert.AreEqual(43, message.GetExtension(DefaultUint32Extension)); - Assert.AreEqual(44, message.GetExtension(DefaultUint64Extension)); - - Assert.False(message.HasExtension(DefaultBoolExtension)); - Assert.False(message.HasExtension(DefaultBytesExtension)); - Assert.False(message.HasExtension(DefaultCordExtension)); - Assert.False(message.HasExtension(DefaultDoubleExtension)); - Assert.False(message.HasExtension(DefaultFixed32Extension)); - Assert.False(message.HasExtension(DefaultFixed64Extension)); - Assert.False(message.HasExtension(DefaultFloatExtension)); - Assert.False(message.HasExtension(DefaultForeignEnumExtension)); - Assert.False(message.HasExtension(DefaultImportEnumExtension)); - Assert.False(message.HasExtension(DefaultInt32Extension)); - Assert.False(message.HasExtension(DefaultInt64Extension)); - Assert.False(message.HasExtension(DefaultNestedEnumExtension)); - Assert.False(message.HasExtension(DefaultSfixed32Extension)); - Assert.False(message.HasExtension(DefaultSfixed64Extension)); - Assert.False(message.HasExtension(DefaultSint32Extension)); - Assert.False(message.HasExtension(DefaultSint64Extension)); - Assert.False(message.HasExtension(DefaultStringExtension)); - Assert.False(message.HasExtension(DefaultStringPieceExtension)); - Assert.False(message.HasExtension(DefaultUint32Extension)); - Assert.False(message.HasExtension(DefaultUint64Extension)); - } - - [Test] - public void FieldPresence() - { - var message = new TestAllTypes(); - - Assert.False(message.HasOptionalBool); - Assert.False(message.OptionalBool); - - message.OptionalBool = true; - - Assert.True(message.HasOptionalBool); - Assert.True(message.OptionalBool); - - message.OptionalBool = false; - - Assert.True(message.HasOptionalBool); - Assert.False(message.OptionalBool); - - message.ClearOptionalBool(); - - Assert.False(message.HasOptionalBool); - Assert.False(message.OptionalBool); - - Assert.False(message.HasDefaultBool); - Assert.True(message.DefaultBool); - - message.DefaultBool = false; - - Assert.True(message.HasDefaultBool); - Assert.False(message.DefaultBool); - - message.DefaultBool = true; - - Assert.True(message.HasDefaultBool); - Assert.True(message.DefaultBool); - - message.ClearDefaultBool(); - - Assert.False(message.HasDefaultBool); - Assert.True(message.DefaultBool); - } - - [Test] - public void RequiredFields() - { - var message = new TestRequired(); - Assert.False(message.IsInitialized()); - - message.A = 1; - message.B = 2; - message.C = 3; - - Assert.True(message.IsInitialized()); - } - - /// - /// Code was accidentally left in message parser that threw exceptions when missing required fields after parsing. - /// We've decided to not throw exceptions on missing fields, instead leaving it up to the consumer how they - /// want to check and handle missing fields. - /// - [Test] - public void RequiredFieldsNoThrow() - { - Assert.DoesNotThrow(() => MessageParsingHelpers.AssertReadingMessage(TestRequired.Parser, new byte[0], m => { })); - Assert.DoesNotThrow(() => MessageParsingHelpers.AssertReadingMessage(TestRequired.Parser as MessageParser, new byte[0], m => { })); - } - - [Test] - public void RequiredFieldsInExtensions() - { - var message = new TestAllExtensions(); - Assert.True(message.IsInitialized()); - - message.SetExtension(TestRequired.Extensions.Single, new TestRequired()); - - Assert.False(message.IsInitialized()); - - var extensionMessage = message.GetExtension(TestRequired.Extensions.Single); - extensionMessage.A = 1; - extensionMessage.B = 2; - extensionMessage.C = 3; - - Assert.True(message.IsInitialized()); - - message.GetOrInitializeExtension(TestRequired.Extensions.Multi); - - Assert.True(message.IsInitialized()); - - message.GetExtension(TestRequired.Extensions.Multi).Add(new TestRequired()); - - Assert.False(message.IsInitialized()); - - extensionMessage = message.GetExtension(TestRequired.Extensions.Multi)[0]; - extensionMessage.A = 1; - extensionMessage.B = 2; - extensionMessage.C = 3; - - Assert.True(message.IsInitialized()); - - message.SetExtension(UnittestExtensions.OptionalBoolExtension, true); - - Assert.True(message.IsInitialized()); - - message.GetOrInitializeExtension(UnittestExtensions.RepeatedBoolExtension).Add(true); - - Assert.True(message.IsInitialized()); - } - - [Test] - public void RequiredFieldInNestedMessageMapValue() - { - var message = new TestRequiredMap(); - message.Foo.Add(0, new TestRequiredMap.Types.NestedMessage()); - - Assert.False(message.IsInitialized()); - - message.Foo[0].RequiredInt32 = 12; - - Assert.True(message.IsInitialized()); - } - - [Test] - public void RoundTrip_Groups() - { - var message = new TestAllTypes - { - OptionalGroup = new TestAllTypes.Types.OptionalGroup - { - A = 10 - }, - RepeatedGroup = - { - new TestAllTypes.Types.RepeatedGroup { A = 10 }, - new TestAllTypes.Types.RepeatedGroup { A = 20 }, - new TestAllTypes.Types.RepeatedGroup { A = 30 } - } - }; - - MessageParsingHelpers.AssertWritingMessage(message); - - MessageParsingHelpers.AssertRoundtrip(Proto2.TestAllTypes.Parser, message); - } - - [Test] - public void RoundTrip_ExtensionGroups() - { - var message = new TestAllExtensions(); - message.SetExtension(UnittestExtensions.OptionalGroupExtension, new OptionalGroup_extension { A = 10 }); - message.GetOrInitializeExtension(UnittestExtensions.RepeatedGroupExtension).AddRange(new[] - { - new RepeatedGroup_extension { A = 10 }, - new RepeatedGroup_extension { A = 20 }, - new RepeatedGroup_extension { A = 30 } - }); - - MessageParsingHelpers.AssertWritingMessage(message); - - MessageParsingHelpers.AssertRoundtrip( - TestAllExtensions.Parser.WithExtensionRegistry(new ExtensionRegistry() { UnittestExtensions.OptionalGroupExtension, UnittestExtensions.RepeatedGroupExtension }), - message); - } - - [Test] - public void RoundTrip_NestedExtensionGroup() - { - var message = new TestGroupExtension(); - message.SetExtension(TestNestedExtension.Extensions.OptionalGroupExtension, new TestNestedExtension.Types.OptionalGroup_extension { A = 10 }); - - MessageParsingHelpers.AssertWritingMessage(message); - - MessageParsingHelpers.AssertRoundtrip( - TestGroupExtension.Parser.WithExtensionRegistry(new ExtensionRegistry() { TestNestedExtension.Extensions.OptionalGroupExtension }), - message); - } - - [Test] - public void RoundTrip_ParseUsingCodedInput() - { - var message = new TestAllExtensions(); - message.SetExtension(UnittestExtensions.OptionalBoolExtension, true); - byte[] bytes = message.ToByteArray(); - using (CodedInputStream input = new CodedInputStream(bytes)) - { - var parsed = TestAllExtensions.Parser.WithExtensionRegistry(new ExtensionRegistry() { UnittestExtensions.OptionalBoolExtension }).ParseFrom(input); - Assert.AreEqual(message, parsed); - } - } - } -} +using Google.Protobuf.TestProtos.Proto2; +using Proto2 = Google.Protobuf.TestProtos.Proto2; +using NUnit.Framework; + +using static Google.Protobuf.TestProtos.Proto2.UnittestExtensions; + +namespace Google.Protobuf +{ + /// + /// Tests around the generated TestAllTypes message in unittest.proto + /// + public partial class GeneratedMessageTest + { + [Test] + public void DefaultProto2Values() + { + var message = new TestAllTypes(); + Assert.AreEqual(false, message.OptionalBool); + Assert.AreEqual(ByteString.Empty, message.OptionalBytes); + Assert.AreEqual(0.0, message.OptionalDouble); + Assert.AreEqual(0, message.OptionalFixed32); + Assert.AreEqual(0L, message.OptionalFixed64); + Assert.AreEqual(0.0f, message.OptionalFloat); + Assert.AreEqual(ForeignEnum.ForeignFoo, message.OptionalForeignEnum); + Assert.IsNull(message.OptionalForeignMessage); + Assert.AreEqual(ImportEnum.ImportFoo, message.OptionalImportEnum); + Assert.IsNull(message.OptionalImportMessage); + Assert.AreEqual(0, message.OptionalInt32); + Assert.AreEqual(0L, message.OptionalInt64); + Assert.AreEqual(Proto2.TestAllTypes.Types.NestedEnum.Foo, message.OptionalNestedEnum); + Assert.IsNull(message.OptionalNestedMessage); + Assert.IsNull(message.OptionalPublicImportMessage); + Assert.AreEqual(0, message.OptionalSfixed32); + Assert.AreEqual(0L, message.OptionalSfixed64); + Assert.AreEqual(0, message.OptionalSint32); + Assert.AreEqual(0L, message.OptionalSint64); + Assert.AreEqual("", message.OptionalString); + Assert.AreEqual(0U, message.OptionalUint32); + Assert.AreEqual(0UL, message.OptionalUint64); + + // Repeated fields + Assert.AreEqual(0, message.RepeatedBool.Count); + Assert.AreEqual(0, message.RepeatedBytes.Count); + Assert.AreEqual(0, message.RepeatedDouble.Count); + Assert.AreEqual(0, message.RepeatedFixed32.Count); + Assert.AreEqual(0, message.RepeatedFixed64.Count); + Assert.AreEqual(0, message.RepeatedFloat.Count); + Assert.AreEqual(0, message.RepeatedForeignEnum.Count); + Assert.AreEqual(0, message.RepeatedForeignMessage.Count); + Assert.AreEqual(0, message.RepeatedImportEnum.Count); + Assert.AreEqual(0, message.RepeatedImportMessage.Count); + Assert.AreEqual(0, message.RepeatedNestedEnum.Count); + Assert.AreEqual(0, message.RepeatedNestedMessage.Count); + Assert.AreEqual(0, message.RepeatedSfixed32.Count); + Assert.AreEqual(0, message.RepeatedSfixed64.Count); + Assert.AreEqual(0, message.RepeatedSint32.Count); + Assert.AreEqual(0, message.RepeatedSint64.Count); + Assert.AreEqual(0, message.RepeatedString.Count); + Assert.AreEqual(0, message.RepeatedUint32.Count); + Assert.AreEqual(0, message.RepeatedUint64.Count); + + // Oneof fields + Assert.AreEqual(Proto2.TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); + Assert.AreEqual(0, message.OneofUint32); + Assert.AreEqual("", message.OneofString); + Assert.AreEqual(ByteString.Empty, message.OneofBytes); + Assert.IsNull(message.OneofNestedMessage); + + Assert.AreEqual(true, message.DefaultBool); + Assert.AreEqual(ByteString.CopyFromUtf8("world"), message.DefaultBytes); + Assert.AreEqual("123", message.DefaultCord); + Assert.AreEqual(52e3, message.DefaultDouble); + Assert.AreEqual(47, message.DefaultFixed32); + Assert.AreEqual(48, message.DefaultFixed64); + Assert.AreEqual(51.5, message.DefaultFloat); + Assert.AreEqual(ForeignEnum.ForeignBar, message.DefaultForeignEnum); + Assert.AreEqual(ImportEnum.ImportBar, message.DefaultImportEnum); + Assert.AreEqual(41, message.DefaultInt32); + Assert.AreEqual(42, message.DefaultInt64); + Assert.AreEqual(Proto2.TestAllTypes.Types.NestedEnum.Bar, message.DefaultNestedEnum); + Assert.AreEqual(49, message.DefaultSfixed32); + Assert.AreEqual(-50, message.DefaultSfixed64); + Assert.AreEqual(-45, message.DefaultSint32); + Assert.AreEqual(46, message.DefaultSint64); + Assert.AreEqual("hello", message.DefaultString); + Assert.AreEqual("abc", message.DefaultStringPiece); + Assert.AreEqual(43, message.DefaultUint32); + Assert.AreEqual(44, message.DefaultUint64); + + Assert.False(message.HasDefaultBool); + Assert.False(message.HasDefaultBytes); + Assert.False(message.HasDefaultCord); + Assert.False(message.HasDefaultDouble); + Assert.False(message.HasDefaultFixed32); + Assert.False(message.HasDefaultFixed64); + Assert.False(message.HasDefaultFloat); + Assert.False(message.HasDefaultForeignEnum); + Assert.False(message.HasDefaultImportEnum); + Assert.False(message.HasDefaultInt32); + Assert.False(message.HasDefaultInt64); + Assert.False(message.HasDefaultNestedEnum); + Assert.False(message.HasDefaultSfixed32); + Assert.False(message.HasDefaultSfixed64); + Assert.False(message.HasDefaultSint32); + Assert.False(message.HasDefaultSint64); + Assert.False(message.HasDefaultString); + Assert.False(message.HasDefaultStringPiece); + Assert.False(message.HasDefaultUint32); + Assert.False(message.HasDefaultUint64); + } + + [Test] + public void DefaultExtensionValues() + { + var message = new TestAllExtensions(); + Assert.AreEqual(false, message.GetExtension(OptionalBoolExtension)); + Assert.AreEqual(ByteString.Empty, message.GetExtension(OptionalBytesExtension)); + Assert.AreEqual(0.0, message.GetExtension(OptionalDoubleExtension)); + Assert.AreEqual(0, message.GetExtension(OptionalFixed32Extension)); + Assert.AreEqual(0L, message.GetExtension(OptionalFixed64Extension)); + Assert.AreEqual(0.0f, message.GetExtension(OptionalFloatExtension)); + Assert.AreEqual(ForeignEnum.ForeignFoo, message.GetExtension(OptionalForeignEnumExtension)); + Assert.IsNull(message.GetExtension(OptionalForeignMessageExtension)); + Assert.AreEqual(ImportEnum.ImportFoo, message.GetExtension(OptionalImportEnumExtension)); + Assert.IsNull(message.GetExtension(OptionalImportMessageExtension)); + Assert.AreEqual(0, message.GetExtension(OptionalInt32Extension)); + Assert.AreEqual(0L, message.GetExtension(OptionalInt64Extension)); + Assert.AreEqual(Proto2.TestAllTypes.Types.NestedEnum.Foo, message.GetExtension(OptionalNestedEnumExtension)); + Assert.IsNull(message.GetExtension(OptionalNestedMessageExtension)); + Assert.IsNull(message.GetExtension(OptionalPublicImportMessageExtension)); + Assert.AreEqual(0, message.GetExtension(OptionalSfixed32Extension)); + Assert.AreEqual(0L, message.GetExtension(OptionalSfixed64Extension)); + Assert.AreEqual(0, message.GetExtension(OptionalSint32Extension)); + Assert.AreEqual(0L, message.GetExtension(OptionalSint64Extension)); + Assert.AreEqual("", message.GetExtension(OptionalStringExtension)); + Assert.AreEqual(0U, message.GetExtension(OptionalUint32Extension)); + Assert.AreEqual(0UL, message.GetExtension(OptionalUint64Extension)); + + // Repeated fields + Assert.IsNull(message.GetExtension(RepeatedBoolExtension)); + Assert.IsNull(message.GetExtension(RepeatedBytesExtension)); + Assert.IsNull(message.GetExtension(RepeatedDoubleExtension)); + Assert.IsNull(message.GetExtension(RepeatedFixed32Extension)); + Assert.IsNull(message.GetExtension(RepeatedFixed64Extension)); + Assert.IsNull(message.GetExtension(RepeatedFloatExtension)); + Assert.IsNull(message.GetExtension(RepeatedForeignEnumExtension)); + Assert.IsNull(message.GetExtension(RepeatedForeignMessageExtension)); + Assert.IsNull(message.GetExtension(RepeatedImportEnumExtension)); + Assert.IsNull(message.GetExtension(RepeatedImportMessageExtension)); + Assert.IsNull(message.GetExtension(RepeatedNestedEnumExtension)); + Assert.IsNull(message.GetExtension(RepeatedNestedMessageExtension)); + Assert.IsNull(message.GetExtension(RepeatedSfixed32Extension)); + Assert.IsNull(message.GetExtension(RepeatedSfixed64Extension)); + Assert.IsNull(message.GetExtension(RepeatedSint32Extension)); + Assert.IsNull(message.GetExtension(RepeatedSint64Extension)); + Assert.IsNull(message.GetExtension(RepeatedStringExtension)); + Assert.IsNull(message.GetExtension(RepeatedUint32Extension)); + Assert.IsNull(message.GetExtension(RepeatedUint64Extension)); + + // Oneof fields + Assert.AreEqual(0, message.GetExtension(OneofUint32Extension)); + Assert.AreEqual("", message.GetExtension(OneofStringExtension)); + Assert.AreEqual(ByteString.Empty, message.GetExtension(OneofBytesExtension)); + Assert.IsNull(message.GetExtension(OneofNestedMessageExtension)); + + Assert.AreEqual(true, message.GetExtension(DefaultBoolExtension)); + Assert.AreEqual(ByteString.CopyFromUtf8("world"), message.GetExtension(DefaultBytesExtension)); + Assert.AreEqual("123", message.GetExtension(DefaultCordExtension)); + Assert.AreEqual(52e3, message.GetExtension(DefaultDoubleExtension)); + Assert.AreEqual(47, message.GetExtension(DefaultFixed32Extension)); + Assert.AreEqual(48, message.GetExtension(DefaultFixed64Extension)); + Assert.AreEqual(51.5, message.GetExtension(DefaultFloatExtension)); + Assert.AreEqual(ForeignEnum.ForeignBar, message.GetExtension(DefaultForeignEnumExtension)); + Assert.AreEqual(ImportEnum.ImportBar, message.GetExtension(DefaultImportEnumExtension)); + Assert.AreEqual(41, message.GetExtension(DefaultInt32Extension)); + Assert.AreEqual(42, message.GetExtension(DefaultInt64Extension)); + Assert.AreEqual(Proto2.TestAllTypes.Types.NestedEnum.Bar, message.GetExtension(DefaultNestedEnumExtension)); + Assert.AreEqual(49, message.GetExtension(DefaultSfixed32Extension)); + Assert.AreEqual(-50, message.GetExtension(DefaultSfixed64Extension)); + Assert.AreEqual(-45, message.GetExtension(DefaultSint32Extension)); + Assert.AreEqual(46, message.GetExtension(DefaultSint64Extension)); + Assert.AreEqual("hello", message.GetExtension(DefaultStringExtension)); + Assert.AreEqual("abc", message.GetExtension(DefaultStringPieceExtension)); + Assert.AreEqual(43, message.GetExtension(DefaultUint32Extension)); + Assert.AreEqual(44, message.GetExtension(DefaultUint64Extension)); + + Assert.False(message.HasExtension(DefaultBoolExtension)); + Assert.False(message.HasExtension(DefaultBytesExtension)); + Assert.False(message.HasExtension(DefaultCordExtension)); + Assert.False(message.HasExtension(DefaultDoubleExtension)); + Assert.False(message.HasExtension(DefaultFixed32Extension)); + Assert.False(message.HasExtension(DefaultFixed64Extension)); + Assert.False(message.HasExtension(DefaultFloatExtension)); + Assert.False(message.HasExtension(DefaultForeignEnumExtension)); + Assert.False(message.HasExtension(DefaultImportEnumExtension)); + Assert.False(message.HasExtension(DefaultInt32Extension)); + Assert.False(message.HasExtension(DefaultInt64Extension)); + Assert.False(message.HasExtension(DefaultNestedEnumExtension)); + Assert.False(message.HasExtension(DefaultSfixed32Extension)); + Assert.False(message.HasExtension(DefaultSfixed64Extension)); + Assert.False(message.HasExtension(DefaultSint32Extension)); + Assert.False(message.HasExtension(DefaultSint64Extension)); + Assert.False(message.HasExtension(DefaultStringExtension)); + Assert.False(message.HasExtension(DefaultStringPieceExtension)); + Assert.False(message.HasExtension(DefaultUint32Extension)); + Assert.False(message.HasExtension(DefaultUint64Extension)); + } + + [Test] + public void FieldPresence() + { + var message = new TestAllTypes(); + + Assert.False(message.HasOptionalBool); + Assert.False(message.OptionalBool); + + message.OptionalBool = true; + + Assert.True(message.HasOptionalBool); + Assert.True(message.OptionalBool); + + message.OptionalBool = false; + + Assert.True(message.HasOptionalBool); + Assert.False(message.OptionalBool); + + message.ClearOptionalBool(); + + Assert.False(message.HasOptionalBool); + Assert.False(message.OptionalBool); + + Assert.False(message.HasDefaultBool); + Assert.True(message.DefaultBool); + + message.DefaultBool = false; + + Assert.True(message.HasDefaultBool); + Assert.False(message.DefaultBool); + + message.DefaultBool = true; + + Assert.True(message.HasDefaultBool); + Assert.True(message.DefaultBool); + + message.ClearDefaultBool(); + + Assert.False(message.HasDefaultBool); + Assert.True(message.DefaultBool); + } + + [Test] + public void RequiredFields() + { + var message = new TestRequired(); + Assert.False(message.IsInitialized()); + + message.A = 1; + message.B = 2; + message.C = 3; + + Assert.True(message.IsInitialized()); + } + + /// + /// Code was accidentally left in message parser that threw exceptions when missing required fields after parsing. + /// We've decided to not throw exceptions on missing fields, instead leaving it up to the consumer how they + /// want to check and handle missing fields. + /// + [Test] + public void RequiredFieldsNoThrow() + { + Assert.DoesNotThrow(() => MessageParsingHelpers.AssertReadingMessage(TestRequired.Parser, new byte[0], m => { })); + Assert.DoesNotThrow(() => MessageParsingHelpers.AssertReadingMessage(TestRequired.Parser as MessageParser, new byte[0], m => { })); + } + + [Test] + public void RequiredFieldsInExtensions() + { + var message = new TestAllExtensions(); + Assert.True(message.IsInitialized()); + + message.SetExtension(TestRequired.Extensions.Single, new TestRequired()); + + Assert.False(message.IsInitialized()); + + var extensionMessage = message.GetExtension(TestRequired.Extensions.Single); + extensionMessage.A = 1; + extensionMessage.B = 2; + extensionMessage.C = 3; + + Assert.True(message.IsInitialized()); + + message.GetOrInitializeExtension(TestRequired.Extensions.Multi); + + Assert.True(message.IsInitialized()); + + message.GetExtension(TestRequired.Extensions.Multi).Add(new TestRequired()); + + Assert.False(message.IsInitialized()); + + extensionMessage = message.GetExtension(TestRequired.Extensions.Multi)[0]; + extensionMessage.A = 1; + extensionMessage.B = 2; + extensionMessage.C = 3; + + Assert.True(message.IsInitialized()); + + message.SetExtension(UnittestExtensions.OptionalBoolExtension, true); + + Assert.True(message.IsInitialized()); + + message.GetOrInitializeExtension(UnittestExtensions.RepeatedBoolExtension).Add(true); + + Assert.True(message.IsInitialized()); + } + + [Test] + public void RequiredFieldInNestedMessageMapValue() + { + var message = new TestRequiredMap(); + message.Foo.Add(0, new TestRequiredMap.Types.NestedMessage()); + + Assert.False(message.IsInitialized()); + + message.Foo[0].RequiredInt32 = 12; + + Assert.True(message.IsInitialized()); + } + + [Test] + public void RoundTrip_Groups() + { + var message = new TestAllTypes + { + OptionalGroup = new TestAllTypes.Types.OptionalGroup + { + A = 10 + }, + RepeatedGroup = + { + new TestAllTypes.Types.RepeatedGroup { A = 10 }, + new TestAllTypes.Types.RepeatedGroup { A = 20 }, + new TestAllTypes.Types.RepeatedGroup { A = 30 } + } + }; + + MessageParsingHelpers.AssertWritingMessage(message); + + MessageParsingHelpers.AssertRoundtrip(Proto2.TestAllTypes.Parser, message); + } + + [Test] + public void RoundTrip_ExtensionGroups() + { + var message = new TestAllExtensions(); + message.SetExtension(UnittestExtensions.OptionalGroupExtension, new OptionalGroup_extension { A = 10 }); + message.GetOrInitializeExtension(UnittestExtensions.RepeatedGroupExtension).AddRange(new[] + { + new RepeatedGroup_extension { A = 10 }, + new RepeatedGroup_extension { A = 20 }, + new RepeatedGroup_extension { A = 30 } + }); + + MessageParsingHelpers.AssertWritingMessage(message); + + MessageParsingHelpers.AssertRoundtrip( + TestAllExtensions.Parser.WithExtensionRegistry(new ExtensionRegistry() { UnittestExtensions.OptionalGroupExtension, UnittestExtensions.RepeatedGroupExtension }), + message); + } + + [Test] + public void RoundTrip_NestedExtensionGroup() + { + var message = new TestGroupExtension(); + message.SetExtension(TestNestedExtension.Extensions.OptionalGroupExtension, new TestNestedExtension.Types.OptionalGroup_extension { A = 10 }); + + MessageParsingHelpers.AssertWritingMessage(message); + + MessageParsingHelpers.AssertRoundtrip( + TestGroupExtension.Parser.WithExtensionRegistry(new ExtensionRegistry() { TestNestedExtension.Extensions.OptionalGroupExtension }), + message); + } + + [Test] + public void RoundTrip_ParseUsingCodedInput() + { + var message = new TestAllExtensions(); + message.SetExtension(UnittestExtensions.OptionalBoolExtension, true); + byte[] bytes = message.ToByteArray(); + using (CodedInputStream input = new CodedInputStream(bytes)) + { + var parsed = TestAllExtensions.Parser.WithExtensionRegistry(new ExtensionRegistry() { UnittestExtensions.OptionalBoolExtension }).ParseFrom(input); + Assert.AreEqual(message, parsed); + } + } + } +} diff --git a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs index 06af5e9e9a04..41a0b914cb76 100644 --- a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs +++ b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs @@ -1,799 +1,799 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2015 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.IO; -using Google.Protobuf.TestProtos; -using Proto2 = Google.Protobuf.TestProtos.Proto2; -using NUnit.Framework; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Google.Protobuf.WellKnownTypes; - -namespace Google.Protobuf -{ - /// - /// Tests around the generated TestAllTypes message. - /// - public partial class GeneratedMessageTest - { - [Test] - public void EmptyMessageFieldDistinctFromMissingMessageField() - { - // This demonstrates what we're really interested in... - var message1 = new TestAllTypes { SingleForeignMessage = new ForeignMessage() }; - var message2 = new TestAllTypes(); // SingleForeignMessage is null - EqualityTester.AssertInequality(message1, message2); - } - - [Test] - public void DefaultValues() - { - // Single fields - var message = new TestAllTypes(); - Assert.AreEqual(false, message.SingleBool); - Assert.AreEqual(ByteString.Empty, message.SingleBytes); - Assert.AreEqual(0.0, message.SingleDouble); - Assert.AreEqual(0, message.SingleFixed32); - Assert.AreEqual(0L, message.SingleFixed64); - Assert.AreEqual(0.0f, message.SingleFloat); - Assert.AreEqual(ForeignEnum.ForeignUnspecified, message.SingleForeignEnum); - Assert.IsNull(message.SingleForeignMessage); - Assert.AreEqual(ImportEnum.Unspecified, message.SingleImportEnum); - Assert.IsNull(message.SingleImportMessage); - Assert.AreEqual(0, message.SingleInt32); - Assert.AreEqual(0L, message.SingleInt64); - Assert.AreEqual(TestAllTypes.Types.NestedEnum.Unspecified, message.SingleNestedEnum); - Assert.IsNull(message.SingleNestedMessage); - Assert.IsNull(message.SinglePublicImportMessage); - Assert.AreEqual(0, message.SingleSfixed32); - Assert.AreEqual(0L, message.SingleSfixed64); - Assert.AreEqual(0, message.SingleSint32); - Assert.AreEqual(0L, message.SingleSint64); - Assert.AreEqual("", message.SingleString); - Assert.AreEqual(0U, message.SingleUint32); - Assert.AreEqual(0UL, message.SingleUint64); - - // Repeated fields - Assert.AreEqual(0, message.RepeatedBool.Count); - Assert.AreEqual(0, message.RepeatedBytes.Count); - Assert.AreEqual(0, message.RepeatedDouble.Count); - Assert.AreEqual(0, message.RepeatedFixed32.Count); - Assert.AreEqual(0, message.RepeatedFixed64.Count); - Assert.AreEqual(0, message.RepeatedFloat.Count); - Assert.AreEqual(0, message.RepeatedForeignEnum.Count); - Assert.AreEqual(0, message.RepeatedForeignMessage.Count); - Assert.AreEqual(0, message.RepeatedImportEnum.Count); - Assert.AreEqual(0, message.RepeatedImportMessage.Count); - Assert.AreEqual(0, message.RepeatedNestedEnum.Count); - Assert.AreEqual(0, message.RepeatedNestedMessage.Count); - Assert.AreEqual(0, message.RepeatedPublicImportMessage.Count); - Assert.AreEqual(0, message.RepeatedSfixed32.Count); - Assert.AreEqual(0, message.RepeatedSfixed64.Count); - Assert.AreEqual(0, message.RepeatedSint32.Count); - Assert.AreEqual(0, message.RepeatedSint64.Count); - Assert.AreEqual(0, message.RepeatedString.Count); - Assert.AreEqual(0, message.RepeatedUint32.Count); - Assert.AreEqual(0, message.RepeatedUint64.Count); - - // Oneof fields - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); - Assert.AreEqual(0, message.OneofUint32); - Assert.AreEqual("", message.OneofString); - Assert.AreEqual(ByteString.Empty, message.OneofBytes); - Assert.IsNull(message.OneofNestedMessage); - } - - [Test] - public void NullStringAndBytesRejected() - { - var message = new TestAllTypes(); - Assert.Throws(() => message.SingleString = null); - Assert.Throws(() => message.OneofString = null); - Assert.Throws(() => message.SingleBytes = null); - Assert.Throws(() => message.OneofBytes = null); - } - - [Test] - public void RoundTrip_Empty() - { - var message = new TestAllTypes(); - // Without setting any values, there's nothing to write. - byte[] bytes = message.ToByteArray(); - Assert.AreEqual(0, bytes.Length); - - MessageParsingHelpers.AssertWritingMessage(message); - - MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message); - } - - [Test] - public void RoundTrip_SingleValues() - { - var message = new TestAllTypes - { - SingleBool = true, - SingleBytes = ByteString.CopyFrom(1, 2, 3, 4), - SingleDouble = 23.5, - SingleFixed32 = 23, - SingleFixed64 = 1234567890123, - SingleFloat = 12.25f, - SingleForeignEnum = ForeignEnum.ForeignBar, - SingleForeignMessage = new ForeignMessage { C = 10 }, - SingleImportEnum = ImportEnum.ImportBaz, - SingleImportMessage = new ImportMessage { D = 20 }, - SingleInt32 = 100, - SingleInt64 = 3210987654321, - SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, - SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 }, - SinglePublicImportMessage = new PublicImportMessage { E = 54 }, - SingleSfixed32 = -123, - SingleSfixed64 = -12345678901234, - SingleSint32 = -456, - SingleSint64 = -12345678901235, - SingleString = "test", - SingleUint32 = uint.MaxValue, - SingleUint64 = ulong.MaxValue - }; - - MessageParsingHelpers.AssertWritingMessage(message); - - MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message); - } - - [Test] - public void RoundTrip_RepeatedValues() - { - var message = new TestAllTypes - { - RepeatedBool = { true, false }, - RepeatedBytes = { ByteString.CopyFrom(1, 2, 3, 4), ByteString.CopyFrom(5, 6) }, - RepeatedDouble = { -12.25, 23.5 }, - RepeatedFixed32 = { uint.MaxValue, 23 }, - RepeatedFixed64 = { ulong.MaxValue, 1234567890123 }, - RepeatedFloat = { 100f, 12.25f }, - RepeatedForeignEnum = { ForeignEnum.ForeignFoo, ForeignEnum.ForeignBar }, - RepeatedForeignMessage = { new ForeignMessage(), new ForeignMessage { C = 10 } }, - RepeatedImportEnum = { ImportEnum.ImportBaz, ImportEnum.Unspecified }, - RepeatedImportMessage = { new ImportMessage { D = 20 }, new ImportMessage { D = 25 } }, - RepeatedInt32 = { 100, 200 }, - RepeatedInt64 = { 3210987654321, long.MaxValue }, - RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg }, - RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 35 }, new TestAllTypes.Types.NestedMessage { Bb = 10 } }, - RepeatedPublicImportMessage = { new PublicImportMessage { E = 54 }, new PublicImportMessage { E = -1 } }, - RepeatedSfixed32 = { -123, 123 }, - RepeatedSfixed64 = { -12345678901234, 12345678901234 }, - RepeatedSint32 = { -456, 100 }, - RepeatedSint64 = { -12345678901235, 123 }, - RepeatedString = { "foo", "bar" }, - RepeatedUint32 = { uint.MaxValue, uint.MinValue }, - RepeatedUint64 = { ulong.MaxValue, uint.MinValue } - }; - - MessageParsingHelpers.AssertWritingMessage(message); - - MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message); - } - - // Note that not every map within map_unittest_proto3 is used. They all go through very - // similar code paths. The fact that all maps are present is validation that we have codecs - // for every type. - [Test] - public void RoundTrip_Maps() - { - var message = new TestMap - { - MapBoolBool = { - { false, true }, - { true, false } - }, - MapInt32Bytes = { - { 5, ByteString.CopyFrom(6, 7, 8) }, - { 25, ByteString.CopyFrom(1, 2, 3, 4, 5) }, - { 10, ByteString.Empty } - }, - MapInt32ForeignMessage = { - { 0, new ForeignMessage { C = 10 } }, - { 5, new ForeignMessage() }, - }, - MapInt32Enum = { - { 1, MapEnum.Bar }, - { 2000, MapEnum.Foo } - } - }; - - MessageParsingHelpers.AssertWritingMessage(message); - - MessageParsingHelpers.AssertRoundtrip(TestMap.Parser, message); - } - - [Test] - public void MapWithEmptyEntry() - { - var message = new TestMap - { - MapInt32Bytes = { { 0, ByteString.Empty } } - }; - - byte[] bytes = message.ToByteArray(); - Assert.AreEqual(2, bytes.Length); // Tag for field entry (1 byte), length of entry (0; 1 byte) - - MessageParsingHelpers.AssertWritingMessage(message); - - MessageParsingHelpers.AssertReadingMessage( - TestMap.Parser, - bytes, - parsed=> - { - Assert.AreEqual(1, parsed.MapInt32Bytes.Count); - Assert.AreEqual(ByteString.Empty, parsed.MapInt32Bytes[0]); - }); - } - - [Test] - public void MapWithOnlyValue() - { - // Hand-craft the stream to contain a single entry with just a value. - var memoryStream = new MemoryStream(); - var output = new CodedOutputStream(memoryStream); - output.WriteTag(TestMap.MapInt32ForeignMessageFieldNumber, WireFormat.WireType.LengthDelimited); - var nestedMessage = new ForeignMessage { C = 20 }; - // Size of the entry (tag, size written by WriteMessage, data written by WriteMessage) - output.WriteLength(2 + nestedMessage.CalculateSize()); - output.WriteTag(2, WireFormat.WireType.LengthDelimited); - output.WriteMessage(nestedMessage); - output.Flush(); - - MessageParsingHelpers.AssertReadingMessage( - TestMap.Parser, - memoryStream.ToArray(), - parsed => - { - Assert.AreEqual(nestedMessage, parsed.MapInt32ForeignMessage[0]); - }); - } - - [Test] - public void MapWithOnlyKey_PrimitiveValue() - { - // Hand-craft the stream to contain a single entry with just a key. - var memoryStream = new MemoryStream(); - var output = new CodedOutputStream(memoryStream); - output.WriteTag(TestMap.MapInt32DoubleFieldNumber, WireFormat.WireType.LengthDelimited); - int key = 10; - output.WriteLength(1 + CodedOutputStream.ComputeInt32Size(key)); - output.WriteTag(1, WireFormat.WireType.Varint); - output.WriteInt32(key); - output.Flush(); - - MessageParsingHelpers.AssertReadingMessage( - TestMap.Parser, - memoryStream.ToArray(), - parsed => - { - Assert.AreEqual(0.0, parsed.MapInt32Double[key]); - }); - } - - [Test] - public void MapWithOnlyKey_MessageValue() - { - // Hand-craft the stream to contain a single entry with just a key. - var memoryStream = new MemoryStream(); - var output = new CodedOutputStream(memoryStream); - output.WriteTag(TestMap.MapInt32ForeignMessageFieldNumber, WireFormat.WireType.LengthDelimited); - int key = 10; - output.WriteLength(1 + CodedOutputStream.ComputeInt32Size(key)); - output.WriteTag(1, WireFormat.WireType.Varint); - output.WriteInt32(key); - output.Flush(); - - MessageParsingHelpers.AssertReadingMessage( - TestMap.Parser, - memoryStream.ToArray(), - parsed => - { - Assert.AreEqual(new ForeignMessage(), parsed.MapInt32ForeignMessage[key]); - }); - } - - [Test] - public void MapIgnoresExtraFieldsWithinEntryMessages() - { - // Hand-craft the stream to contain a single entry with three fields - var memoryStream = new MemoryStream(); - var output = new CodedOutputStream(memoryStream); - - output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); - - var key = 10; // Field 1 - var value = 20; // Field 2 - var extra = 30; // Field 3 - - // Each field can be represented in a single byte, with a single byte tag. - // Total message size: 6 bytes. - output.WriteLength(6); - output.WriteTag(1, WireFormat.WireType.Varint); - output.WriteInt32(key); - output.WriteTag(2, WireFormat.WireType.Varint); - output.WriteInt32(value); - output.WriteTag(3, WireFormat.WireType.Varint); - output.WriteInt32(extra); - output.Flush(); - - MessageParsingHelpers.AssertReadingMessage( - TestMap.Parser, - memoryStream.ToArray(), - parsed => - { - Assert.AreEqual(value, parsed.MapInt32Int32[key]); - }); - } - - [Test] - public void MapFieldOrderIsIrrelevant() - { - var memoryStream = new MemoryStream(); - var output = new CodedOutputStream(memoryStream); - - output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); - - var key = 10; - var value = 20; - - // Each field can be represented in a single byte, with a single byte tag. - // Total message size: 4 bytes. - output.WriteLength(4); - output.WriteTag(2, WireFormat.WireType.Varint); - output.WriteInt32(value); - output.WriteTag(1, WireFormat.WireType.Varint); - output.WriteInt32(key); - output.Flush(); - - MessageParsingHelpers.AssertReadingMessage( - TestMap.Parser, - memoryStream.ToArray(), - parsed => - { - Assert.AreEqual(value, parsed.MapInt32Int32[key]); - }); - } - - [Test] - public void MapNonContiguousEntries() - { - var memoryStream = new MemoryStream(); - var output = new CodedOutputStream(memoryStream); - - // Message structure: - // Entry for MapInt32Int32 - // Entry for MapStringString - // Entry for MapInt32Int32 - - // First entry - var key1 = 10; - var value1 = 20; - output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); - output.WriteLength(4); - output.WriteTag(1, WireFormat.WireType.Varint); - output.WriteInt32(key1); - output.WriteTag(2, WireFormat.WireType.Varint); - output.WriteInt32(value1); - - // Second entry - var key2 = "a"; - var value2 = "b"; - output.WriteTag(TestMap.MapStringStringFieldNumber, WireFormat.WireType.LengthDelimited); - output.WriteLength(6); // 3 bytes per entry: tag, size, character - output.WriteTag(1, WireFormat.WireType.LengthDelimited); - output.WriteString(key2); - output.WriteTag(2, WireFormat.WireType.LengthDelimited); - output.WriteString(value2); - - // Third entry - var key3 = 15; - var value3 = 25; - output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); - output.WriteLength(4); - output.WriteTag(1, WireFormat.WireType.Varint); - output.WriteInt32(key3); - output.WriteTag(2, WireFormat.WireType.Varint); - output.WriteInt32(value3); - - output.Flush(); - - MessageParsingHelpers.AssertReadingMessage( - TestMap.Parser, - memoryStream.ToArray(), - parsed => - { - var expected = new TestMap - { - MapInt32Int32 = { { key1, value1 }, { key3, value3 } }, - MapStringString = { { key2, value2 } } - }; - Assert.AreEqual(expected, parsed); - }); - } - - [Test] - public void DuplicateKeys_LastEntryWins() - { - var memoryStream = new MemoryStream(); - var output = new CodedOutputStream(memoryStream); - - var key = 10; - var value1 = 20; - var value2 = 30; - - // First entry - output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); - output.WriteLength(4); - output.WriteTag(1, WireFormat.WireType.Varint); - output.WriteInt32(key); - output.WriteTag(2, WireFormat.WireType.Varint); - output.WriteInt32(value1); - - // Second entry - same key, different value - output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); - output.WriteLength(4); - output.WriteTag(1, WireFormat.WireType.Varint); - output.WriteInt32(key); - output.WriteTag(2, WireFormat.WireType.Varint); - output.WriteInt32(value2); - output.Flush(); - - MessageParsingHelpers.AssertReadingMessage( - TestMap.Parser, - memoryStream.ToArray(), - parsed => - { - Assert.AreEqual(value2, parsed.MapInt32Int32[key]); - }); - } - - [Test] - public void CloneSingleNonMessageValues() - { - var original = new TestAllTypes - { - SingleBool = true, - SingleBytes = ByteString.CopyFrom(1, 2, 3, 4), - SingleDouble = 23.5, - SingleFixed32 = 23, - SingleFixed64 = 1234567890123, - SingleFloat = 12.25f, - SingleInt32 = 100, - SingleInt64 = 3210987654321, - SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, - SingleSfixed32 = -123, - SingleSfixed64 = -12345678901234, - SingleSint32 = -456, - SingleSint64 = -12345678901235, - SingleString = "test", - SingleUint32 = uint.MaxValue, - SingleUint64 = ulong.MaxValue - }; - var clone = original.Clone(); - Assert.AreNotSame(original, clone); - Assert.AreEqual(original, clone); - // Just as a single example - clone.SingleInt32 = 150; - Assert.AreNotEqual(original, clone); - } - - [Test] - public void CloneRepeatedNonMessageValues() - { - var original = new TestAllTypes - { - RepeatedBool = { true, false }, - RepeatedBytes = { ByteString.CopyFrom(1, 2, 3, 4), ByteString.CopyFrom(5, 6) }, - RepeatedDouble = { -12.25, 23.5 }, - RepeatedFixed32 = { uint.MaxValue, 23 }, - RepeatedFixed64 = { ulong.MaxValue, 1234567890123 }, - RepeatedFloat = { 100f, 12.25f }, - RepeatedInt32 = { 100, 200 }, - RepeatedInt64 = { 3210987654321, long.MaxValue }, - RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg }, - RepeatedSfixed32 = { -123, 123 }, - RepeatedSfixed64 = { -12345678901234, 12345678901234 }, - RepeatedSint32 = { -456, 100 }, - RepeatedSint64 = { -12345678901235, 123 }, - RepeatedString = { "foo", "bar" }, - RepeatedUint32 = { uint.MaxValue, uint.MinValue }, - RepeatedUint64 = { ulong.MaxValue, uint.MinValue } - }; - - var clone = original.Clone(); - Assert.AreNotSame(original, clone); - Assert.AreEqual(original, clone); - // Just as a single example - clone.RepeatedDouble.Add(25.5); - Assert.AreNotEqual(original, clone); - } - - [Test] - public void CloneSingleMessageField() - { - var original = new TestAllTypes - { - SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } - }; - - var clone = original.Clone(); - Assert.AreNotSame(original, clone); - Assert.AreNotSame(original.SingleNestedMessage, clone.SingleNestedMessage); - Assert.AreEqual(original, clone); - - clone.SingleNestedMessage.Bb = 30; - Assert.AreNotEqual(original, clone); - } - - [Test] - public void CloneRepeatedMessageField() - { - var original = new TestAllTypes - { - RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 20 } } - }; - - var clone = original.Clone(); - Assert.AreNotSame(original, clone); - Assert.AreNotSame(original.RepeatedNestedMessage, clone.RepeatedNestedMessage); - Assert.AreNotSame(original.RepeatedNestedMessage[0], clone.RepeatedNestedMessage[0]); - Assert.AreEqual(original, clone); - - clone.RepeatedNestedMessage[0].Bb = 30; - Assert.AreNotEqual(original, clone); - } - - [Test] - public void CloneOneofField() - { - var original = new TestAllTypes - { - OneofNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } - }; - - var clone = original.Clone(); - Assert.AreNotSame(original, clone); - Assert.AreEqual(original, clone); - - // We should have cloned the message - original.OneofNestedMessage.Bb = 30; - Assert.AreNotEqual(original, clone); - } - - [Test] - public void OneofProperties() - { - // Switch the oneof case between each of the different options, and check everything behaves - // as expected in each case. - var message = new TestAllTypes(); - Assert.AreEqual("", message.OneofString); - Assert.AreEqual(0, message.OneofUint32); - Assert.AreEqual(ByteString.Empty, message.OneofBytes); - Assert.IsNull(message.OneofNestedMessage); - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); - - message.OneofString = "sample"; - Assert.AreEqual("sample", message.OneofString); - Assert.AreEqual(0, message.OneofUint32); - Assert.AreEqual(ByteString.Empty, message.OneofBytes); - Assert.IsNull(message.OneofNestedMessage); - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofString, message.OneofFieldCase); - - var bytes = ByteString.CopyFrom(1, 2, 3); - message.OneofBytes = bytes; - Assert.AreEqual("", message.OneofString); - Assert.AreEqual(0, message.OneofUint32); - Assert.AreEqual(bytes, message.OneofBytes); - Assert.IsNull(message.OneofNestedMessage); - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofBytes, message.OneofFieldCase); - - message.OneofUint32 = 20; - Assert.AreEqual("", message.OneofString); - Assert.AreEqual(20, message.OneofUint32); - Assert.AreEqual(ByteString.Empty, message.OneofBytes); - Assert.IsNull(message.OneofNestedMessage); - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message.OneofFieldCase); - - var nestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 25 }; - message.OneofNestedMessage = nestedMessage; - Assert.AreEqual("", message.OneofString); - Assert.AreEqual(0, message.OneofUint32); - Assert.AreEqual(ByteString.Empty, message.OneofBytes); - Assert.AreEqual(nestedMessage, message.OneofNestedMessage); - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofNestedMessage, message.OneofFieldCase); - - message.ClearOneofField(); - Assert.AreEqual("", message.OneofString); - Assert.AreEqual(0, message.OneofUint32); - Assert.AreEqual(ByteString.Empty, message.OneofBytes); - Assert.IsNull(message.OneofNestedMessage); - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); - } - - [Test] - public void Oneof_DefaultValuesNotEqual() - { - var message1 = new TestAllTypes { OneofString = "" }; - var message2 = new TestAllTypes { OneofUint32 = 0 }; - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofString, message1.OneofFieldCase); - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase); - Assert.AreNotEqual(message1, message2); - } - - [Test] - public void OneofSerialization_NonDefaultValue() - { - var message = new TestAllTypes(); - message.OneofString = "this would take a bit of space"; - message.OneofUint32 = 10; - var bytes = message.ToByteArray(); - Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - no string! - - MessageParsingHelpers.AssertWritingMessage(message); - - MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message, parsedMessage => - { - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, parsedMessage.OneofFieldCase); - }); - } - - [Test] - public void OneofSerialization_DefaultValue() - { - var message = new TestAllTypes(); - message.OneofString = "this would take a bit of space"; - message.OneofUint32 = 0; // This is the default value for UInt32; normally wouldn't be serialized - var bytes = message.ToByteArray(); - Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - it's still serialized - - MessageParsingHelpers.AssertWritingMessage(message); - - MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message, parsedMessage => - { - Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, parsedMessage.OneofFieldCase); - }); - } - - [Test] - public void DiscardUnknownFields_RealDataStillRead() - { - var message = SampleMessages.CreateFullTestAllTypes(); - var stream = new MemoryStream(); - var output = new CodedOutputStream(stream); - var unusedFieldNumber = 23456; - Assert.IsFalse(TestAllTypes.Descriptor.Fields.InDeclarationOrder().Select(x => x.FieldNumber).Contains(unusedFieldNumber)); - output.WriteTag(unusedFieldNumber, WireFormat.WireType.LengthDelimited); - output.WriteString("ignore me"); - message.WriteTo(output); - output.Flush(); - - MessageParsingHelpers.AssertReadingMessage( - TestAllTypes.Parser, - stream.ToArray(), - parsed => - { - // TODO(jieluo): Add test back when DiscardUnknownFields API is supported. - // Assert.AreEqual(message, parsed); - }); - } - - [Test] - public void DiscardUnknownFields_AllTypes() - { - // Simple way of ensuring we can skip all kinds of fields. - var data = SampleMessages.CreateFullTestAllTypes().ToByteArray(); - var empty = Empty.Parser.ParseFrom(data); - - MessageParsingHelpers.AssertReadingMessage( - Empty.Parser, - data, - parsed => - { - // TODO(jieluo): Add test back when DiscardUnknownFields API is supported. - // Assert.AreNotEqual(new Empty(), empty); - }); - } - - // This was originally seen as a conformance test failure. - [Test] - public void TruncatedMessageFieldThrows() - { - // 130, 3 is the message tag - // 1 is the data length - but there's no data. - var data = new byte[] { 130, 3, 1 }; - MessageParsingHelpers.AssertReadingMessageThrows(TestAllTypes.Parser, data); - } - - /// - /// Demonstrates current behaviour with an extraneous end group tag - see issue 688 - /// for details; we may want to change this. - /// - [Test] - public void ExtraEndGroupThrows() - { - var message = SampleMessages.CreateFullTestAllTypes(); - var stream = new MemoryStream(); - var output = new CodedOutputStream(stream); - - output.WriteTag(TestAllTypes.SingleFixed32FieldNumber, WireFormat.WireType.Fixed32); - output.WriteFixed32(123); - output.WriteTag(100, WireFormat.WireType.EndGroup); - - output.Flush(); - - stream.Position = 0; - MessageParsingHelpers.AssertReadingMessageThrows(TestAllTypes.Parser, stream.ToArray()); - } - - [Test] - public void CustomDiagnosticMessage_DirectToStringCall() - { - var message = new ForeignMessage { C = 31 }; - Assert.AreEqual("{ \"c\": 31, \"@cInHex\": \"1f\" }", message.ToString()); - Assert.AreEqual("{ \"c\": 31 }", JsonFormatter.Default.Format(message)); - } - - [Test] - public void CustomDiagnosticMessage_Nested() - { - var message = new TestAllTypes { SingleForeignMessage = new ForeignMessage { C = 16 } }; - Assert.AreEqual("{ \"singleForeignMessage\": { \"c\": 16, \"@cInHex\": \"10\" } }", message.ToString()); - Assert.AreEqual("{ \"singleForeignMessage\": { \"c\": 16 } }", JsonFormatter.Default.Format(message)); - } - - [Test] - public void CustomDiagnosticMessage_DirectToTextWriterCall() - { - var message = new ForeignMessage { C = 31 }; - var writer = new StringWriter(); - JsonFormatter.Default.Format(message, writer); - Assert.AreEqual("{ \"c\": 31 }", writer.ToString()); - } - - [Test] - public void NaNComparisons() - { - var message1 = new TestAllTypes { SingleDouble = SampleNaNs.Regular }; - var message2 = new TestAllTypes { SingleDouble = SampleNaNs.PayloadFlipped }; - var message3 = new TestAllTypes { SingleDouble = SampleNaNs.Regular }; - - EqualityTester.AssertInequality(message1, message2); - EqualityTester.AssertEquality(message1, message3); - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.IO; +using Google.Protobuf.TestProtos; +using Proto2 = Google.Protobuf.TestProtos.Proto2; +using NUnit.Framework; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Google.Protobuf.WellKnownTypes; + +namespace Google.Protobuf +{ + /// + /// Tests around the generated TestAllTypes message. + /// + public partial class GeneratedMessageTest + { + [Test] + public void EmptyMessageFieldDistinctFromMissingMessageField() + { + // This demonstrates what we're really interested in... + var message1 = new TestAllTypes { SingleForeignMessage = new ForeignMessage() }; + var message2 = new TestAllTypes(); // SingleForeignMessage is null + EqualityTester.AssertInequality(message1, message2); + } + + [Test] + public void DefaultValues() + { + // Single fields + var message = new TestAllTypes(); + Assert.AreEqual(false, message.SingleBool); + Assert.AreEqual(ByteString.Empty, message.SingleBytes); + Assert.AreEqual(0.0, message.SingleDouble); + Assert.AreEqual(0, message.SingleFixed32); + Assert.AreEqual(0L, message.SingleFixed64); + Assert.AreEqual(0.0f, message.SingleFloat); + Assert.AreEqual(ForeignEnum.ForeignUnspecified, message.SingleForeignEnum); + Assert.IsNull(message.SingleForeignMessage); + Assert.AreEqual(ImportEnum.Unspecified, message.SingleImportEnum); + Assert.IsNull(message.SingleImportMessage); + Assert.AreEqual(0, message.SingleInt32); + Assert.AreEqual(0L, message.SingleInt64); + Assert.AreEqual(TestAllTypes.Types.NestedEnum.Unspecified, message.SingleNestedEnum); + Assert.IsNull(message.SingleNestedMessage); + Assert.IsNull(message.SinglePublicImportMessage); + Assert.AreEqual(0, message.SingleSfixed32); + Assert.AreEqual(0L, message.SingleSfixed64); + Assert.AreEqual(0, message.SingleSint32); + Assert.AreEqual(0L, message.SingleSint64); + Assert.AreEqual("", message.SingleString); + Assert.AreEqual(0U, message.SingleUint32); + Assert.AreEqual(0UL, message.SingleUint64); + + // Repeated fields + Assert.AreEqual(0, message.RepeatedBool.Count); + Assert.AreEqual(0, message.RepeatedBytes.Count); + Assert.AreEqual(0, message.RepeatedDouble.Count); + Assert.AreEqual(0, message.RepeatedFixed32.Count); + Assert.AreEqual(0, message.RepeatedFixed64.Count); + Assert.AreEqual(0, message.RepeatedFloat.Count); + Assert.AreEqual(0, message.RepeatedForeignEnum.Count); + Assert.AreEqual(0, message.RepeatedForeignMessage.Count); + Assert.AreEqual(0, message.RepeatedImportEnum.Count); + Assert.AreEqual(0, message.RepeatedImportMessage.Count); + Assert.AreEqual(0, message.RepeatedNestedEnum.Count); + Assert.AreEqual(0, message.RepeatedNestedMessage.Count); + Assert.AreEqual(0, message.RepeatedPublicImportMessage.Count); + Assert.AreEqual(0, message.RepeatedSfixed32.Count); + Assert.AreEqual(0, message.RepeatedSfixed64.Count); + Assert.AreEqual(0, message.RepeatedSint32.Count); + Assert.AreEqual(0, message.RepeatedSint64.Count); + Assert.AreEqual(0, message.RepeatedString.Count); + Assert.AreEqual(0, message.RepeatedUint32.Count); + Assert.AreEqual(0, message.RepeatedUint64.Count); + + // Oneof fields + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); + Assert.AreEqual(0, message.OneofUint32); + Assert.AreEqual("", message.OneofString); + Assert.AreEqual(ByteString.Empty, message.OneofBytes); + Assert.IsNull(message.OneofNestedMessage); + } + + [Test] + public void NullStringAndBytesRejected() + { + var message = new TestAllTypes(); + Assert.Throws(() => message.SingleString = null); + Assert.Throws(() => message.OneofString = null); + Assert.Throws(() => message.SingleBytes = null); + Assert.Throws(() => message.OneofBytes = null); + } + + [Test] + public void RoundTrip_Empty() + { + var message = new TestAllTypes(); + // Without setting any values, there's nothing to write. + byte[] bytes = message.ToByteArray(); + Assert.AreEqual(0, bytes.Length); + + MessageParsingHelpers.AssertWritingMessage(message); + + MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message); + } + + [Test] + public void RoundTrip_SingleValues() + { + var message = new TestAllTypes + { + SingleBool = true, + SingleBytes = ByteString.CopyFrom(1, 2, 3, 4), + SingleDouble = 23.5, + SingleFixed32 = 23, + SingleFixed64 = 1234567890123, + SingleFloat = 12.25f, + SingleForeignEnum = ForeignEnum.ForeignBar, + SingleForeignMessage = new ForeignMessage { C = 10 }, + SingleImportEnum = ImportEnum.ImportBaz, + SingleImportMessage = new ImportMessage { D = 20 }, + SingleInt32 = 100, + SingleInt64 = 3210987654321, + SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, + SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 }, + SinglePublicImportMessage = new PublicImportMessage { E = 54 }, + SingleSfixed32 = -123, + SingleSfixed64 = -12345678901234, + SingleSint32 = -456, + SingleSint64 = -12345678901235, + SingleString = "test", + SingleUint32 = uint.MaxValue, + SingleUint64 = ulong.MaxValue + }; + + MessageParsingHelpers.AssertWritingMessage(message); + + MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message); + } + + [Test] + public void RoundTrip_RepeatedValues() + { + var message = new TestAllTypes + { + RepeatedBool = { true, false }, + RepeatedBytes = { ByteString.CopyFrom(1, 2, 3, 4), ByteString.CopyFrom(5, 6) }, + RepeatedDouble = { -12.25, 23.5 }, + RepeatedFixed32 = { uint.MaxValue, 23 }, + RepeatedFixed64 = { ulong.MaxValue, 1234567890123 }, + RepeatedFloat = { 100f, 12.25f }, + RepeatedForeignEnum = { ForeignEnum.ForeignFoo, ForeignEnum.ForeignBar }, + RepeatedForeignMessage = { new ForeignMessage(), new ForeignMessage { C = 10 } }, + RepeatedImportEnum = { ImportEnum.ImportBaz, ImportEnum.Unspecified }, + RepeatedImportMessage = { new ImportMessage { D = 20 }, new ImportMessage { D = 25 } }, + RepeatedInt32 = { 100, 200 }, + RepeatedInt64 = { 3210987654321, long.MaxValue }, + RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg }, + RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 35 }, new TestAllTypes.Types.NestedMessage { Bb = 10 } }, + RepeatedPublicImportMessage = { new PublicImportMessage { E = 54 }, new PublicImportMessage { E = -1 } }, + RepeatedSfixed32 = { -123, 123 }, + RepeatedSfixed64 = { -12345678901234, 12345678901234 }, + RepeatedSint32 = { -456, 100 }, + RepeatedSint64 = { -12345678901235, 123 }, + RepeatedString = { "foo", "bar" }, + RepeatedUint32 = { uint.MaxValue, uint.MinValue }, + RepeatedUint64 = { ulong.MaxValue, uint.MinValue } + }; + + MessageParsingHelpers.AssertWritingMessage(message); + + MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message); + } + + // Note that not every map within map_unittest_proto3 is used. They all go through very + // similar code paths. The fact that all maps are present is validation that we have codecs + // for every type. + [Test] + public void RoundTrip_Maps() + { + var message = new TestMap + { + MapBoolBool = { + { false, true }, + { true, false } + }, + MapInt32Bytes = { + { 5, ByteString.CopyFrom(6, 7, 8) }, + { 25, ByteString.CopyFrom(1, 2, 3, 4, 5) }, + { 10, ByteString.Empty } + }, + MapInt32ForeignMessage = { + { 0, new ForeignMessage { C = 10 } }, + { 5, new ForeignMessage() }, + }, + MapInt32Enum = { + { 1, MapEnum.Bar }, + { 2000, MapEnum.Foo } + } + }; + + MessageParsingHelpers.AssertWritingMessage(message); + + MessageParsingHelpers.AssertRoundtrip(TestMap.Parser, message); + } + + [Test] + public void MapWithEmptyEntry() + { + var message = new TestMap + { + MapInt32Bytes = { { 0, ByteString.Empty } } + }; + + byte[] bytes = message.ToByteArray(); + Assert.AreEqual(2, bytes.Length); // Tag for field entry (1 byte), length of entry (0; 1 byte) + + MessageParsingHelpers.AssertWritingMessage(message); + + MessageParsingHelpers.AssertReadingMessage( + TestMap.Parser, + bytes, + parsed=> + { + Assert.AreEqual(1, parsed.MapInt32Bytes.Count); + Assert.AreEqual(ByteString.Empty, parsed.MapInt32Bytes[0]); + }); + } + + [Test] + public void MapWithOnlyValue() + { + // Hand-craft the stream to contain a single entry with just a value. + var memoryStream = new MemoryStream(); + var output = new CodedOutputStream(memoryStream); + output.WriteTag(TestMap.MapInt32ForeignMessageFieldNumber, WireFormat.WireType.LengthDelimited); + var nestedMessage = new ForeignMessage { C = 20 }; + // Size of the entry (tag, size written by WriteMessage, data written by WriteMessage) + output.WriteLength(2 + nestedMessage.CalculateSize()); + output.WriteTag(2, WireFormat.WireType.LengthDelimited); + output.WriteMessage(nestedMessage); + output.Flush(); + + MessageParsingHelpers.AssertReadingMessage( + TestMap.Parser, + memoryStream.ToArray(), + parsed => + { + Assert.AreEqual(nestedMessage, parsed.MapInt32ForeignMessage[0]); + }); + } + + [Test] + public void MapWithOnlyKey_PrimitiveValue() + { + // Hand-craft the stream to contain a single entry with just a key. + var memoryStream = new MemoryStream(); + var output = new CodedOutputStream(memoryStream); + output.WriteTag(TestMap.MapInt32DoubleFieldNumber, WireFormat.WireType.LengthDelimited); + int key = 10; + output.WriteLength(1 + CodedOutputStream.ComputeInt32Size(key)); + output.WriteTag(1, WireFormat.WireType.Varint); + output.WriteInt32(key); + output.Flush(); + + MessageParsingHelpers.AssertReadingMessage( + TestMap.Parser, + memoryStream.ToArray(), + parsed => + { + Assert.AreEqual(0.0, parsed.MapInt32Double[key]); + }); + } + + [Test] + public void MapWithOnlyKey_MessageValue() + { + // Hand-craft the stream to contain a single entry with just a key. + var memoryStream = new MemoryStream(); + var output = new CodedOutputStream(memoryStream); + output.WriteTag(TestMap.MapInt32ForeignMessageFieldNumber, WireFormat.WireType.LengthDelimited); + int key = 10; + output.WriteLength(1 + CodedOutputStream.ComputeInt32Size(key)); + output.WriteTag(1, WireFormat.WireType.Varint); + output.WriteInt32(key); + output.Flush(); + + MessageParsingHelpers.AssertReadingMessage( + TestMap.Parser, + memoryStream.ToArray(), + parsed => + { + Assert.AreEqual(new ForeignMessage(), parsed.MapInt32ForeignMessage[key]); + }); + } + + [Test] + public void MapIgnoresExtraFieldsWithinEntryMessages() + { + // Hand-craft the stream to contain a single entry with three fields + var memoryStream = new MemoryStream(); + var output = new CodedOutputStream(memoryStream); + + output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); + + var key = 10; // Field 1 + var value = 20; // Field 2 + var extra = 30; // Field 3 + + // Each field can be represented in a single byte, with a single byte tag. + // Total message size: 6 bytes. + output.WriteLength(6); + output.WriteTag(1, WireFormat.WireType.Varint); + output.WriteInt32(key); + output.WriteTag(2, WireFormat.WireType.Varint); + output.WriteInt32(value); + output.WriteTag(3, WireFormat.WireType.Varint); + output.WriteInt32(extra); + output.Flush(); + + MessageParsingHelpers.AssertReadingMessage( + TestMap.Parser, + memoryStream.ToArray(), + parsed => + { + Assert.AreEqual(value, parsed.MapInt32Int32[key]); + }); + } + + [Test] + public void MapFieldOrderIsIrrelevant() + { + var memoryStream = new MemoryStream(); + var output = new CodedOutputStream(memoryStream); + + output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); + + var key = 10; + var value = 20; + + // Each field can be represented in a single byte, with a single byte tag. + // Total message size: 4 bytes. + output.WriteLength(4); + output.WriteTag(2, WireFormat.WireType.Varint); + output.WriteInt32(value); + output.WriteTag(1, WireFormat.WireType.Varint); + output.WriteInt32(key); + output.Flush(); + + MessageParsingHelpers.AssertReadingMessage( + TestMap.Parser, + memoryStream.ToArray(), + parsed => + { + Assert.AreEqual(value, parsed.MapInt32Int32[key]); + }); + } + + [Test] + public void MapNonContiguousEntries() + { + var memoryStream = new MemoryStream(); + var output = new CodedOutputStream(memoryStream); + + // Message structure: + // Entry for MapInt32Int32 + // Entry for MapStringString + // Entry for MapInt32Int32 + + // First entry + var key1 = 10; + var value1 = 20; + output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); + output.WriteLength(4); + output.WriteTag(1, WireFormat.WireType.Varint); + output.WriteInt32(key1); + output.WriteTag(2, WireFormat.WireType.Varint); + output.WriteInt32(value1); + + // Second entry + var key2 = "a"; + var value2 = "b"; + output.WriteTag(TestMap.MapStringStringFieldNumber, WireFormat.WireType.LengthDelimited); + output.WriteLength(6); // 3 bytes per entry: tag, size, character + output.WriteTag(1, WireFormat.WireType.LengthDelimited); + output.WriteString(key2); + output.WriteTag(2, WireFormat.WireType.LengthDelimited); + output.WriteString(value2); + + // Third entry + var key3 = 15; + var value3 = 25; + output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); + output.WriteLength(4); + output.WriteTag(1, WireFormat.WireType.Varint); + output.WriteInt32(key3); + output.WriteTag(2, WireFormat.WireType.Varint); + output.WriteInt32(value3); + + output.Flush(); + + MessageParsingHelpers.AssertReadingMessage( + TestMap.Parser, + memoryStream.ToArray(), + parsed => + { + var expected = new TestMap + { + MapInt32Int32 = { { key1, value1 }, { key3, value3 } }, + MapStringString = { { key2, value2 } } + }; + Assert.AreEqual(expected, parsed); + }); + } + + [Test] + public void DuplicateKeys_LastEntryWins() + { + var memoryStream = new MemoryStream(); + var output = new CodedOutputStream(memoryStream); + + var key = 10; + var value1 = 20; + var value2 = 30; + + // First entry + output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); + output.WriteLength(4); + output.WriteTag(1, WireFormat.WireType.Varint); + output.WriteInt32(key); + output.WriteTag(2, WireFormat.WireType.Varint); + output.WriteInt32(value1); + + // Second entry - same key, different value + output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); + output.WriteLength(4); + output.WriteTag(1, WireFormat.WireType.Varint); + output.WriteInt32(key); + output.WriteTag(2, WireFormat.WireType.Varint); + output.WriteInt32(value2); + output.Flush(); + + MessageParsingHelpers.AssertReadingMessage( + TestMap.Parser, + memoryStream.ToArray(), + parsed => + { + Assert.AreEqual(value2, parsed.MapInt32Int32[key]); + }); + } + + [Test] + public void CloneSingleNonMessageValues() + { + var original = new TestAllTypes + { + SingleBool = true, + SingleBytes = ByteString.CopyFrom(1, 2, 3, 4), + SingleDouble = 23.5, + SingleFixed32 = 23, + SingleFixed64 = 1234567890123, + SingleFloat = 12.25f, + SingleInt32 = 100, + SingleInt64 = 3210987654321, + SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, + SingleSfixed32 = -123, + SingleSfixed64 = -12345678901234, + SingleSint32 = -456, + SingleSint64 = -12345678901235, + SingleString = "test", + SingleUint32 = uint.MaxValue, + SingleUint64 = ulong.MaxValue + }; + var clone = original.Clone(); + Assert.AreNotSame(original, clone); + Assert.AreEqual(original, clone); + // Just as a single example + clone.SingleInt32 = 150; + Assert.AreNotEqual(original, clone); + } + + [Test] + public void CloneRepeatedNonMessageValues() + { + var original = new TestAllTypes + { + RepeatedBool = { true, false }, + RepeatedBytes = { ByteString.CopyFrom(1, 2, 3, 4), ByteString.CopyFrom(5, 6) }, + RepeatedDouble = { -12.25, 23.5 }, + RepeatedFixed32 = { uint.MaxValue, 23 }, + RepeatedFixed64 = { ulong.MaxValue, 1234567890123 }, + RepeatedFloat = { 100f, 12.25f }, + RepeatedInt32 = { 100, 200 }, + RepeatedInt64 = { 3210987654321, long.MaxValue }, + RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg }, + RepeatedSfixed32 = { -123, 123 }, + RepeatedSfixed64 = { -12345678901234, 12345678901234 }, + RepeatedSint32 = { -456, 100 }, + RepeatedSint64 = { -12345678901235, 123 }, + RepeatedString = { "foo", "bar" }, + RepeatedUint32 = { uint.MaxValue, uint.MinValue }, + RepeatedUint64 = { ulong.MaxValue, uint.MinValue } + }; + + var clone = original.Clone(); + Assert.AreNotSame(original, clone); + Assert.AreEqual(original, clone); + // Just as a single example + clone.RepeatedDouble.Add(25.5); + Assert.AreNotEqual(original, clone); + } + + [Test] + public void CloneSingleMessageField() + { + var original = new TestAllTypes + { + SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } + }; + + var clone = original.Clone(); + Assert.AreNotSame(original, clone); + Assert.AreNotSame(original.SingleNestedMessage, clone.SingleNestedMessage); + Assert.AreEqual(original, clone); + + clone.SingleNestedMessage.Bb = 30; + Assert.AreNotEqual(original, clone); + } + + [Test] + public void CloneRepeatedMessageField() + { + var original = new TestAllTypes + { + RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 20 } } + }; + + var clone = original.Clone(); + Assert.AreNotSame(original, clone); + Assert.AreNotSame(original.RepeatedNestedMessage, clone.RepeatedNestedMessage); + Assert.AreNotSame(original.RepeatedNestedMessage[0], clone.RepeatedNestedMessage[0]); + Assert.AreEqual(original, clone); + + clone.RepeatedNestedMessage[0].Bb = 30; + Assert.AreNotEqual(original, clone); + } + + [Test] + public void CloneOneofField() + { + var original = new TestAllTypes + { + OneofNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } + }; + + var clone = original.Clone(); + Assert.AreNotSame(original, clone); + Assert.AreEqual(original, clone); + + // We should have cloned the message + original.OneofNestedMessage.Bb = 30; + Assert.AreNotEqual(original, clone); + } + + [Test] + public void OneofProperties() + { + // Switch the oneof case between each of the different options, and check everything behaves + // as expected in each case. + var message = new TestAllTypes(); + Assert.AreEqual("", message.OneofString); + Assert.AreEqual(0, message.OneofUint32); + Assert.AreEqual(ByteString.Empty, message.OneofBytes); + Assert.IsNull(message.OneofNestedMessage); + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); + + message.OneofString = "sample"; + Assert.AreEqual("sample", message.OneofString); + Assert.AreEqual(0, message.OneofUint32); + Assert.AreEqual(ByteString.Empty, message.OneofBytes); + Assert.IsNull(message.OneofNestedMessage); + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofString, message.OneofFieldCase); + + var bytes = ByteString.CopyFrom(1, 2, 3); + message.OneofBytes = bytes; + Assert.AreEqual("", message.OneofString); + Assert.AreEqual(0, message.OneofUint32); + Assert.AreEqual(bytes, message.OneofBytes); + Assert.IsNull(message.OneofNestedMessage); + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofBytes, message.OneofFieldCase); + + message.OneofUint32 = 20; + Assert.AreEqual("", message.OneofString); + Assert.AreEqual(20, message.OneofUint32); + Assert.AreEqual(ByteString.Empty, message.OneofBytes); + Assert.IsNull(message.OneofNestedMessage); + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message.OneofFieldCase); + + var nestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 25 }; + message.OneofNestedMessage = nestedMessage; + Assert.AreEqual("", message.OneofString); + Assert.AreEqual(0, message.OneofUint32); + Assert.AreEqual(ByteString.Empty, message.OneofBytes); + Assert.AreEqual(nestedMessage, message.OneofNestedMessage); + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofNestedMessage, message.OneofFieldCase); + + message.ClearOneofField(); + Assert.AreEqual("", message.OneofString); + Assert.AreEqual(0, message.OneofUint32); + Assert.AreEqual(ByteString.Empty, message.OneofBytes); + Assert.IsNull(message.OneofNestedMessage); + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); + } + + [Test] + public void Oneof_DefaultValuesNotEqual() + { + var message1 = new TestAllTypes { OneofString = "" }; + var message2 = new TestAllTypes { OneofUint32 = 0 }; + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofString, message1.OneofFieldCase); + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase); + Assert.AreNotEqual(message1, message2); + } + + [Test] + public void OneofSerialization_NonDefaultValue() + { + var message = new TestAllTypes(); + message.OneofString = "this would take a bit of space"; + message.OneofUint32 = 10; + var bytes = message.ToByteArray(); + Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - no string! + + MessageParsingHelpers.AssertWritingMessage(message); + + MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message, parsedMessage => + { + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, parsedMessage.OneofFieldCase); + }); + } + + [Test] + public void OneofSerialization_DefaultValue() + { + var message = new TestAllTypes(); + message.OneofString = "this would take a bit of space"; + message.OneofUint32 = 0; // This is the default value for UInt32; normally wouldn't be serialized + var bytes = message.ToByteArray(); + Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - it's still serialized + + MessageParsingHelpers.AssertWritingMessage(message); + + MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message, parsedMessage => + { + Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, parsedMessage.OneofFieldCase); + }); + } + + [Test] + public void DiscardUnknownFields_RealDataStillRead() + { + var message = SampleMessages.CreateFullTestAllTypes(); + var stream = new MemoryStream(); + var output = new CodedOutputStream(stream); + var unusedFieldNumber = 23456; + Assert.IsFalse(TestAllTypes.Descriptor.Fields.InDeclarationOrder().Select(x => x.FieldNumber).Contains(unusedFieldNumber)); + output.WriteTag(unusedFieldNumber, WireFormat.WireType.LengthDelimited); + output.WriteString("ignore me"); + message.WriteTo(output); + output.Flush(); + + MessageParsingHelpers.AssertReadingMessage( + TestAllTypes.Parser, + stream.ToArray(), + parsed => + { + // TODO(jieluo): Add test back when DiscardUnknownFields API is supported. + // Assert.AreEqual(message, parsed); + }); + } + + [Test] + public void DiscardUnknownFields_AllTypes() + { + // Simple way of ensuring we can skip all kinds of fields. + var data = SampleMessages.CreateFullTestAllTypes().ToByteArray(); + var empty = Empty.Parser.ParseFrom(data); + + MessageParsingHelpers.AssertReadingMessage( + Empty.Parser, + data, + parsed => + { + // TODO(jieluo): Add test back when DiscardUnknownFields API is supported. + // Assert.AreNotEqual(new Empty(), empty); + }); + } + + // This was originally seen as a conformance test failure. + [Test] + public void TruncatedMessageFieldThrows() + { + // 130, 3 is the message tag + // 1 is the data length - but there's no data. + var data = new byte[] { 130, 3, 1 }; + MessageParsingHelpers.AssertReadingMessageThrows(TestAllTypes.Parser, data); + } + + /// + /// Demonstrates current behaviour with an extraneous end group tag - see issue 688 + /// for details; we may want to change this. + /// + [Test] + public void ExtraEndGroupThrows() + { + var message = SampleMessages.CreateFullTestAllTypes(); + var stream = new MemoryStream(); + var output = new CodedOutputStream(stream); + + output.WriteTag(TestAllTypes.SingleFixed32FieldNumber, WireFormat.WireType.Fixed32); + output.WriteFixed32(123); + output.WriteTag(100, WireFormat.WireType.EndGroup); + + output.Flush(); + + stream.Position = 0; + MessageParsingHelpers.AssertReadingMessageThrows(TestAllTypes.Parser, stream.ToArray()); + } + + [Test] + public void CustomDiagnosticMessage_DirectToStringCall() + { + var message = new ForeignMessage { C = 31 }; + Assert.AreEqual("{ \"c\": 31, \"@cInHex\": \"1f\" }", message.ToString()); + Assert.AreEqual("{ \"c\": 31 }", JsonFormatter.Default.Format(message)); + } + + [Test] + public void CustomDiagnosticMessage_Nested() + { + var message = new TestAllTypes { SingleForeignMessage = new ForeignMessage { C = 16 } }; + Assert.AreEqual("{ \"singleForeignMessage\": { \"c\": 16, \"@cInHex\": \"10\" } }", message.ToString()); + Assert.AreEqual("{ \"singleForeignMessage\": { \"c\": 16 } }", JsonFormatter.Default.Format(message)); + } + + [Test] + public void CustomDiagnosticMessage_DirectToTextWriterCall() + { + var message = new ForeignMessage { C = 31 }; + var writer = new StringWriter(); + JsonFormatter.Default.Format(message, writer); + Assert.AreEqual("{ \"c\": 31 }", writer.ToString()); + } + + [Test] + public void NaNComparisons() + { + var message1 = new TestAllTypes { SingleDouble = SampleNaNs.Regular }; + var message2 = new TestAllTypes { SingleDouble = SampleNaNs.PayloadFlipped }; + var message3 = new TestAllTypes { SingleDouble = SampleNaNs.Regular }; + + EqualityTester.AssertInequality(message1, message2); + EqualityTester.AssertEquality(message1, message3); + } + } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf.Test/IssuesTest.cs b/csharp/src/Google.Protobuf.Test/IssuesTest.cs index 2904c461df30..a46467ca0707 100644 --- a/csharp/src/Google.Protobuf.Test/IssuesTest.cs +++ b/csharp/src/Google.Protobuf.Test/IssuesTest.cs @@ -1,116 +1,116 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using Google.Protobuf.Reflection; -using UnitTest.Issues.TestProtos; -using NUnit.Framework; -using System.IO; -using static UnitTest.Issues.TestProtos.OneofMerging.Types; - -namespace Google.Protobuf -{ - /// - /// Tests for issues which aren't easily compartmentalized into other unit tests. - /// - public class IssuesTest - { - // Issue 45 - [Test] - public void FieldCalledItem() - { - ItemField message = new ItemField { Item = 3 }; - FieldDescriptor field = ItemField.Descriptor.FindFieldByName("item"); - Assert.NotNull(field); - Assert.AreEqual(3, (int)field.Accessor.GetValue(message)); - } - - [Test] - public void ReservedNames() - { - var message = new ReservedNames { Types_ = 10, Descriptor_ = 20 }; - // Underscores aren't reflected in the JSON. - Assert.AreEqual("{ \"types\": 10, \"descriptor\": 20 }", message.ToString()); - } - - [Test] - public void JsonNameParseTest() - { - var settings = new JsonParser.Settings(10, TypeRegistry.FromFiles(UnittestIssuesReflection.Descriptor)); - var parser = new JsonParser(settings); - - // It is safe to use either original field name or explicitly specified json_name - Assert.AreEqual(new TestJsonName { Name = "test", Description = "test2", Guid = "test3" }, - parser.Parse("{ \"name\": \"test\", \"desc\": \"test2\", \"guid\": \"test3\" }")); - } - - [Test] - public void JsonNameFormatTest() - { - var message = new TestJsonName { Name = "test", Description = "test2", Guid = "test3" }; - Assert.AreEqual("{ \"name\": \"test\", \"desc\": \"test2\", \"exid\": \"test3\" }", - JsonFormatter.Default.Format(message)); - } - - [Test] - public void OneofMerging() - { - var message1 = new OneofMerging { Nested = new Nested { X = 10 } }; - var message2 = new OneofMerging { Nested = new Nested { Y = 20 } }; - var expected = new OneofMerging { Nested = new Nested { X = 10, Y = 20 } }; - - var merged = message1.Clone(); - merged.MergeFrom(message2); - Assert.AreEqual(expected, merged); - } - - // Check that a tag immediately followed by end of limit can still be read. - [Test] - public void CodedInputStream_LimitReachedRightAfterTag() - { - MemoryStream ms = new MemoryStream(); - var cos = new CodedOutputStream(ms); - cos.WriteTag(11, WireFormat.WireType.Varint); - Assert.AreEqual(1, cos.Position); - cos.WriteString("some extra padding"); // ensure is currentLimit distinct from the end of the buffer. - cos.Flush(); - - var cis = new CodedInputStream(ms.ToArray()); - cis.PushLimit(1); // make sure we reach the limit right after reading the tag. - - // we still must read the tag correctly, even though the tag is at the very end of our limited input - // (which is a corner case and will most likely result in an error when trying to read value of the field - // described by this tag, but it would be a logical error not to read the tag that's actually present). - // See https://github.com/protocolbuffers/protobuf/pull/7289 - cis.AssertNextTag(WireFormat.MakeTag(11, WireFormat.WireType.Varint)); - } - } -} +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using Google.Protobuf.Reflection; +using UnitTest.Issues.TestProtos; +using NUnit.Framework; +using System.IO; +using static UnitTest.Issues.TestProtos.OneofMerging.Types; + +namespace Google.Protobuf +{ + /// + /// Tests for issues which aren't easily compartmentalized into other unit tests. + /// + public class IssuesTest + { + // Issue 45 + [Test] + public void FieldCalledItem() + { + ItemField message = new ItemField { Item = 3 }; + FieldDescriptor field = ItemField.Descriptor.FindFieldByName("item"); + Assert.NotNull(field); + Assert.AreEqual(3, (int)field.Accessor.GetValue(message)); + } + + [Test] + public void ReservedNames() + { + var message = new ReservedNames { Types_ = 10, Descriptor_ = 20 }; + // Underscores aren't reflected in the JSON. + Assert.AreEqual("{ \"types\": 10, \"descriptor\": 20 }", message.ToString()); + } + + [Test] + public void JsonNameParseTest() + { + var settings = new JsonParser.Settings(10, TypeRegistry.FromFiles(UnittestIssuesReflection.Descriptor)); + var parser = new JsonParser(settings); + + // It is safe to use either original field name or explicitly specified json_name + Assert.AreEqual(new TestJsonName { Name = "test", Description = "test2", Guid = "test3" }, + parser.Parse("{ \"name\": \"test\", \"desc\": \"test2\", \"guid\": \"test3\" }")); + } + + [Test] + public void JsonNameFormatTest() + { + var message = new TestJsonName { Name = "test", Description = "test2", Guid = "test3" }; + Assert.AreEqual("{ \"name\": \"test\", \"desc\": \"test2\", \"exid\": \"test3\" }", + JsonFormatter.Default.Format(message)); + } + + [Test] + public void OneofMerging() + { + var message1 = new OneofMerging { Nested = new Nested { X = 10 } }; + var message2 = new OneofMerging { Nested = new Nested { Y = 20 } }; + var expected = new OneofMerging { Nested = new Nested { X = 10, Y = 20 } }; + + var merged = message1.Clone(); + merged.MergeFrom(message2); + Assert.AreEqual(expected, merged); + } + + // Check that a tag immediately followed by end of limit can still be read. + [Test] + public void CodedInputStream_LimitReachedRightAfterTag() + { + MemoryStream ms = new MemoryStream(); + var cos = new CodedOutputStream(ms); + cos.WriteTag(11, WireFormat.WireType.Varint); + Assert.AreEqual(1, cos.Position); + cos.WriteString("some extra padding"); // ensure is currentLimit distinct from the end of the buffer. + cos.Flush(); + + var cis = new CodedInputStream(ms.ToArray()); + cis.PushLimit(1); // make sure we reach the limit right after reading the tag. + + // we still must read the tag correctly, even though the tag is at the very end of our limited input + // (which is a corner case and will most likely result in an error when trying to read value of the field + // described by this tag, but it would be a logical error not to read the tag that's actually present). + // See https://github.com/protocolbuffers/protobuf/pull/7289 + cis.AssertNextTag(WireFormat.MakeTag(11, WireFormat.WireType.Varint)); + } + } +} diff --git a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs index 51fa5e01d6bd..3a77990cf143 100644 --- a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs +++ b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs @@ -1,705 +1,705 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using Google.Protobuf.TestProtos; -using NUnit.Framework; -using UnitTest.Issues.TestProtos; -using Google.Protobuf.WellKnownTypes; -using Google.Protobuf.Reflection; - -using static Google.Protobuf.JsonParserTest; // For WrapInQuotes -using System.IO; -using Google.Protobuf.Collections; -using ProtobufUnittest; - -namespace Google.Protobuf -{ - /// - /// Tests for the JSON formatter. Note that in these tests, double quotes are replaced with apostrophes - /// for the sake of readability (embedding \" everywhere is painful). See the AssertJson method for details. - /// - public class JsonFormatterTest - { - [Test] - public void DefaultValues_WhenOmitted() - { - var formatter = JsonFormatter.Default; - - AssertJson("{ }", formatter.Format(new ForeignMessage())); - AssertJson("{ }", formatter.Format(new TestAllTypes())); - AssertJson("{ }", formatter.Format(new TestMap())); - } - - [Test] - public void DefaultValues_WhenIncluded() - { - var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); - AssertJson("{ 'c': 0 }", formatter.Format(new ForeignMessage())); - } - - [Test] - public void EnumAllowAlias() - { - var message = new TestEnumAllowAlias - { - Value = TestEnumWithDupValue.Foo2, - }; - var actualText = JsonFormatter.Default.Format(message); - var expectedText = "{ 'value': 'FOO1' }"; - AssertJson(expectedText, actualText); - } - - [Test] - public void EnumAsInt() - { - var message = new TestAllTypes - { - SingleForeignEnum = ForeignEnum.ForeignBar, - RepeatedForeignEnum = { ForeignEnum.ForeignBaz, (ForeignEnum) 100, ForeignEnum.ForeignFoo } - }; - var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatEnumsAsIntegers(true)); - var actualText = formatter.Format(message); - var expectedText = "{ " + - "'singleForeignEnum': 5, " + - "'repeatedForeignEnum': [ 6, 100, 4 ]" + - " }"; - AssertJson(expectedText, actualText); - } - - [Test] - public void AllSingleFields() - { - var message = new TestAllTypes - { - SingleBool = true, - SingleBytes = ByteString.CopyFrom(1, 2, 3, 4), - SingleDouble = 23.5, - SingleFixed32 = 23, - SingleFixed64 = 1234567890123, - SingleFloat = 12.25f, - SingleForeignEnum = ForeignEnum.ForeignBar, - SingleForeignMessage = new ForeignMessage { C = 10 }, - SingleImportEnum = ImportEnum.ImportBaz, - SingleImportMessage = new ImportMessage { D = 20 }, - SingleInt32 = 100, - SingleInt64 = 3210987654321, - SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, - SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 }, - SinglePublicImportMessage = new PublicImportMessage { E = 54 }, - SingleSfixed32 = -123, - SingleSfixed64 = -12345678901234, - SingleSint32 = -456, - SingleSint64 = -12345678901235, - SingleString = "test\twith\ttabs", - SingleUint32 = uint.MaxValue, - SingleUint64 = ulong.MaxValue, - }; - var actualText = JsonFormatter.Default.Format(message); - - // Fields in numeric order - var expectedText = "{ " + - "'singleInt32': 100, " + - "'singleInt64': '3210987654321', " + - "'singleUint32': 4294967295, " + - "'singleUint64': '18446744073709551615', " + - "'singleSint32': -456, " + - "'singleSint64': '-12345678901235', " + - "'singleFixed32': 23, " + - "'singleFixed64': '1234567890123', " + - "'singleSfixed32': -123, " + - "'singleSfixed64': '-12345678901234', " + - "'singleFloat': 12.25, " + - "'singleDouble': 23.5, " + - "'singleBool': true, " + - "'singleString': 'test\\twith\\ttabs', " + - "'singleBytes': 'AQIDBA==', " + - "'singleNestedMessage': { 'bb': 35 }, " + - "'singleForeignMessage': { 'c': 10 }, " + - "'singleImportMessage': { 'd': 20 }, " + - "'singleNestedEnum': 'FOO', " + - "'singleForeignEnum': 'FOREIGN_BAR', " + - "'singleImportEnum': 'IMPORT_BAZ', " + - "'singlePublicImportMessage': { 'e': 54 }" + - " }"; - AssertJson(expectedText, actualText); - } - - [Test] - public void WithFormatDefaultValues_DoesNotAffectMessageFields() - { - var message = new TestAllTypes(); - var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); - var json = formatter.Format(message); - Assert.IsFalse(json.Contains("\"singleNestedMessage\"")); - Assert.IsFalse(json.Contains("\"singleForeignMessage\"")); - Assert.IsFalse(json.Contains("\"singleImportMessage\"")); - } - - [Test] - public void WithFormatDefaultValues_DoesNotAffectProto3OptionalFields() - { - var message = new TestProto3Optional(); - message.OptionalInt32 = 0; - var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); - var json = formatter.Format(message); - // The non-optional proto3 fields are formatted, as is the optional-but-specified field. - AssertJson("{ 'optionalInt32': 0, 'singularInt32': 0, 'singularInt64': '0' }", json); - } - - [Test] - public void WithFormatDefaultValues_DoesNotAffectProto2Fields() - { - var message = new TestProtos.Proto2.ForeignMessage(); - message.C = 0; - var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); - var json = formatter.Format(message); - // The specified field is formatted, but the non-specified field (d) is not. - AssertJson("{ 'c': 0 }", json); - } - - [Test] - public void WithFormatDefaultValues_DoesNotAffectOneofFields() - { - var message = new TestOneof(); - var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); - var json = formatter.Format(message); - AssertJson("{ }", json); - } - - [Test] - public void RepeatedField() - { - AssertJson("{ 'repeatedInt32': [ 1, 2, 3, 4, 5 ] }", - JsonFormatter.Default.Format(new TestAllTypes { RepeatedInt32 = { 1, 2, 3, 4, 5 } })); - } - - [Test] - public void MapField_StringString() - { - AssertJson("{ 'mapStringString': { 'with spaces': 'bar', 'a': 'b' } }", - JsonFormatter.Default.Format(new TestMap { MapStringString = { { "with spaces", "bar" }, { "a", "b" } } })); - } - - [Test] - public void MapField_Int32Int32() - { - // The keys are quoted, but the values aren't. - AssertJson("{ 'mapInt32Int32': { '0': 1, '2': 3 } }", - JsonFormatter.Default.Format(new TestMap { MapInt32Int32 = { { 0, 1 }, { 2, 3 } } })); - } - - [Test] - public void MapField_BoolBool() - { - // The keys are quoted, but the values aren't. - AssertJson("{ 'mapBoolBool': { 'false': true, 'true': false } }", - JsonFormatter.Default.Format(new TestMap { MapBoolBool = { { false, true }, { true, false } } })); - } - - [Test] - public void NullValueOutsideStruct() - { - var message = new NullValueOutsideStruct { NullValue = NullValue.NullValue }; - AssertJson("{ 'nullValue': null }", JsonFormatter.Default.Format(message)); - } - - [Test] - public void NullValueNotInOneof() - { - var message = new NullValueNotInOneof(); - AssertJson("{ }", JsonFormatter.Default.Format(message)); - } - - [Test] - public void NullValueNotInOneof_FormatDefaults() - { - var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); - var message = new NullValueNotInOneof(); - AssertJson("{ 'nullValue': null }", formatter.Format(message)); - } - - [TestCase(1.0, "1")] - [TestCase(double.NaN, "'NaN'")] - [TestCase(double.PositiveInfinity, "'Infinity'")] - [TestCase(double.NegativeInfinity, "'-Infinity'")] - public void DoubleRepresentations(double value, string expectedValueText) - { - var message = new TestAllTypes { SingleDouble = value }; - string actualText = JsonFormatter.Default.Format(message); - string expectedText = "{ 'singleDouble': " + expectedValueText + " }"; - AssertJson(expectedText, actualText); - } - - [Test] - public void UnknownEnumValueNumeric_SingleField() - { - var message = new TestAllTypes { SingleForeignEnum = (ForeignEnum) 100 }; - AssertJson("{ 'singleForeignEnum': 100 }", JsonFormatter.Default.Format(message)); - } - - [Test] - public void UnknownEnumValueNumeric_RepeatedField() - { - var message = new TestAllTypes { RepeatedForeignEnum = { ForeignEnum.ForeignBaz, (ForeignEnum) 100, ForeignEnum.ForeignFoo } }; - AssertJson("{ 'repeatedForeignEnum': [ 'FOREIGN_BAZ', 100, 'FOREIGN_FOO' ] }", JsonFormatter.Default.Format(message)); - } - - [Test] - public void UnknownEnumValueNumeric_MapField() - { - var message = new TestMap { MapInt32Enum = { { 1, MapEnum.Foo }, { 2, (MapEnum) 100 }, { 3, MapEnum.Bar } } }; - AssertJson("{ 'mapInt32Enum': { '1': 'MAP_ENUM_FOO', '2': 100, '3': 'MAP_ENUM_BAR' } }", JsonFormatter.Default.Format(message)); - } - - [Test] - public void UnknownEnumValue_RepeatedField_AllEntriesUnknown() - { - var message = new TestAllTypes { RepeatedForeignEnum = { (ForeignEnum) 200, (ForeignEnum) 100 } }; - AssertJson("{ 'repeatedForeignEnum': [ 200, 100 ] }", JsonFormatter.Default.Format(message)); - } - - [Test] - [TestCase("a\u17b4b", "a\\u17b4b")] // Explicit - [TestCase("a\u0601b", "a\\u0601b")] // Ranged - [TestCase("a\u0605b", "a\u0605b")] // Passthrough (note lack of double backslash...) - public void SimpleNonAscii(string text, string encoded) - { - var message = new TestAllTypes { SingleString = text }; - AssertJson("{ 'singleString': '" + encoded + "' }", JsonFormatter.Default.Format(message)); - } - - [Test] - public void SurrogatePairEscaping() - { - var message = new TestAllTypes { SingleString = "a\uD801\uDC01b" }; - AssertJson("{ 'singleString': 'a\\ud801\\udc01b' }", JsonFormatter.Default.Format(message)); - } - - [Test] - public void InvalidSurrogatePairsFail() - { - // Note: don't use TestCase for these, as the strings can't be reliably represented - // See http://codeblog.jonskeet.uk/2014/11/07/when-is-a-string-not-a-string/ - - // Lone low surrogate - var message = new TestAllTypes { SingleString = "a\uDC01b" }; - Assert.Throws(() => JsonFormatter.Default.Format(message)); - - // Lone high surrogate - message = new TestAllTypes { SingleString = "a\uD801b" }; - Assert.Throws(() => JsonFormatter.Default.Format(message)); - } - - [Test] - [TestCase("foo_bar", "fooBar")] - [TestCase("bananaBanana", "bananaBanana")] - [TestCase("BANANABanana", "BANANABanana")] - [TestCase("simple", "simple")] - [TestCase("ACTION_AND_ADVENTURE", "ACTIONANDADVENTURE")] - [TestCase("action_and_adventure", "actionAndAdventure")] - [TestCase("kFoo", "kFoo")] - [TestCase("HTTPServer", "HTTPServer")] - [TestCase("CLIENT", "CLIENT")] - public void ToJsonName(string original, string expected) - { - Assert.AreEqual(expected, JsonFormatter.ToJsonName(original)); - } - - [Test] - [TestCase(null, "{ }")] - [TestCase("x", "{ 'fooString': 'x' }")] - [TestCase("", "{ 'fooString': '' }")] - public void Oneof(string fooStringValue, string expectedJson) - { - var message = new TestOneof(); - if (fooStringValue != null) - { - message.FooString = fooStringValue; - } - - // We should get the same result both with and without "format default values". - var formatter = JsonFormatter.Default; - AssertJson(expectedJson, formatter.Format(message)); - formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); - AssertJson(expectedJson, formatter.Format(message)); - } - - [Test] - public void WrapperFormatting_Single() - { - // Just a few examples, handling both classes and value types, and - // default vs non-default values - var message = new TestWellKnownTypes - { - Int64Field = 10, - Int32Field = 0, - BytesField = ByteString.FromBase64("ABCD"), - StringField = "" - }; - var expectedJson = "{ 'int64Field': '10', 'int32Field': 0, 'stringField': '', 'bytesField': 'ABCD' }"; - AssertJson(expectedJson, JsonFormatter.Default.Format(message)); - } - - [Test] - public void WrapperFormatting_Message() - { - Assert.AreEqual("\"\"", JsonFormatter.Default.Format(new StringValue())); - Assert.AreEqual("0", JsonFormatter.Default.Format(new Int32Value())); - } - - [Test] - public void WrapperFormatting_FormatDefaultValuesDoesNotFormatNull() - { - // The actual JSON here is very large because there are lots of fields. Just test a couple of them. - var message = new TestWellKnownTypes { Int32Field = 10 }; - var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); - var actualJson = formatter.Format(message); - // This *used* to include "int64Field": null, but that was a bug. - // WithDefaultValues should not affect message fields, including wrapper types. - Assert.IsFalse(actualJson.Contains("\"int64Field\": null")); - Assert.IsTrue(actualJson.Contains("\"int32Field\": 10")); - } - - [Test] - public void OutputIsInNumericFieldOrder_NoDefaults() - { - var formatter = JsonFormatter.Default; - var message = new TestJsonFieldOrdering { PlainString = "p1", PlainInt32 = 2 }; - AssertJson("{ 'plainString': 'p1', 'plainInt32': 2 }", formatter.Format(message)); - message = new TestJsonFieldOrdering { O1Int32 = 5, O2String = "o2", PlainInt32 = 10, PlainString = "plain" }; - AssertJson("{ 'plainString': 'plain', 'o2String': 'o2', 'plainInt32': 10, 'o1Int32': 5 }", formatter.Format(message)); - message = new TestJsonFieldOrdering { O1String = "", O2Int32 = 0, PlainInt32 = 10, PlainString = "plain" }; - AssertJson("{ 'plainString': 'plain', 'o1String': '', 'plainInt32': 10, 'o2Int32': 0 }", formatter.Format(message)); - } - - [Test] - public void OutputIsInNumericFieldOrder_WithDefaults() - { - var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); - var message = new TestJsonFieldOrdering(); - AssertJson("{ 'plainString': '', 'plainInt32': 0 }", formatter.Format(message)); - message = new TestJsonFieldOrdering { O1Int32 = 5, O2String = "o2", PlainInt32 = 10, PlainString = "plain" }; - AssertJson("{ 'plainString': 'plain', 'o2String': 'o2', 'plainInt32': 10, 'o1Int32': 5 }", formatter.Format(message)); - message = new TestJsonFieldOrdering { O1String = "", O2Int32 = 0, PlainInt32 = 10, PlainString = "plain" }; - AssertJson("{ 'plainString': 'plain', 'o1String': '', 'plainInt32': 10, 'o2Int32': 0 }", formatter.Format(message)); - } - - [Test] - [TestCase("1970-01-01T00:00:00Z", 0)] - [TestCase("1970-01-01T00:00:00.000000001Z", 1)] - [TestCase("1970-01-01T00:00:00.000000010Z", 10)] - [TestCase("1970-01-01T00:00:00.000000100Z", 100)] - [TestCase("1970-01-01T00:00:00.000001Z", 1000)] - [TestCase("1970-01-01T00:00:00.000010Z", 10000)] - [TestCase("1970-01-01T00:00:00.000100Z", 100000)] - [TestCase("1970-01-01T00:00:00.001Z", 1000000)] - [TestCase("1970-01-01T00:00:00.010Z", 10000000)] - [TestCase("1970-01-01T00:00:00.100Z", 100000000)] - [TestCase("1970-01-01T00:00:00.120Z", 120000000)] - [TestCase("1970-01-01T00:00:00.123Z", 123000000)] - [TestCase("1970-01-01T00:00:00.123400Z", 123400000)] - [TestCase("1970-01-01T00:00:00.123450Z", 123450000)] - [TestCase("1970-01-01T00:00:00.123456Z", 123456000)] - [TestCase("1970-01-01T00:00:00.123456700Z", 123456700)] - [TestCase("1970-01-01T00:00:00.123456780Z", 123456780)] - [TestCase("1970-01-01T00:00:00.123456789Z", 123456789)] - public void TimestampStandalone(string expected, int nanos) - { - Assert.AreEqual(WrapInQuotes(expected), new Timestamp { Nanos = nanos }.ToString()); - } - - [Test] - public void TimestampStandalone_FromDateTime() - { - // One before and one after the Unix epoch, more easily represented via DateTime. - Assert.AreEqual("\"1673-06-19T12:34:56Z\"", - new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp().ToString()); - Assert.AreEqual("\"2015-07-31T10:29:34Z\"", - new DateTime(2015, 7, 31, 10, 29, 34, DateTimeKind.Utc).ToTimestamp().ToString()); - } - - [Test] - [TestCase(-1, -1)] // Would be valid as duration - [TestCase(1, Timestamp.MaxNanos + 1)] - [TestCase(Timestamp.UnixSecondsAtBclMaxValue + 1, 0)] - [TestCase(Timestamp.UnixSecondsAtBclMinValue - 1, 0)] - public void TimestampStandalone_NonNormalized(long seconds, int nanoseconds) - { - var timestamp = new Timestamp { Seconds = seconds, Nanos = nanoseconds }; - Assert.Throws(() => JsonFormatter.Default.Format(timestamp)); - } - - [Test] - public void TimestampField() - { - var message = new TestWellKnownTypes { TimestampField = new Timestamp() }; - AssertJson("{ 'timestampField': '1970-01-01T00:00:00Z' }", JsonFormatter.Default.Format(message)); - } - - [Test] - [TestCase(0, 0, "0s")] - [TestCase(1, 0, "1s")] - [TestCase(-1, 0, "-1s")] - [TestCase(0, 1, "0.000000001s")] - [TestCase(0, 10, "0.000000010s")] - [TestCase(0, 100, "0.000000100s")] - [TestCase(0, 1000, "0.000001s")] - [TestCase(0, 10000, "0.000010s")] - [TestCase(0, 100000, "0.000100s")] - [TestCase(0, 1000000, "0.001s")] - [TestCase(0, 10000000, "0.010s")] - [TestCase(0, 100000000, "0.100s")] - [TestCase(0, 120000000, "0.120s")] - [TestCase(0, 123000000, "0.123s")] - [TestCase(0, 123400000, "0.123400s")] - [TestCase(0, 123450000, "0.123450s")] - [TestCase(0, 123456000, "0.123456s")] - [TestCase(0, 123456700, "0.123456700s")] - [TestCase(0, 123456780, "0.123456780s")] - [TestCase(0, 123456789, "0.123456789s")] - [TestCase(0, -100000000, "-0.100s")] - [TestCase(1, 100000000, "1.100s")] - [TestCase(-1, -100000000, "-1.100s")] - public void DurationStandalone(long seconds, int nanoseconds, string expected) - { - var json = JsonFormatter.Default.Format(new Duration { Seconds = seconds, Nanos = nanoseconds }); - Assert.AreEqual(WrapInQuotes(expected), json); - } - - [Test] - [TestCase(1, 2123456789)] - [TestCase(1, -100000000)] - public void DurationStandalone_NonNormalized(long seconds, int nanoseconds) - { - var duration = new Duration { Seconds = seconds, Nanos = nanoseconds }; - Assert.Throws(() => JsonFormatter.Default.Format(duration)); - } - - [Test] - public void DurationField() - { - var message = new TestWellKnownTypes { DurationField = new Duration() }; - AssertJson("{ 'durationField': '0s' }", JsonFormatter.Default.Format(message)); - } - - [Test] - public void StructSample() - { - var message = new Struct - { - Fields = - { - { "a", Value.ForNull() }, - { "b", Value.ForBool(false) }, - { "c", Value.ForNumber(10.5) }, - { "d", Value.ForString("text") }, - { "e", Value.ForList(Value.ForString("t1"), Value.ForNumber(5)) }, - { "f", Value.ForStruct(new Struct { Fields = { { "nested", Value.ForString("value") } } }) } - } - }; - AssertJson("{ 'a': null, 'b': false, 'c': 10.5, 'd': 'text', 'e': [ 't1', 5 ], 'f': { 'nested': 'value' } }", message.ToString()); - } - - [Test] - [TestCase("foo__bar")] - [TestCase("foo_3_ar")] - [TestCase("fooBar")] - public void FieldMaskInvalid(string input) - { - var mask = new FieldMask { Paths = { input } }; - Assert.Throws(() => JsonFormatter.Default.Format(mask)); - } - - [Test] - public void FieldMaskStandalone() - { - var fieldMask = new FieldMask { Paths = { "", "single", "with_underscore", "nested.field.name", "nested..double_dot" } }; - Assert.AreEqual("\",single,withUnderscore,nested.field.name,nested..doubleDot\"", fieldMask.ToString()); - - // Invalid, but we shouldn't create broken JSON... - fieldMask = new FieldMask { Paths = { "x\\y" } }; - Assert.AreEqual(@"""x\\y""", fieldMask.ToString()); - } - - [Test] - public void FieldMaskField() - { - var message = new TestWellKnownTypes { FieldMaskField = new FieldMask { Paths = { "user.display_name", "photo" } } }; - AssertJson("{ 'fieldMaskField': 'user.displayName,photo' }", JsonFormatter.Default.Format(message)); - } - - // SourceContext is an example of a well-known type with no special JSON handling - [Test] - public void SourceContextStandalone() - { - var message = new SourceContext { FileName = "foo.proto" }; - AssertJson("{ 'fileName': 'foo.proto' }", JsonFormatter.Default.Format(message)); - } - - [Test] - public void AnyWellKnownType() - { - var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithTypeRegistry(TypeRegistry.FromMessages(Timestamp.Descriptor))); - var timestamp = new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp(); - var any = Any.Pack(timestamp); - AssertJson("{ '@type': 'type.googleapis.com/google.protobuf.Timestamp', 'value': '1673-06-19T12:34:56Z' }", formatter.Format(any)); - } - - [Test] - public void AnyMessageType() - { - var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithTypeRegistry(TypeRegistry.FromMessages(TestAllTypes.Descriptor))); - var message = new TestAllTypes { SingleInt32 = 10, SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } }; - var any = Any.Pack(message); - AssertJson("{ '@type': 'type.googleapis.com/protobuf_unittest3.TestAllTypes', 'singleInt32': 10, 'singleNestedMessage': { 'bb': 20 } }", formatter.Format(any)); - } - - [Test] - public void AnyMessageType_CustomPrefix() - { - var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithTypeRegistry(TypeRegistry.FromMessages(TestAllTypes.Descriptor))); - var message = new TestAllTypes { SingleInt32 = 10 }; - var any = Any.Pack(message, "foo.bar/baz"); - AssertJson("{ '@type': 'foo.bar/baz/protobuf_unittest3.TestAllTypes', 'singleInt32': 10 }", formatter.Format(any)); - } - - [Test] - public void AnyNested() - { - var registry = TypeRegistry.FromMessages(TestWellKnownTypes.Descriptor, TestAllTypes.Descriptor); - var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithTypeRegistry(registry)); - - // Nest an Any as the value of an Any. - var doubleNestedMessage = new TestAllTypes { SingleInt32 = 20 }; - var nestedMessage = Any.Pack(doubleNestedMessage); - var message = new TestWellKnownTypes { AnyField = Any.Pack(nestedMessage) }; - AssertJson("{ 'anyField': { '@type': 'type.googleapis.com/google.protobuf.Any', 'value': { '@type': 'type.googleapis.com/protobuf_unittest3.TestAllTypes', 'singleInt32': 20 } } }", - formatter.Format(message)); - } - - [Test] - public void AnyUnknownType() - { - // The default type registry doesn't have any types in it. - var message = new TestAllTypes(); - var any = Any.Pack(message); - Assert.Throws(() => JsonFormatter.Default.Format(any)); - } - - [Test] - [TestCase(typeof(BoolValue), true, "true")] - [TestCase(typeof(Int32Value), 32, "32")] - [TestCase(typeof(Int64Value), 32L, "\"32\"")] - [TestCase(typeof(UInt32Value), 32U, "32")] - [TestCase(typeof(UInt64Value), 32UL, "\"32\"")] - [TestCase(typeof(StringValue), "foo", "\"foo\"")] - [TestCase(typeof(FloatValue), 1.5f, "1.5")] - [TestCase(typeof(DoubleValue), 1.5d, "1.5")] - public void Wrappers_Standalone(System.Type wrapperType, object value, string expectedJson) - { - IMessage populated = (IMessage)Activator.CreateInstance(wrapperType); - populated.Descriptor.Fields[WrappersReflection.WrapperValueFieldNumber].Accessor.SetValue(populated, value); - Assert.AreEqual(expectedJson, JsonFormatter.Default.Format(populated)); - } - - // Sanity tests for WriteValue. Not particularly comprehensive, as it's all covered above already, - // as FormatMessage uses WriteValue. - - [TestCase(null, "null")] - [TestCase(1, "1")] - [TestCase(1L, "'1'")] - [TestCase(0.5f, "0.5")] - [TestCase(0.5d, "0.5")] - [TestCase("text", "'text'")] - [TestCase("x\ny", @"'x\ny'")] - [TestCase(ForeignEnum.ForeignBar, "'FOREIGN_BAR'")] - public void WriteValue_Constant(object value, string expectedJson) - { - AssertWriteValue(value, expectedJson); - } - - [Test] - public void WriteValue_Timestamp() - { - var value = new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp(); - AssertWriteValue(value, "'1673-06-19T12:34:56Z'"); - } - - [Test] - public void WriteValue_Message() - { - var value = new TestAllTypes { SingleInt32 = 100, SingleInt64 = 3210987654321L }; - AssertWriteValue(value, "{ 'singleInt32': 100, 'singleInt64': '3210987654321' }"); - } - - [Test] - public void WriteValue_Message_PreserveNames() - { - var value = new TestAllTypes { SingleInt32 = 100, SingleInt64 = 3210987654321L }; - AssertWriteValue(value, "{ 'single_int32': 100, 'single_int64': '3210987654321' }", JsonFormatter.Settings.Default.WithPreserveProtoFieldNames(true)); - } - - [Test] - public void WriteValue_List() - { - var value = new RepeatedField { 1, 2, 3 }; - AssertWriteValue(value, "[ 1, 2, 3 ]"); - } - - [Test] - public void Proto2_DefaultValuesWritten() - { - var value = new ProtobufTestMessages.Proto2.TestAllTypesProto2() { FieldName13 = 0 }; - AssertWriteValue(value, "{ 'FieldName13': 0 }"); - } - - private static void AssertWriteValue(object value, string expectedJson, JsonFormatter.Settings settings = null) - { - var writer = new StringWriter(); - new JsonFormatter(settings ?? JsonFormatter.Settings.Default).WriteValue(writer, value); - string actual = writer.ToString(); - AssertJson(expectedJson, actual); - } - - /// - /// Checks that the actual JSON is the same as the expected JSON - but after replacing - /// all apostrophes in the expected JSON with double quotes. This basically makes the tests easier - /// to read. - /// - private static void AssertJson(string expectedJsonWithApostrophes, string actualJson) - { - var expectedJson = expectedJsonWithApostrophes.Replace("'", "\""); - Assert.AreEqual(expectedJson, actualJson); - } - } -} +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using Google.Protobuf.TestProtos; +using NUnit.Framework; +using UnitTest.Issues.TestProtos; +using Google.Protobuf.WellKnownTypes; +using Google.Protobuf.Reflection; + +using static Google.Protobuf.JsonParserTest; // For WrapInQuotes +using System.IO; +using Google.Protobuf.Collections; +using ProtobufUnittest; + +namespace Google.Protobuf +{ + /// + /// Tests for the JSON formatter. Note that in these tests, double quotes are replaced with apostrophes + /// for the sake of readability (embedding \" everywhere is painful). See the AssertJson method for details. + /// + public class JsonFormatterTest + { + [Test] + public void DefaultValues_WhenOmitted() + { + var formatter = JsonFormatter.Default; + + AssertJson("{ }", formatter.Format(new ForeignMessage())); + AssertJson("{ }", formatter.Format(new TestAllTypes())); + AssertJson("{ }", formatter.Format(new TestMap())); + } + + [Test] + public void DefaultValues_WhenIncluded() + { + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); + AssertJson("{ 'c': 0 }", formatter.Format(new ForeignMessage())); + } + + [Test] + public void EnumAllowAlias() + { + var message = new TestEnumAllowAlias + { + Value = TestEnumWithDupValue.Foo2, + }; + var actualText = JsonFormatter.Default.Format(message); + var expectedText = "{ 'value': 'FOO1' }"; + AssertJson(expectedText, actualText); + } + + [Test] + public void EnumAsInt() + { + var message = new TestAllTypes + { + SingleForeignEnum = ForeignEnum.ForeignBar, + RepeatedForeignEnum = { ForeignEnum.ForeignBaz, (ForeignEnum) 100, ForeignEnum.ForeignFoo } + }; + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatEnumsAsIntegers(true)); + var actualText = formatter.Format(message); + var expectedText = "{ " + + "'singleForeignEnum': 5, " + + "'repeatedForeignEnum': [ 6, 100, 4 ]" + + " }"; + AssertJson(expectedText, actualText); + } + + [Test] + public void AllSingleFields() + { + var message = new TestAllTypes + { + SingleBool = true, + SingleBytes = ByteString.CopyFrom(1, 2, 3, 4), + SingleDouble = 23.5, + SingleFixed32 = 23, + SingleFixed64 = 1234567890123, + SingleFloat = 12.25f, + SingleForeignEnum = ForeignEnum.ForeignBar, + SingleForeignMessage = new ForeignMessage { C = 10 }, + SingleImportEnum = ImportEnum.ImportBaz, + SingleImportMessage = new ImportMessage { D = 20 }, + SingleInt32 = 100, + SingleInt64 = 3210987654321, + SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, + SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 }, + SinglePublicImportMessage = new PublicImportMessage { E = 54 }, + SingleSfixed32 = -123, + SingleSfixed64 = -12345678901234, + SingleSint32 = -456, + SingleSint64 = -12345678901235, + SingleString = "test\twith\ttabs", + SingleUint32 = uint.MaxValue, + SingleUint64 = ulong.MaxValue, + }; + var actualText = JsonFormatter.Default.Format(message); + + // Fields in numeric order + var expectedText = "{ " + + "'singleInt32': 100, " + + "'singleInt64': '3210987654321', " + + "'singleUint32': 4294967295, " + + "'singleUint64': '18446744073709551615', " + + "'singleSint32': -456, " + + "'singleSint64': '-12345678901235', " + + "'singleFixed32': 23, " + + "'singleFixed64': '1234567890123', " + + "'singleSfixed32': -123, " + + "'singleSfixed64': '-12345678901234', " + + "'singleFloat': 12.25, " + + "'singleDouble': 23.5, " + + "'singleBool': true, " + + "'singleString': 'test\\twith\\ttabs', " + + "'singleBytes': 'AQIDBA==', " + + "'singleNestedMessage': { 'bb': 35 }, " + + "'singleForeignMessage': { 'c': 10 }, " + + "'singleImportMessage': { 'd': 20 }, " + + "'singleNestedEnum': 'FOO', " + + "'singleForeignEnum': 'FOREIGN_BAR', " + + "'singleImportEnum': 'IMPORT_BAZ', " + + "'singlePublicImportMessage': { 'e': 54 }" + + " }"; + AssertJson(expectedText, actualText); + } + + [Test] + public void WithFormatDefaultValues_DoesNotAffectMessageFields() + { + var message = new TestAllTypes(); + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); + var json = formatter.Format(message); + Assert.IsFalse(json.Contains("\"singleNestedMessage\"")); + Assert.IsFalse(json.Contains("\"singleForeignMessage\"")); + Assert.IsFalse(json.Contains("\"singleImportMessage\"")); + } + + [Test] + public void WithFormatDefaultValues_DoesNotAffectProto3OptionalFields() + { + var message = new TestProto3Optional(); + message.OptionalInt32 = 0; + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); + var json = formatter.Format(message); + // The non-optional proto3 fields are formatted, as is the optional-but-specified field. + AssertJson("{ 'optionalInt32': 0, 'singularInt32': 0, 'singularInt64': '0' }", json); + } + + [Test] + public void WithFormatDefaultValues_DoesNotAffectProto2Fields() + { + var message = new TestProtos.Proto2.ForeignMessage(); + message.C = 0; + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); + var json = formatter.Format(message); + // The specified field is formatted, but the non-specified field (d) is not. + AssertJson("{ 'c': 0 }", json); + } + + [Test] + public void WithFormatDefaultValues_DoesNotAffectOneofFields() + { + var message = new TestOneof(); + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); + var json = formatter.Format(message); + AssertJson("{ }", json); + } + + [Test] + public void RepeatedField() + { + AssertJson("{ 'repeatedInt32': [ 1, 2, 3, 4, 5 ] }", + JsonFormatter.Default.Format(new TestAllTypes { RepeatedInt32 = { 1, 2, 3, 4, 5 } })); + } + + [Test] + public void MapField_StringString() + { + AssertJson("{ 'mapStringString': { 'with spaces': 'bar', 'a': 'b' } }", + JsonFormatter.Default.Format(new TestMap { MapStringString = { { "with spaces", "bar" }, { "a", "b" } } })); + } + + [Test] + public void MapField_Int32Int32() + { + // The keys are quoted, but the values aren't. + AssertJson("{ 'mapInt32Int32': { '0': 1, '2': 3 } }", + JsonFormatter.Default.Format(new TestMap { MapInt32Int32 = { { 0, 1 }, { 2, 3 } } })); + } + + [Test] + public void MapField_BoolBool() + { + // The keys are quoted, but the values aren't. + AssertJson("{ 'mapBoolBool': { 'false': true, 'true': false } }", + JsonFormatter.Default.Format(new TestMap { MapBoolBool = { { false, true }, { true, false } } })); + } + + [Test] + public void NullValueOutsideStruct() + { + var message = new NullValueOutsideStruct { NullValue = NullValue.NullValue }; + AssertJson("{ 'nullValue': null }", JsonFormatter.Default.Format(message)); + } + + [Test] + public void NullValueNotInOneof() + { + var message = new NullValueNotInOneof(); + AssertJson("{ }", JsonFormatter.Default.Format(message)); + } + + [Test] + public void NullValueNotInOneof_FormatDefaults() + { + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); + var message = new NullValueNotInOneof(); + AssertJson("{ 'nullValue': null }", formatter.Format(message)); + } + + [TestCase(1.0, "1")] + [TestCase(double.NaN, "'NaN'")] + [TestCase(double.PositiveInfinity, "'Infinity'")] + [TestCase(double.NegativeInfinity, "'-Infinity'")] + public void DoubleRepresentations(double value, string expectedValueText) + { + var message = new TestAllTypes { SingleDouble = value }; + string actualText = JsonFormatter.Default.Format(message); + string expectedText = "{ 'singleDouble': " + expectedValueText + " }"; + AssertJson(expectedText, actualText); + } + + [Test] + public void UnknownEnumValueNumeric_SingleField() + { + var message = new TestAllTypes { SingleForeignEnum = (ForeignEnum) 100 }; + AssertJson("{ 'singleForeignEnum': 100 }", JsonFormatter.Default.Format(message)); + } + + [Test] + public void UnknownEnumValueNumeric_RepeatedField() + { + var message = new TestAllTypes { RepeatedForeignEnum = { ForeignEnum.ForeignBaz, (ForeignEnum) 100, ForeignEnum.ForeignFoo } }; + AssertJson("{ 'repeatedForeignEnum': [ 'FOREIGN_BAZ', 100, 'FOREIGN_FOO' ] }", JsonFormatter.Default.Format(message)); + } + + [Test] + public void UnknownEnumValueNumeric_MapField() + { + var message = new TestMap { MapInt32Enum = { { 1, MapEnum.Foo }, { 2, (MapEnum) 100 }, { 3, MapEnum.Bar } } }; + AssertJson("{ 'mapInt32Enum': { '1': 'MAP_ENUM_FOO', '2': 100, '3': 'MAP_ENUM_BAR' } }", JsonFormatter.Default.Format(message)); + } + + [Test] + public void UnknownEnumValue_RepeatedField_AllEntriesUnknown() + { + var message = new TestAllTypes { RepeatedForeignEnum = { (ForeignEnum) 200, (ForeignEnum) 100 } }; + AssertJson("{ 'repeatedForeignEnum': [ 200, 100 ] }", JsonFormatter.Default.Format(message)); + } + + [Test] + [TestCase("a\u17b4b", "a\\u17b4b")] // Explicit + [TestCase("a\u0601b", "a\\u0601b")] // Ranged + [TestCase("a\u0605b", "a\u0605b")] // Passthrough (note lack of double backslash...) + public void SimpleNonAscii(string text, string encoded) + { + var message = new TestAllTypes { SingleString = text }; + AssertJson("{ 'singleString': '" + encoded + "' }", JsonFormatter.Default.Format(message)); + } + + [Test] + public void SurrogatePairEscaping() + { + var message = new TestAllTypes { SingleString = "a\uD801\uDC01b" }; + AssertJson("{ 'singleString': 'a\\ud801\\udc01b' }", JsonFormatter.Default.Format(message)); + } + + [Test] + public void InvalidSurrogatePairsFail() + { + // Note: don't use TestCase for these, as the strings can't be reliably represented + // See http://codeblog.jonskeet.uk/2014/11/07/when-is-a-string-not-a-string/ + + // Lone low surrogate + var message = new TestAllTypes { SingleString = "a\uDC01b" }; + Assert.Throws(() => JsonFormatter.Default.Format(message)); + + // Lone high surrogate + message = new TestAllTypes { SingleString = "a\uD801b" }; + Assert.Throws(() => JsonFormatter.Default.Format(message)); + } + + [Test] + [TestCase("foo_bar", "fooBar")] + [TestCase("bananaBanana", "bananaBanana")] + [TestCase("BANANABanana", "BANANABanana")] + [TestCase("simple", "simple")] + [TestCase("ACTION_AND_ADVENTURE", "ACTIONANDADVENTURE")] + [TestCase("action_and_adventure", "actionAndAdventure")] + [TestCase("kFoo", "kFoo")] + [TestCase("HTTPServer", "HTTPServer")] + [TestCase("CLIENT", "CLIENT")] + public void ToJsonName(string original, string expected) + { + Assert.AreEqual(expected, JsonFormatter.ToJsonName(original)); + } + + [Test] + [TestCase(null, "{ }")] + [TestCase("x", "{ 'fooString': 'x' }")] + [TestCase("", "{ 'fooString': '' }")] + public void Oneof(string fooStringValue, string expectedJson) + { + var message = new TestOneof(); + if (fooStringValue != null) + { + message.FooString = fooStringValue; + } + + // We should get the same result both with and without "format default values". + var formatter = JsonFormatter.Default; + AssertJson(expectedJson, formatter.Format(message)); + formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); + AssertJson(expectedJson, formatter.Format(message)); + } + + [Test] + public void WrapperFormatting_Single() + { + // Just a few examples, handling both classes and value types, and + // default vs non-default values + var message = new TestWellKnownTypes + { + Int64Field = 10, + Int32Field = 0, + BytesField = ByteString.FromBase64("ABCD"), + StringField = "" + }; + var expectedJson = "{ 'int64Field': '10', 'int32Field': 0, 'stringField': '', 'bytesField': 'ABCD' }"; + AssertJson(expectedJson, JsonFormatter.Default.Format(message)); + } + + [Test] + public void WrapperFormatting_Message() + { + Assert.AreEqual("\"\"", JsonFormatter.Default.Format(new StringValue())); + Assert.AreEqual("0", JsonFormatter.Default.Format(new Int32Value())); + } + + [Test] + public void WrapperFormatting_FormatDefaultValuesDoesNotFormatNull() + { + // The actual JSON here is very large because there are lots of fields. Just test a couple of them. + var message = new TestWellKnownTypes { Int32Field = 10 }; + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); + var actualJson = formatter.Format(message); + // This *used* to include "int64Field": null, but that was a bug. + // WithDefaultValues should not affect message fields, including wrapper types. + Assert.IsFalse(actualJson.Contains("\"int64Field\": null")); + Assert.IsTrue(actualJson.Contains("\"int32Field\": 10")); + } + + [Test] + public void OutputIsInNumericFieldOrder_NoDefaults() + { + var formatter = JsonFormatter.Default; + var message = new TestJsonFieldOrdering { PlainString = "p1", PlainInt32 = 2 }; + AssertJson("{ 'plainString': 'p1', 'plainInt32': 2 }", formatter.Format(message)); + message = new TestJsonFieldOrdering { O1Int32 = 5, O2String = "o2", PlainInt32 = 10, PlainString = "plain" }; + AssertJson("{ 'plainString': 'plain', 'o2String': 'o2', 'plainInt32': 10, 'o1Int32': 5 }", formatter.Format(message)); + message = new TestJsonFieldOrdering { O1String = "", O2Int32 = 0, PlainInt32 = 10, PlainString = "plain" }; + AssertJson("{ 'plainString': 'plain', 'o1String': '', 'plainInt32': 10, 'o2Int32': 0 }", formatter.Format(message)); + } + + [Test] + public void OutputIsInNumericFieldOrder_WithDefaults() + { + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); + var message = new TestJsonFieldOrdering(); + AssertJson("{ 'plainString': '', 'plainInt32': 0 }", formatter.Format(message)); + message = new TestJsonFieldOrdering { O1Int32 = 5, O2String = "o2", PlainInt32 = 10, PlainString = "plain" }; + AssertJson("{ 'plainString': 'plain', 'o2String': 'o2', 'plainInt32': 10, 'o1Int32': 5 }", formatter.Format(message)); + message = new TestJsonFieldOrdering { O1String = "", O2Int32 = 0, PlainInt32 = 10, PlainString = "plain" }; + AssertJson("{ 'plainString': 'plain', 'o1String': '', 'plainInt32': 10, 'o2Int32': 0 }", formatter.Format(message)); + } + + [Test] + [TestCase("1970-01-01T00:00:00Z", 0)] + [TestCase("1970-01-01T00:00:00.000000001Z", 1)] + [TestCase("1970-01-01T00:00:00.000000010Z", 10)] + [TestCase("1970-01-01T00:00:00.000000100Z", 100)] + [TestCase("1970-01-01T00:00:00.000001Z", 1000)] + [TestCase("1970-01-01T00:00:00.000010Z", 10000)] + [TestCase("1970-01-01T00:00:00.000100Z", 100000)] + [TestCase("1970-01-01T00:00:00.001Z", 1000000)] + [TestCase("1970-01-01T00:00:00.010Z", 10000000)] + [TestCase("1970-01-01T00:00:00.100Z", 100000000)] + [TestCase("1970-01-01T00:00:00.120Z", 120000000)] + [TestCase("1970-01-01T00:00:00.123Z", 123000000)] + [TestCase("1970-01-01T00:00:00.123400Z", 123400000)] + [TestCase("1970-01-01T00:00:00.123450Z", 123450000)] + [TestCase("1970-01-01T00:00:00.123456Z", 123456000)] + [TestCase("1970-01-01T00:00:00.123456700Z", 123456700)] + [TestCase("1970-01-01T00:00:00.123456780Z", 123456780)] + [TestCase("1970-01-01T00:00:00.123456789Z", 123456789)] + public void TimestampStandalone(string expected, int nanos) + { + Assert.AreEqual(WrapInQuotes(expected), new Timestamp { Nanos = nanos }.ToString()); + } + + [Test] + public void TimestampStandalone_FromDateTime() + { + // One before and one after the Unix epoch, more easily represented via DateTime. + Assert.AreEqual("\"1673-06-19T12:34:56Z\"", + new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp().ToString()); + Assert.AreEqual("\"2015-07-31T10:29:34Z\"", + new DateTime(2015, 7, 31, 10, 29, 34, DateTimeKind.Utc).ToTimestamp().ToString()); + } + + [Test] + [TestCase(-1, -1)] // Would be valid as duration + [TestCase(1, Timestamp.MaxNanos + 1)] + [TestCase(Timestamp.UnixSecondsAtBclMaxValue + 1, 0)] + [TestCase(Timestamp.UnixSecondsAtBclMinValue - 1, 0)] + public void TimestampStandalone_NonNormalized(long seconds, int nanoseconds) + { + var timestamp = new Timestamp { Seconds = seconds, Nanos = nanoseconds }; + Assert.Throws(() => JsonFormatter.Default.Format(timestamp)); + } + + [Test] + public void TimestampField() + { + var message = new TestWellKnownTypes { TimestampField = new Timestamp() }; + AssertJson("{ 'timestampField': '1970-01-01T00:00:00Z' }", JsonFormatter.Default.Format(message)); + } + + [Test] + [TestCase(0, 0, "0s")] + [TestCase(1, 0, "1s")] + [TestCase(-1, 0, "-1s")] + [TestCase(0, 1, "0.000000001s")] + [TestCase(0, 10, "0.000000010s")] + [TestCase(0, 100, "0.000000100s")] + [TestCase(0, 1000, "0.000001s")] + [TestCase(0, 10000, "0.000010s")] + [TestCase(0, 100000, "0.000100s")] + [TestCase(0, 1000000, "0.001s")] + [TestCase(0, 10000000, "0.010s")] + [TestCase(0, 100000000, "0.100s")] + [TestCase(0, 120000000, "0.120s")] + [TestCase(0, 123000000, "0.123s")] + [TestCase(0, 123400000, "0.123400s")] + [TestCase(0, 123450000, "0.123450s")] + [TestCase(0, 123456000, "0.123456s")] + [TestCase(0, 123456700, "0.123456700s")] + [TestCase(0, 123456780, "0.123456780s")] + [TestCase(0, 123456789, "0.123456789s")] + [TestCase(0, -100000000, "-0.100s")] + [TestCase(1, 100000000, "1.100s")] + [TestCase(-1, -100000000, "-1.100s")] + public void DurationStandalone(long seconds, int nanoseconds, string expected) + { + var json = JsonFormatter.Default.Format(new Duration { Seconds = seconds, Nanos = nanoseconds }); + Assert.AreEqual(WrapInQuotes(expected), json); + } + + [Test] + [TestCase(1, 2123456789)] + [TestCase(1, -100000000)] + public void DurationStandalone_NonNormalized(long seconds, int nanoseconds) + { + var duration = new Duration { Seconds = seconds, Nanos = nanoseconds }; + Assert.Throws(() => JsonFormatter.Default.Format(duration)); + } + + [Test] + public void DurationField() + { + var message = new TestWellKnownTypes { DurationField = new Duration() }; + AssertJson("{ 'durationField': '0s' }", JsonFormatter.Default.Format(message)); + } + + [Test] + public void StructSample() + { + var message = new Struct + { + Fields = + { + { "a", Value.ForNull() }, + { "b", Value.ForBool(false) }, + { "c", Value.ForNumber(10.5) }, + { "d", Value.ForString("text") }, + { "e", Value.ForList(Value.ForString("t1"), Value.ForNumber(5)) }, + { "f", Value.ForStruct(new Struct { Fields = { { "nested", Value.ForString("value") } } }) } + } + }; + AssertJson("{ 'a': null, 'b': false, 'c': 10.5, 'd': 'text', 'e': [ 't1', 5 ], 'f': { 'nested': 'value' } }", message.ToString()); + } + + [Test] + [TestCase("foo__bar")] + [TestCase("foo_3_ar")] + [TestCase("fooBar")] + public void FieldMaskInvalid(string input) + { + var mask = new FieldMask { Paths = { input } }; + Assert.Throws(() => JsonFormatter.Default.Format(mask)); + } + + [Test] + public void FieldMaskStandalone() + { + var fieldMask = new FieldMask { Paths = { "", "single", "with_underscore", "nested.field.name", "nested..double_dot" } }; + Assert.AreEqual("\",single,withUnderscore,nested.field.name,nested..doubleDot\"", fieldMask.ToString()); + + // Invalid, but we shouldn't create broken JSON... + fieldMask = new FieldMask { Paths = { "x\\y" } }; + Assert.AreEqual(@"""x\\y""", fieldMask.ToString()); + } + + [Test] + public void FieldMaskField() + { + var message = new TestWellKnownTypes { FieldMaskField = new FieldMask { Paths = { "user.display_name", "photo" } } }; + AssertJson("{ 'fieldMaskField': 'user.displayName,photo' }", JsonFormatter.Default.Format(message)); + } + + // SourceContext is an example of a well-known type with no special JSON handling + [Test] + public void SourceContextStandalone() + { + var message = new SourceContext { FileName = "foo.proto" }; + AssertJson("{ 'fileName': 'foo.proto' }", JsonFormatter.Default.Format(message)); + } + + [Test] + public void AnyWellKnownType() + { + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithTypeRegistry(TypeRegistry.FromMessages(Timestamp.Descriptor))); + var timestamp = new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp(); + var any = Any.Pack(timestamp); + AssertJson("{ '@type': 'type.googleapis.com/google.protobuf.Timestamp', 'value': '1673-06-19T12:34:56Z' }", formatter.Format(any)); + } + + [Test] + public void AnyMessageType() + { + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithTypeRegistry(TypeRegistry.FromMessages(TestAllTypes.Descriptor))); + var message = new TestAllTypes { SingleInt32 = 10, SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } }; + var any = Any.Pack(message); + AssertJson("{ '@type': 'type.googleapis.com/protobuf_unittest3.TestAllTypes', 'singleInt32': 10, 'singleNestedMessage': { 'bb': 20 } }", formatter.Format(any)); + } + + [Test] + public void AnyMessageType_CustomPrefix() + { + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithTypeRegistry(TypeRegistry.FromMessages(TestAllTypes.Descriptor))); + var message = new TestAllTypes { SingleInt32 = 10 }; + var any = Any.Pack(message, "foo.bar/baz"); + AssertJson("{ '@type': 'foo.bar/baz/protobuf_unittest3.TestAllTypes', 'singleInt32': 10 }", formatter.Format(any)); + } + + [Test] + public void AnyNested() + { + var registry = TypeRegistry.FromMessages(TestWellKnownTypes.Descriptor, TestAllTypes.Descriptor); + var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithTypeRegistry(registry)); + + // Nest an Any as the value of an Any. + var doubleNestedMessage = new TestAllTypes { SingleInt32 = 20 }; + var nestedMessage = Any.Pack(doubleNestedMessage); + var message = new TestWellKnownTypes { AnyField = Any.Pack(nestedMessage) }; + AssertJson("{ 'anyField': { '@type': 'type.googleapis.com/google.protobuf.Any', 'value': { '@type': 'type.googleapis.com/protobuf_unittest3.TestAllTypes', 'singleInt32': 20 } } }", + formatter.Format(message)); + } + + [Test] + public void AnyUnknownType() + { + // The default type registry doesn't have any types in it. + var message = new TestAllTypes(); + var any = Any.Pack(message); + Assert.Throws(() => JsonFormatter.Default.Format(any)); + } + + [Test] + [TestCase(typeof(BoolValue), true, "true")] + [TestCase(typeof(Int32Value), 32, "32")] + [TestCase(typeof(Int64Value), 32L, "\"32\"")] + [TestCase(typeof(UInt32Value), 32U, "32")] + [TestCase(typeof(UInt64Value), 32UL, "\"32\"")] + [TestCase(typeof(StringValue), "foo", "\"foo\"")] + [TestCase(typeof(FloatValue), 1.5f, "1.5")] + [TestCase(typeof(DoubleValue), 1.5d, "1.5")] + public void Wrappers_Standalone(System.Type wrapperType, object value, string expectedJson) + { + IMessage populated = (IMessage)Activator.CreateInstance(wrapperType); + populated.Descriptor.Fields[WrappersReflection.WrapperValueFieldNumber].Accessor.SetValue(populated, value); + Assert.AreEqual(expectedJson, JsonFormatter.Default.Format(populated)); + } + + // Sanity tests for WriteValue. Not particularly comprehensive, as it's all covered above already, + // as FormatMessage uses WriteValue. + + [TestCase(null, "null")] + [TestCase(1, "1")] + [TestCase(1L, "'1'")] + [TestCase(0.5f, "0.5")] + [TestCase(0.5d, "0.5")] + [TestCase("text", "'text'")] + [TestCase("x\ny", @"'x\ny'")] + [TestCase(ForeignEnum.ForeignBar, "'FOREIGN_BAR'")] + public void WriteValue_Constant(object value, string expectedJson) + { + AssertWriteValue(value, expectedJson); + } + + [Test] + public void WriteValue_Timestamp() + { + var value = new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp(); + AssertWriteValue(value, "'1673-06-19T12:34:56Z'"); + } + + [Test] + public void WriteValue_Message() + { + var value = new TestAllTypes { SingleInt32 = 100, SingleInt64 = 3210987654321L }; + AssertWriteValue(value, "{ 'singleInt32': 100, 'singleInt64': '3210987654321' }"); + } + + [Test] + public void WriteValue_Message_PreserveNames() + { + var value = new TestAllTypes { SingleInt32 = 100, SingleInt64 = 3210987654321L }; + AssertWriteValue(value, "{ 'single_int32': 100, 'single_int64': '3210987654321' }", JsonFormatter.Settings.Default.WithPreserveProtoFieldNames(true)); + } + + [Test] + public void WriteValue_List() + { + var value = new RepeatedField { 1, 2, 3 }; + AssertWriteValue(value, "[ 1, 2, 3 ]"); + } + + [Test] + public void Proto2_DefaultValuesWritten() + { + var value = new ProtobufTestMessages.Proto2.TestAllTypesProto2() { FieldName13 = 0 }; + AssertWriteValue(value, "{ 'FieldName13': 0 }"); + } + + private static void AssertWriteValue(object value, string expectedJson, JsonFormatter.Settings settings = null) + { + var writer = new StringWriter(); + new JsonFormatter(settings ?? JsonFormatter.Settings.Default).WriteValue(writer, value); + string actual = writer.ToString(); + AssertJson(expectedJson, actual); + } + + /// + /// Checks that the actual JSON is the same as the expected JSON - but after replacing + /// all apostrophes in the expected JSON with double quotes. This basically makes the tests easier + /// to read. + /// + private static void AssertJson(string expectedJsonWithApostrophes, string actualJson) + { + var expectedJson = expectedJsonWithApostrophes.Replace("'", "\""); + Assert.AreEqual(expectedJson, actualJson); + } + } +} diff --git a/csharp/src/Google.Protobuf.Test/TestCornerCases.cs b/csharp/src/Google.Protobuf.Test/TestCornerCases.cs index 248f5fa913f2..859b49c2d637 100644 --- a/csharp/src/Google.Protobuf.Test/TestCornerCases.cs +++ b/csharp/src/Google.Protobuf.Test/TestCornerCases.cs @@ -1,62 +1,62 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using UnitTest.Issues.TestProtos; -using NUnit.Framework; - -namespace Google.Protobuf -{ - public class TestCornerCases - { - [Test] - public void TestRoundTripNegativeEnums() - { - NegativeEnumMessage msg = new NegativeEnumMessage - { - Value = NegativeEnum.MinusOne, - Values = { NegativeEnum.Zero, NegativeEnum.MinusOne, NegativeEnum.FiveBelow }, - PackedValues = { NegativeEnum.Zero, NegativeEnum.MinusOne, NegativeEnum.FiveBelow } - }; - - Assert.AreEqual(58, msg.CalculateSize()); - - byte[] bytes = new byte[58]; - CodedOutputStream output = new CodedOutputStream(bytes); - - msg.WriteTo(output); - Assert.AreEqual(0, output.SpaceLeft); - - NegativeEnumMessage copy = NegativeEnumMessage.Parser.ParseFrom(bytes); - Assert.AreEqual(msg, copy); - } - } -} +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using UnitTest.Issues.TestProtos; +using NUnit.Framework; + +namespace Google.Protobuf +{ + public class TestCornerCases + { + [Test] + public void TestRoundTripNegativeEnums() + { + NegativeEnumMessage msg = new NegativeEnumMessage + { + Value = NegativeEnum.MinusOne, + Values = { NegativeEnum.Zero, NegativeEnum.MinusOne, NegativeEnum.FiveBelow }, + PackedValues = { NegativeEnum.Zero, NegativeEnum.MinusOne, NegativeEnum.FiveBelow } + }; + + Assert.AreEqual(58, msg.CalculateSize()); + + byte[] bytes = new byte[58]; + CodedOutputStream output = new CodedOutputStream(bytes); + + msg.WriteTo(output); + Assert.AreEqual(0, output.SpaceLeft); + + NegativeEnumMessage copy = NegativeEnumMessage.Parser.ParseFrom(bytes); + Assert.AreEqual(msg, copy); + } + } +} diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs index 4b9a56939540..c05cb0853fc8 100644 --- a/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs +++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs @@ -1,4 +1,4 @@ -#region Copyright notice and license +#region Copyright notice and license // Protocol Buffers - Google's data interchange format // Copyright 2015 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ @@ -142,16 +142,16 @@ public void ToString_MessageContainingAny() } [Test] - public void IsWrongType() - { - var any = Any.Pack(SampleMessages.CreateFullTestAllTypes()); - Assert.False(any.Is(TestOneof.Descriptor)); + public void IsWrongType() + { + var any = Any.Pack(SampleMessages.CreateFullTestAllTypes()); + Assert.False(any.Is(TestOneof.Descriptor)); } - public void IsRightType() - { - var any = Any.Pack(SampleMessages.CreateFullTestAllTypes()); - Assert.True(any.Is(TestAllTypes.Descriptor)); + public void IsRightType() + { + var any = Any.Pack(SampleMessages.CreateFullTestAllTypes()); + Assert.True(any.Is(TestAllTypes.Descriptor)); } } } diff --git a/csharp/src/Google.Protobuf/ByteArray.cs b/csharp/src/Google.Protobuf/ByteArray.cs index 69b6ef8d634a..094a81eac64f 100644 --- a/csharp/src/Google.Protobuf/ByteArray.cs +++ b/csharp/src/Google.Protobuf/ByteArray.cs @@ -1,79 +1,79 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; - -namespace Google.Protobuf -{ - /// - /// Provides a utility routine to copy small arrays much more quickly than Buffer.BlockCopy - /// - internal static class ByteArray - { - /// - /// The threshold above which you should use Buffer.BlockCopy rather than ByteArray.Copy - /// - private const int CopyThreshold = 12; - - /// - /// Determines which copy routine to use based on the number of bytes to be copied. - /// - internal static void Copy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count) - { - if (count > CopyThreshold) - { - Buffer.BlockCopy(src, srcOffset, dst, dstOffset, count); - } - else - { - int stop = srcOffset + count; - for (int i = srcOffset; i < stop; i++) - { - dst[dstOffset++] = src[i]; - } - } - } - - /// - /// Reverses the order of bytes in the array - /// - internal static void Reverse(byte[] bytes) - { - for (int first = 0, last = bytes.Length - 1; first < last; first++, last--) - { - byte temp = bytes[first]; - bytes[first] = bytes[last]; - bytes[last] = temp; - } - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; + +namespace Google.Protobuf +{ + /// + /// Provides a utility routine to copy small arrays much more quickly than Buffer.BlockCopy + /// + internal static class ByteArray + { + /// + /// The threshold above which you should use Buffer.BlockCopy rather than ByteArray.Copy + /// + private const int CopyThreshold = 12; + + /// + /// Determines which copy routine to use based on the number of bytes to be copied. + /// + internal static void Copy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count) + { + if (count > CopyThreshold) + { + Buffer.BlockCopy(src, srcOffset, dst, dstOffset, count); + } + else + { + int stop = srcOffset + count; + for (int i = srcOffset; i < stop; i++) + { + dst[dstOffset++] = src[i]; + } + } + } + + /// + /// Reverses the order of bytes in the array + /// + internal static void Reverse(byte[] bytes) + { + for (int first = 0, last = bytes.Length - 1; first < last; first++, last--) + { + byte temp = bytes[first]; + bytes[first] = bytes[last]; + bytes[last] = temp; + } + } + } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf/ByteString.cs b/csharp/src/Google.Protobuf/ByteString.cs index 063b54356289..8c6eb5b3be7a 100644 --- a/csharp/src/Google.Protobuf/ByteString.cs +++ b/csharp/src/Google.Protobuf/ByteString.cs @@ -1,434 +1,434 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; -#if !NET35 -using System.Threading; -using System.Threading.Tasks; -#endif -#if NET35 -using Google.Protobuf.Compatibility; -#endif - -namespace Google.Protobuf -{ - /// - /// Immutable array of bytes. - /// - [SecuritySafeCritical] - public sealed class ByteString : IEnumerable, IEquatable - { - private static readonly ByteString empty = new ByteString(new byte[0]); - - private readonly ReadOnlyMemory bytes; - - /// - /// Internal use only. Ensure that the provided memory is not mutated and belongs to this instance. - /// - internal static ByteString AttachBytes(ReadOnlyMemory bytes) - { - return new ByteString(bytes); - } - - /// - /// Internal use only. Ensure that the provided memory is not mutated and belongs to this instance. - /// This method encapsulates converting array to memory. Reduces need for SecuritySafeCritical - /// in .NET Framework. - /// - internal static ByteString AttachBytes(byte[] bytes) - { - return AttachBytes(bytes.AsMemory()); - } - - /// - /// Constructs a new ByteString from the given memory. The memory is - /// *not* copied, and must not be modified after this constructor is called. - /// - private ByteString(ReadOnlyMemory bytes) - { - this.bytes = bytes; - } - - /// - /// Returns an empty ByteString. - /// - public static ByteString Empty - { - get { return empty; } - } - - /// - /// Returns the length of this ByteString in bytes. - /// - public int Length - { - get { return bytes.Length; } - } - - /// - /// Returns true if this byte string is empty, false otherwise. - /// - public bool IsEmpty - { - get { return Length == 0; } - } - - /// - /// Provides read-only access to the data of this . - /// No data is copied so this is the most efficient way of accessing. - /// - public ReadOnlySpan Span - { - get { return bytes.Span; } - } - - /// - /// Provides read-only access to the data of this . - /// No data is copied so this is the most efficient way of accessing. - /// - public ReadOnlyMemory Memory - { - get { return bytes; } - } - - /// - /// Converts this into a byte array. - /// - /// The data is copied - changes to the returned array will not be reflected in this ByteString. - /// A byte array with the same data as this ByteString. - public byte[] ToByteArray() - { - return bytes.ToArray(); - } - - /// - /// Converts this into a standard base64 representation. - /// - /// A base64 representation of this ByteString. - public string ToBase64() - { - if (MemoryMarshal.TryGetArray(bytes, out ArraySegment segment)) - { - // Fast path. ByteString was created with an array, so pass the underlying array. - return Convert.ToBase64String(segment.Array, segment.Offset, segment.Count); - } - else - { - // Slow path. BytesString is not an array. Convert memory and pass result to ToBase64String. - return Convert.ToBase64String(bytes.ToArray()); - } - } - - /// - /// Constructs a from the Base64 Encoded String. - /// - public static ByteString FromBase64(string bytes) - { - // By handling the empty string explicitly, we not only optimize but we fix a - // problem on CF 2.0. See issue 61 for details. - return bytes == "" ? Empty : new ByteString(Convert.FromBase64String(bytes)); - } - - /// - /// Constructs a from data in the given stream, synchronously. - /// - /// If successful, will be read completely, from the position - /// at the start of the call. - /// The stream to copy into a ByteString. - /// A ByteString with content read from the given stream. - public static ByteString FromStream(Stream stream) - { - ProtoPreconditions.CheckNotNull(stream, nameof(stream)); - int capacity = stream.CanSeek ? checked((int) (stream.Length - stream.Position)) : 0; - var memoryStream = new MemoryStream(capacity); - stream.CopyTo(memoryStream); -#if NETSTANDARD1_1 || NETSTANDARD2_0 - byte[] bytes = memoryStream.ToArray(); -#else - // Avoid an extra copy if we can. - byte[] bytes = memoryStream.Length == memoryStream.Capacity ? memoryStream.GetBuffer() : memoryStream.ToArray(); -#endif - return AttachBytes(bytes); - } - -#if !NET35 - /// - /// Constructs a from data in the given stream, asynchronously. - /// - /// If successful, will be read completely, from the position - /// at the start of the call. - /// The stream to copy into a ByteString. - /// The cancellation token to use when reading from the stream, if any. - /// A ByteString with content read from the given stream. - public static Task FromStreamAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken)) - { - ProtoPreconditions.CheckNotNull(stream, nameof(stream)); - return ByteStringAsync.FromStreamAsyncCore(stream, cancellationToken); - } -#endif - - /// - /// Constructs a from the given array. The contents - /// are copied, so further modifications to the array will not - /// be reflected in the returned ByteString. - /// This method can also be invoked in ByteString.CopyFrom(0xaa, 0xbb, ...) form - /// which is primarily useful for testing. - /// - public static ByteString CopyFrom(params byte[] bytes) - { - return new ByteString((byte[]) bytes.Clone()); - } - - /// - /// Constructs a from a portion of a byte array. - /// - public static ByteString CopyFrom(byte[] bytes, int offset, int count) - { - byte[] portion = new byte[count]; - ByteArray.Copy(bytes, offset, portion, 0, count); - return new ByteString(portion); - } - - /// - /// Constructs a from a read only span. The contents - /// are copied, so further modifications to the span will not - /// be reflected in the returned . - /// - public static ByteString CopyFrom(ReadOnlySpan bytes) - { - return new ByteString(bytes.ToArray()); - } - - /// - /// Creates a new by encoding the specified text with - /// the given encoding. - /// - public static ByteString CopyFrom(string text, Encoding encoding) - { - return new ByteString(encoding.GetBytes(text)); - } - - /// - /// Creates a new by encoding the specified text in UTF-8. - /// - public static ByteString CopyFromUtf8(string text) - { - return CopyFrom(text, Encoding.UTF8); - } - - /// - /// Returns the byte at the given index. - /// - public byte this[int index] - { - get { return bytes.Span[index]; } - } - - /// - /// Converts this into a string by applying the given encoding. - /// - /// - /// This method should only be used to convert binary data which was the result of encoding - /// text with the given encoding. - /// - /// The encoding to use to decode the binary data into text. - /// The result of decoding the binary data with the given decoding. - public string ToString(Encoding encoding) - { - if (MemoryMarshal.TryGetArray(bytes, out ArraySegment segment)) - { - // Fast path. ByteString was created with an array. - return encoding.GetString(segment.Array, segment.Offset, segment.Count); - } - else - { - // Slow path. BytesString is not an array. Convert memory and pass result to GetString. - // TODO: Consider using GetString overload that takes a pointer. - byte[] array = bytes.ToArray(); - return encoding.GetString(array, 0, array.Length); - } - } - - /// - /// Converts this into a string by applying the UTF-8 encoding. - /// - /// - /// This method should only be used to convert binary data which was the result of encoding - /// text with UTF-8. - /// - /// The result of decoding the binary data with the given decoding. - public string ToStringUtf8() - { - return ToString(Encoding.UTF8); - } - - /// - /// Returns an iterator over the bytes in this . - /// - /// An iterator over the bytes in this object. - [SecuritySafeCritical] - public IEnumerator GetEnumerator() - { - return MemoryMarshal.ToEnumerable(bytes).GetEnumerator(); - } - - /// - /// Returns an iterator over the bytes in this . - /// - /// An iterator over the bytes in this object. - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// Creates a CodedInputStream from this ByteString's data. - /// - public CodedInputStream CreateCodedInput() - { - // We trust CodedInputStream not to reveal the provided byte array or modify it - if (MemoryMarshal.TryGetArray(bytes, out ArraySegment segment) && segment.Count == bytes.Length) - { - // Fast path. ByteString was created with a complete array. - return new CodedInputStream(segment.Array, segment.Offset, segment.Count); - } - else - { - // Slow path. BytesString is not an array, or is a slice of an array. - // Convert memory and pass result to WriteRawBytes. - return new CodedInputStream(bytes.ToArray()); - } - } - - /// - /// Compares two byte strings for equality. - /// - /// The first byte string to compare. - /// The second byte string to compare. - /// true if the byte strings are equal; false otherwise. - public static bool operator ==(ByteString lhs, ByteString rhs) - { - if (ReferenceEquals(lhs, rhs)) - { - return true; - } - if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null)) - { - return false; - } - - return lhs.bytes.Span.SequenceEqual(rhs.bytes.Span); - } - - /// - /// Compares two byte strings for inequality. - /// - /// The first byte string to compare. - /// The second byte string to compare. - /// false if the byte strings are equal; true otherwise. - public static bool operator !=(ByteString lhs, ByteString rhs) - { - return !(lhs == rhs); - } - - /// - /// Compares this byte string with another object. - /// - /// The object to compare this with. - /// true if refers to an equal ; false otherwise. - [SecuritySafeCritical] - public override bool Equals(object obj) - { - return this == (obj as ByteString); - } - - /// - /// Returns a hash code for this object. Two equal byte strings - /// will return the same hash code. - /// - /// A hash code for this object. - [SecuritySafeCritical] - public override int GetHashCode() - { - ReadOnlySpan b = bytes.Span; - - int ret = 23; - for (int i = 0; i < b.Length; i++) - { - ret = (ret * 31) + b[i]; - } - return ret; - } - - /// - /// Compares this byte string with another. - /// - /// The to compare this with. - /// true if refers to an equal byte string; false otherwise. - public bool Equals(ByteString other) - { - return this == other; - } - - /// - /// Copies the entire byte array to the destination array provided at the offset specified. - /// - public void CopyTo(byte[] array, int position) - { - bytes.CopyTo(array.AsMemory(position)); - } - - /// - /// Writes the entire byte array to the provided stream - /// - public void WriteTo(Stream outputStream) - { - if (MemoryMarshal.TryGetArray(bytes, out ArraySegment segment)) - { - // Fast path. ByteString was created with an array, so pass the underlying array. - outputStream.Write(segment.Array, segment.Offset, segment.Count); - } - else - { - // Slow path. BytesString is not an array. Convert memory and pass result to WriteRawBytes. - var array = bytes.ToArray(); - outputStream.Write(array, 0, array.Length); - } - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Security; +using System.Text; +#if !NET35 +using System.Threading; +using System.Threading.Tasks; +#endif +#if NET35 +using Google.Protobuf.Compatibility; +#endif + +namespace Google.Protobuf +{ + /// + /// Immutable array of bytes. + /// + [SecuritySafeCritical] + public sealed class ByteString : IEnumerable, IEquatable + { + private static readonly ByteString empty = new ByteString(new byte[0]); + + private readonly ReadOnlyMemory bytes; + + /// + /// Internal use only. Ensure that the provided memory is not mutated and belongs to this instance. + /// + internal static ByteString AttachBytes(ReadOnlyMemory bytes) + { + return new ByteString(bytes); + } + + /// + /// Internal use only. Ensure that the provided memory is not mutated and belongs to this instance. + /// This method encapsulates converting array to memory. Reduces need for SecuritySafeCritical + /// in .NET Framework. + /// + internal static ByteString AttachBytes(byte[] bytes) + { + return AttachBytes(bytes.AsMemory()); + } + + /// + /// Constructs a new ByteString from the given memory. The memory is + /// *not* copied, and must not be modified after this constructor is called. + /// + private ByteString(ReadOnlyMemory bytes) + { + this.bytes = bytes; + } + + /// + /// Returns an empty ByteString. + /// + public static ByteString Empty + { + get { return empty; } + } + + /// + /// Returns the length of this ByteString in bytes. + /// + public int Length + { + get { return bytes.Length; } + } + + /// + /// Returns true if this byte string is empty, false otherwise. + /// + public bool IsEmpty + { + get { return Length == 0; } + } + + /// + /// Provides read-only access to the data of this . + /// No data is copied so this is the most efficient way of accessing. + /// + public ReadOnlySpan Span + { + get { return bytes.Span; } + } + + /// + /// Provides read-only access to the data of this . + /// No data is copied so this is the most efficient way of accessing. + /// + public ReadOnlyMemory Memory + { + get { return bytes; } + } + + /// + /// Converts this into a byte array. + /// + /// The data is copied - changes to the returned array will not be reflected in this ByteString. + /// A byte array with the same data as this ByteString. + public byte[] ToByteArray() + { + return bytes.ToArray(); + } + + /// + /// Converts this into a standard base64 representation. + /// + /// A base64 representation of this ByteString. + public string ToBase64() + { + if (MemoryMarshal.TryGetArray(bytes, out ArraySegment segment)) + { + // Fast path. ByteString was created with an array, so pass the underlying array. + return Convert.ToBase64String(segment.Array, segment.Offset, segment.Count); + } + else + { + // Slow path. BytesString is not an array. Convert memory and pass result to ToBase64String. + return Convert.ToBase64String(bytes.ToArray()); + } + } + + /// + /// Constructs a from the Base64 Encoded String. + /// + public static ByteString FromBase64(string bytes) + { + // By handling the empty string explicitly, we not only optimize but we fix a + // problem on CF 2.0. See issue 61 for details. + return bytes == "" ? Empty : new ByteString(Convert.FromBase64String(bytes)); + } + + /// + /// Constructs a from data in the given stream, synchronously. + /// + /// If successful, will be read completely, from the position + /// at the start of the call. + /// The stream to copy into a ByteString. + /// A ByteString with content read from the given stream. + public static ByteString FromStream(Stream stream) + { + ProtoPreconditions.CheckNotNull(stream, nameof(stream)); + int capacity = stream.CanSeek ? checked((int) (stream.Length - stream.Position)) : 0; + var memoryStream = new MemoryStream(capacity); + stream.CopyTo(memoryStream); +#if NETSTANDARD1_1 || NETSTANDARD2_0 + byte[] bytes = memoryStream.ToArray(); +#else + // Avoid an extra copy if we can. + byte[] bytes = memoryStream.Length == memoryStream.Capacity ? memoryStream.GetBuffer() : memoryStream.ToArray(); +#endif + return AttachBytes(bytes); + } + +#if !NET35 + /// + /// Constructs a from data in the given stream, asynchronously. + /// + /// If successful, will be read completely, from the position + /// at the start of the call. + /// The stream to copy into a ByteString. + /// The cancellation token to use when reading from the stream, if any. + /// A ByteString with content read from the given stream. + public static Task FromStreamAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken)) + { + ProtoPreconditions.CheckNotNull(stream, nameof(stream)); + return ByteStringAsync.FromStreamAsyncCore(stream, cancellationToken); + } +#endif + + /// + /// Constructs a from the given array. The contents + /// are copied, so further modifications to the array will not + /// be reflected in the returned ByteString. + /// This method can also be invoked in ByteString.CopyFrom(0xaa, 0xbb, ...) form + /// which is primarily useful for testing. + /// + public static ByteString CopyFrom(params byte[] bytes) + { + return new ByteString((byte[]) bytes.Clone()); + } + + /// + /// Constructs a from a portion of a byte array. + /// + public static ByteString CopyFrom(byte[] bytes, int offset, int count) + { + byte[] portion = new byte[count]; + ByteArray.Copy(bytes, offset, portion, 0, count); + return new ByteString(portion); + } + + /// + /// Constructs a from a read only span. The contents + /// are copied, so further modifications to the span will not + /// be reflected in the returned . + /// + public static ByteString CopyFrom(ReadOnlySpan bytes) + { + return new ByteString(bytes.ToArray()); + } + + /// + /// Creates a new by encoding the specified text with + /// the given encoding. + /// + public static ByteString CopyFrom(string text, Encoding encoding) + { + return new ByteString(encoding.GetBytes(text)); + } + + /// + /// Creates a new by encoding the specified text in UTF-8. + /// + public static ByteString CopyFromUtf8(string text) + { + return CopyFrom(text, Encoding.UTF8); + } + + /// + /// Returns the byte at the given index. + /// + public byte this[int index] + { + get { return bytes.Span[index]; } + } + + /// + /// Converts this into a string by applying the given encoding. + /// + /// + /// This method should only be used to convert binary data which was the result of encoding + /// text with the given encoding. + /// + /// The encoding to use to decode the binary data into text. + /// The result of decoding the binary data with the given decoding. + public string ToString(Encoding encoding) + { + if (MemoryMarshal.TryGetArray(bytes, out ArraySegment segment)) + { + // Fast path. ByteString was created with an array. + return encoding.GetString(segment.Array, segment.Offset, segment.Count); + } + else + { + // Slow path. BytesString is not an array. Convert memory and pass result to GetString. + // TODO: Consider using GetString overload that takes a pointer. + byte[] array = bytes.ToArray(); + return encoding.GetString(array, 0, array.Length); + } + } + + /// + /// Converts this into a string by applying the UTF-8 encoding. + /// + /// + /// This method should only be used to convert binary data which was the result of encoding + /// text with UTF-8. + /// + /// The result of decoding the binary data with the given decoding. + public string ToStringUtf8() + { + return ToString(Encoding.UTF8); + } + + /// + /// Returns an iterator over the bytes in this . + /// + /// An iterator over the bytes in this object. + [SecuritySafeCritical] + public IEnumerator GetEnumerator() + { + return MemoryMarshal.ToEnumerable(bytes).GetEnumerator(); + } + + /// + /// Returns an iterator over the bytes in this . + /// + /// An iterator over the bytes in this object. + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Creates a CodedInputStream from this ByteString's data. + /// + public CodedInputStream CreateCodedInput() + { + // We trust CodedInputStream not to reveal the provided byte array or modify it + if (MemoryMarshal.TryGetArray(bytes, out ArraySegment segment) && segment.Count == bytes.Length) + { + // Fast path. ByteString was created with a complete array. + return new CodedInputStream(segment.Array, segment.Offset, segment.Count); + } + else + { + // Slow path. BytesString is not an array, or is a slice of an array. + // Convert memory and pass result to WriteRawBytes. + return new CodedInputStream(bytes.ToArray()); + } + } + + /// + /// Compares two byte strings for equality. + /// + /// The first byte string to compare. + /// The second byte string to compare. + /// true if the byte strings are equal; false otherwise. + public static bool operator ==(ByteString lhs, ByteString rhs) + { + if (ReferenceEquals(lhs, rhs)) + { + return true; + } + if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null)) + { + return false; + } + + return lhs.bytes.Span.SequenceEqual(rhs.bytes.Span); + } + + /// + /// Compares two byte strings for inequality. + /// + /// The first byte string to compare. + /// The second byte string to compare. + /// false if the byte strings are equal; true otherwise. + public static bool operator !=(ByteString lhs, ByteString rhs) + { + return !(lhs == rhs); + } + + /// + /// Compares this byte string with another object. + /// + /// The object to compare this with. + /// true if refers to an equal ; false otherwise. + [SecuritySafeCritical] + public override bool Equals(object obj) + { + return this == (obj as ByteString); + } + + /// + /// Returns a hash code for this object. Two equal byte strings + /// will return the same hash code. + /// + /// A hash code for this object. + [SecuritySafeCritical] + public override int GetHashCode() + { + ReadOnlySpan b = bytes.Span; + + int ret = 23; + for (int i = 0; i < b.Length; i++) + { + ret = (ret * 31) + b[i]; + } + return ret; + } + + /// + /// Compares this byte string with another. + /// + /// The to compare this with. + /// true if refers to an equal byte string; false otherwise. + public bool Equals(ByteString other) + { + return this == other; + } + + /// + /// Copies the entire byte array to the destination array provided at the offset specified. + /// + public void CopyTo(byte[] array, int position) + { + bytes.CopyTo(array.AsMemory(position)); + } + + /// + /// Writes the entire byte array to the provided stream + /// + public void WriteTo(Stream outputStream) + { + if (MemoryMarshal.TryGetArray(bytes, out ArraySegment segment)) + { + // Fast path. ByteString was created with an array, so pass the underlying array. + outputStream.Write(segment.Array, segment.Offset, segment.Count); + } + else + { + // Slow path. BytesString is not an array. Convert memory and pass result to WriteRawBytes. + var array = bytes.ToArray(); + outputStream.Write(array, 0, array.Length); + } + } + } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf/CodedInputStream.cs b/csharp/src/Google.Protobuf/CodedInputStream.cs index 27b23c0d9ce6..912c11f74f04 100644 --- a/csharp/src/Google.Protobuf/CodedInputStream.cs +++ b/csharp/src/Google.Protobuf/CodedInputStream.cs @@ -1,698 +1,698 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using Google.Protobuf.Collections; -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Security; - -namespace Google.Protobuf -{ - /// - /// Reads and decodes protocol message fields. - /// - /// - /// - /// This class is generally used by generated code to read appropriate - /// primitives from the stream. It effectively encapsulates the lowest - /// levels of protocol buffer format. - /// - /// - /// Repeated fields and map fields are not handled by this class; use - /// and to serialize such fields. - /// - /// - [SecuritySafeCritical] - public sealed class CodedInputStream : IDisposable - { - /// - /// Whether to leave the underlying stream open when disposing of this stream. - /// This is always true when there's no stream. - /// - private readonly bool leaveOpen; - - /// - /// Buffer of data read from the stream or provided at construction time. - /// - private readonly byte[] buffer; - - /// - /// The stream to read further input from, or null if the byte array buffer was provided - /// directly on construction, with no further data available. - /// - private readonly Stream input; - - /// - /// The parser state is kept separately so that other parse implementations can reuse the same - /// parsing primitives. - /// - private ParserInternalState state; - - internal const int DefaultRecursionLimit = 100; - internal const int DefaultSizeLimit = Int32.MaxValue; - internal const int BufferSize = 4096; - - #region Construction - // Note that the checks are performed such that we don't end up checking obviously-valid things - // like non-null references for arrays we've just created. - - /// - /// Creates a new CodedInputStream reading data from the given byte array. - /// - public CodedInputStream(byte[] buffer) : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), 0, buffer.Length, true) - { - } - - /// - /// Creates a new that reads from the given byte array slice. - /// - public CodedInputStream(byte[] buffer, int offset, int length) - : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), offset, offset + length, true) - { - if (offset < 0 || offset > buffer.Length) - { - throw new ArgumentOutOfRangeException("offset", "Offset must be within the buffer"); - } - if (length < 0 || offset + length > buffer.Length) - { - throw new ArgumentOutOfRangeException("length", "Length must be non-negative and within the buffer"); - } - } - - /// - /// Creates a new reading data from the given stream, which will be disposed - /// when the returned object is disposed. - /// - /// The stream to read from. - public CodedInputStream(Stream input) : this(input, false) - { - } - - /// - /// Creates a new reading data from the given stream. - /// - /// The stream to read from. - /// true to leave open when the returned - /// is disposed; false to dispose of the given stream when the - /// returned object is disposed. - public CodedInputStream(Stream input, bool leaveOpen) - : this(ProtoPreconditions.CheckNotNull(input, "input"), new byte[BufferSize], 0, 0, leaveOpen) - { - } - - /// - /// Creates a new CodedInputStream reading data from the given - /// stream and buffer, using the default limits. - /// - internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, bool leaveOpen) - { - this.input = input; - this.buffer = buffer; - this.state.bufferPos = bufferPos; - this.state.bufferSize = bufferSize; - this.state.sizeLimit = DefaultSizeLimit; - this.state.recursionLimit = DefaultRecursionLimit; - SegmentedBufferHelper.Initialize(this, out this.state.segmentedBufferHelper); - this.leaveOpen = leaveOpen; - - this.state.currentLimit = int.MaxValue; - } - - /// - /// Creates a new CodedInputStream reading data from the given - /// stream and buffer, using the specified limits. - /// - /// - /// This chains to the version with the default limits instead of vice versa to avoid - /// having to check that the default values are valid every time. - /// - internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, int sizeLimit, int recursionLimit, bool leaveOpen) - : this(input, buffer, bufferPos, bufferSize, leaveOpen) - { - if (sizeLimit <= 0) - { - throw new ArgumentOutOfRangeException("sizeLimit", "Size limit must be positive"); - } - if (recursionLimit <= 0) - { - throw new ArgumentOutOfRangeException("recursionLimit!", "Recursion limit must be positive"); - } - this.state.sizeLimit = sizeLimit; - this.state.recursionLimit = recursionLimit; - } - #endregion - - /// - /// Creates a with the specified size and recursion limits, reading - /// from an input stream. - /// - /// - /// This method exists separately from the constructor to reduce the number of constructor overloads. - /// It is likely to be used considerably less frequently than the constructors, as the default limits - /// are suitable for most use cases. - /// - /// The input stream to read from - /// The total limit of data to read from the stream. - /// The maximum recursion depth to allow while reading. - /// A CodedInputStream reading from with the specified size - /// and recursion limits. - public static CodedInputStream CreateWithLimits(Stream input, int sizeLimit, int recursionLimit) - { - // Note: we may want an overload accepting leaveOpen - return new CodedInputStream(input, new byte[BufferSize], 0, 0, sizeLimit, recursionLimit, false); - } - - /// - /// Returns the current position in the input stream, or the position in the input buffer - /// - public long Position - { - get - { - if (input != null) - { - return input.Position - ((state.bufferSize + state.bufferSizeAfterLimit) - state.bufferPos); - } - return state.bufferPos; - } - } - - /// - /// Returns the last tag read, or 0 if no tags have been read or we've read beyond - /// the end of the stream. - /// - internal uint LastTag { get { return state.lastTag; } } - - /// - /// Returns the size limit for this stream. - /// - /// - /// This limit is applied when reading from the underlying stream, as a sanity check. It is - /// not applied when reading from a byte array data source without an underlying stream. - /// The default value is Int32.MaxValue. - /// - /// - /// The size limit. - /// - public int SizeLimit { get { return state.sizeLimit; } } - - /// - /// Returns the recursion limit for this stream. This limit is applied whilst reading messages, - /// to avoid maliciously-recursive data. - /// - /// - /// The default limit is 100. - /// - /// - /// The recursion limit for this stream. - /// - public int RecursionLimit { get { return state.recursionLimit; } } - - /// - /// Internal-only property; when set to true, unknown fields will be discarded while parsing. - /// - internal bool DiscardUnknownFields - { - get { return state.DiscardUnknownFields; } - set { state.DiscardUnknownFields = value; } - } - - /// - /// Internal-only property; provides extension identifiers to compatible messages while parsing. - /// - internal ExtensionRegistry ExtensionRegistry - { - get { return state.ExtensionRegistry; } - set { state.ExtensionRegistry = value; } - } - - internal byte[] InternalBuffer => buffer; - - internal Stream InternalInputStream => input; - - internal ref ParserInternalState InternalState => ref state; - - /// - /// Disposes of this instance, potentially closing any underlying stream. - /// - /// - /// As there is no flushing to perform here, disposing of a which - /// was constructed with the leaveOpen option parameter set to true (or one which - /// was constructed to read from a byte array) has no effect. - /// - public void Dispose() - { - if (!leaveOpen) - { - input.Dispose(); - } - } - - #region Validation - /// - /// Verifies that the last call to ReadTag() returned tag 0 - in other words, - /// we've reached the end of the stream when we expected to. - /// - /// The - /// tag read was not the one specified - internal void CheckReadEndOfStreamTag() - { - ParsingPrimitivesMessages.CheckReadEndOfStreamTag(ref state); - } - #endregion - - #region Reading of tags etc - - /// - /// Peeks at the next field tag. This is like calling , but the - /// tag is not consumed. (So a subsequent call to will return the - /// same value.) - /// - public uint PeekTag() - { - var span = new ReadOnlySpan(buffer); - return ParsingPrimitives.PeekTag(ref span, ref state); - } - - /// - /// Reads a field tag, returning the tag of 0 for "end of stream". - /// - /// - /// If this method returns 0, it doesn't necessarily mean the end of all - /// the data in this CodedInputStream; it may be the end of the logical stream - /// for an embedded message, for example. - /// - /// The next field tag, or 0 for end of stream. (0 is never a valid tag.) - public uint ReadTag() - { - var span = new ReadOnlySpan(buffer); - return ParsingPrimitives.ParseTag(ref span, ref state); - } - - /// - /// Skips the data for the field with the tag we've just read. - /// This should be called directly after , when - /// the caller wishes to skip an unknown field. - /// - /// - /// This method throws if the last-read tag was an end-group tag. - /// If a caller wishes to skip a group, they should skip the whole group, by calling this method after reading the - /// start-group tag. This behavior allows callers to call this method on any field they don't understand, correctly - /// resulting in an error if an end-group tag has not been paired with an earlier start-group tag. - /// - /// The last tag was an end-group tag - /// The last read operation read to the end of the logical stream - public void SkipLastField() - { - var span = new ReadOnlySpan(buffer); - ParsingPrimitivesMessages.SkipLastField(ref span, ref state); - } - - /// - /// Skip a group. - /// - internal void SkipGroup(uint startGroupTag) - { - var span = new ReadOnlySpan(buffer); - ParsingPrimitivesMessages.SkipGroup(ref span, ref state, startGroupTag); - } - - /// - /// Reads a double field from the stream. - /// - public double ReadDouble() - { - var span = new ReadOnlySpan(buffer); - return ParsingPrimitives.ParseDouble(ref span, ref state); - } - - /// - /// Reads a float field from the stream. - /// - public float ReadFloat() - { - var span = new ReadOnlySpan(buffer); - return ParsingPrimitives.ParseFloat(ref span, ref state); - } - - /// - /// Reads a uint64 field from the stream. - /// - public ulong ReadUInt64() - { - return ReadRawVarint64(); - } - - /// - /// Reads an int64 field from the stream. - /// - public long ReadInt64() - { - return (long) ReadRawVarint64(); - } - - /// - /// Reads an int32 field from the stream. - /// - public int ReadInt32() - { - return (int) ReadRawVarint32(); - } - - /// - /// Reads a fixed64 field from the stream. - /// - public ulong ReadFixed64() - { - return ReadRawLittleEndian64(); - } - - /// - /// Reads a fixed32 field from the stream. - /// - public uint ReadFixed32() - { - return ReadRawLittleEndian32(); - } - - /// - /// Reads a bool field from the stream. - /// - public bool ReadBool() - { - return ReadRawVarint64() != 0; - } - - /// - /// Reads a string field from the stream. - /// - public string ReadString() - { - var span = new ReadOnlySpan(buffer); - return ParsingPrimitives.ReadString(ref span, ref state); - } - - /// - /// Reads an embedded message field value from the stream. - /// - public void ReadMessage(IMessage builder) - { - // TODO(jtattermusch): if the message doesn't implement IBufferMessage (and thus does not provide the InternalMergeFrom method), - // what we're doing here works fine, but could be more efficient. - // What happends is that we first initialize a ParseContext from the current coded input stream only to parse the length of the message, at which point - // we will need to switch back again to CodedInputStream-based parsing (which involves copying and storing the state) to be able to - // invoke the legacy MergeFrom(CodedInputStream) method. - // For now, this inefficiency is fine, considering this is only a backward-compatibility scenario (and regenerating the code fixes it). - ParseContext.Initialize(buffer.AsSpan(), ref state, out ParseContext ctx); - try - { - ParsingPrimitivesMessages.ReadMessage(ref ctx, builder); - } - finally - { - ctx.CopyStateTo(this); - } - } - - /// - /// Reads an embedded group field from the stream. - /// - public void ReadGroup(IMessage builder) - { - ParseContext.Initialize(this, out ParseContext ctx); - try - { - ParsingPrimitivesMessages.ReadGroup(ref ctx, builder); - } - finally - { - ctx.CopyStateTo(this); - } - } - - /// - /// Reads a bytes field value from the stream. - /// - public ByteString ReadBytes() - { - var span = new ReadOnlySpan(buffer); - return ParsingPrimitives.ReadBytes(ref span, ref state); - } - - /// - /// Reads a uint32 field value from the stream. - /// - public uint ReadUInt32() - { - return ReadRawVarint32(); - } - - /// - /// Reads an enum field value from the stream. - /// - public int ReadEnum() - { - // Currently just a pass-through, but it's nice to separate it logically from WriteInt32. - return (int) ReadRawVarint32(); - } - - /// - /// Reads an sfixed32 field value from the stream. - /// - public int ReadSFixed32() - { - return (int) ReadRawLittleEndian32(); - } - - /// - /// Reads an sfixed64 field value from the stream. - /// - public long ReadSFixed64() - { - return (long) ReadRawLittleEndian64(); - } - - /// - /// Reads an sint32 field value from the stream. - /// - public int ReadSInt32() - { - return ParsingPrimitives.DecodeZigZag32(ReadRawVarint32()); - } - - /// - /// Reads an sint64 field value from the stream. - /// - public long ReadSInt64() - { - return ParsingPrimitives.DecodeZigZag64(ReadRawVarint64()); - } - - /// - /// Reads a length for length-delimited data. - /// - /// - /// This is internally just reading a varint, but this method exists - /// to make the calling code clearer. - /// - public int ReadLength() - { - var span = new ReadOnlySpan(buffer); - return ParsingPrimitives.ParseLength(ref span, ref state); - } - - /// - /// Peeks at the next tag in the stream. If it matches , - /// the tag is consumed and the method returns true; otherwise, the - /// stream is left in the original position and the method returns false. - /// - public bool MaybeConsumeTag(uint tag) - { - var span = new ReadOnlySpan(buffer); - return ParsingPrimitives.MaybeConsumeTag(ref span, ref state, tag); - } - -#endregion - - #region Underlying reading primitives - - /// - /// Reads a raw Varint from the stream. If larger than 32 bits, discard the upper bits. - /// This method is optimised for the case where we've got lots of data in the buffer. - /// That means we can check the size just once, then just read directly from the buffer - /// without constant rechecking of the buffer length. - /// - internal uint ReadRawVarint32() - { - var span = new ReadOnlySpan(buffer); - return ParsingPrimitives.ParseRawVarint32(ref span, ref state); - } - - /// - /// Reads a varint from the input one byte at a time, so that it does not - /// read any bytes after the end of the varint. If you simply wrapped the - /// stream in a CodedInputStream and used ReadRawVarint32(Stream) - /// then you would probably end up reading past the end of the varint since - /// CodedInputStream buffers its input. - /// - /// - /// - internal static uint ReadRawVarint32(Stream input) - { - return ParsingPrimitives.ReadRawVarint32(input); - } - - /// - /// Reads a raw varint from the stream. - /// - internal ulong ReadRawVarint64() - { - var span = new ReadOnlySpan(buffer); - return ParsingPrimitives.ParseRawVarint64(ref span, ref state); - } - - /// - /// Reads a 32-bit little-endian integer from the stream. - /// - internal uint ReadRawLittleEndian32() - { - var span = new ReadOnlySpan(buffer); - return ParsingPrimitives.ParseRawLittleEndian32(ref span, ref state); - } - - /// - /// Reads a 64-bit little-endian integer from the stream. - /// - internal ulong ReadRawLittleEndian64() - { - var span = new ReadOnlySpan(buffer); - return ParsingPrimitives.ParseRawLittleEndian64(ref span, ref state); - } - #endregion - - #region Internal reading and buffer management - - /// - /// Sets currentLimit to (current position) + byteLimit. This is called - /// when descending into a length-delimited embedded message. The previous - /// limit is returned. - /// - /// The old limit. - internal int PushLimit(int byteLimit) - { - return SegmentedBufferHelper.PushLimit(ref state, byteLimit); - } - - /// - /// Discards the current limit, returning the previous limit. - /// - internal void PopLimit(int oldLimit) - { - SegmentedBufferHelper.PopLimit(ref state, oldLimit); - } - - /// - /// Returns whether or not all the data before the limit has been read. - /// - /// - internal bool ReachedLimit - { - get - { - return SegmentedBufferHelper.IsReachedLimit(ref state); - } - } - - /// - /// Returns true if the stream has reached the end of the input. This is the - /// case if either the end of the underlying input source has been reached or - /// the stream has reached a limit created using PushLimit. - /// - public bool IsAtEnd - { - get - { - var span = new ReadOnlySpan(buffer); - return SegmentedBufferHelper.IsAtEnd(ref span, ref state); - } - } - - /// - /// Called when buffer is empty to read more bytes from the - /// input. If is true, RefillBuffer() guarantees that - /// either there will be at least one byte in the buffer when it returns - /// or it will throw an exception. If is false, - /// RefillBuffer() returns false if no more bytes were available. - /// - /// - /// - private bool RefillBuffer(bool mustSucceed) - { - var span = new ReadOnlySpan(buffer); - return state.segmentedBufferHelper.RefillBuffer(ref span, ref state, mustSucceed); - } - - /// - /// Reads a fixed size of bytes from the input. - /// - /// - /// the end of the stream or the current limit was reached - /// - internal byte[] ReadRawBytes(int size) - { - var span = new ReadOnlySpan(buffer); - return ParsingPrimitives.ReadRawBytes(ref span, ref state, size); - } - - /// - /// Reads a top-level message or a nested message after the limits for this message have been pushed. - /// (parser will proceed until the end of the current limit) - /// NOTE: this method needs to be public because it's invoked by the generated code - e.g. msg.MergeFrom(CodedInputStream input) method - /// - public void ReadRawMessage(IMessage message) - { - ParseContext.Initialize(this, out ParseContext ctx); - try - { - ParsingPrimitivesMessages.ReadRawMessage(ref ctx, message); - } - finally - { - ctx.CopyStateTo(this); - } - } -#endregion - } -} +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using Google.Protobuf.Collections; +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; + +namespace Google.Protobuf +{ + /// + /// Reads and decodes protocol message fields. + /// + /// + /// + /// This class is generally used by generated code to read appropriate + /// primitives from the stream. It effectively encapsulates the lowest + /// levels of protocol buffer format. + /// + /// + /// Repeated fields and map fields are not handled by this class; use + /// and to serialize such fields. + /// + /// + [SecuritySafeCritical] + public sealed class CodedInputStream : IDisposable + { + /// + /// Whether to leave the underlying stream open when disposing of this stream. + /// This is always true when there's no stream. + /// + private readonly bool leaveOpen; + + /// + /// Buffer of data read from the stream or provided at construction time. + /// + private readonly byte[] buffer; + + /// + /// The stream to read further input from, or null if the byte array buffer was provided + /// directly on construction, with no further data available. + /// + private readonly Stream input; + + /// + /// The parser state is kept separately so that other parse implementations can reuse the same + /// parsing primitives. + /// + private ParserInternalState state; + + internal const int DefaultRecursionLimit = 100; + internal const int DefaultSizeLimit = Int32.MaxValue; + internal const int BufferSize = 4096; + + #region Construction + // Note that the checks are performed such that we don't end up checking obviously-valid things + // like non-null references for arrays we've just created. + + /// + /// Creates a new CodedInputStream reading data from the given byte array. + /// + public CodedInputStream(byte[] buffer) : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), 0, buffer.Length, true) + { + } + + /// + /// Creates a new that reads from the given byte array slice. + /// + public CodedInputStream(byte[] buffer, int offset, int length) + : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), offset, offset + length, true) + { + if (offset < 0 || offset > buffer.Length) + { + throw new ArgumentOutOfRangeException("offset", "Offset must be within the buffer"); + } + if (length < 0 || offset + length > buffer.Length) + { + throw new ArgumentOutOfRangeException("length", "Length must be non-negative and within the buffer"); + } + } + + /// + /// Creates a new reading data from the given stream, which will be disposed + /// when the returned object is disposed. + /// + /// The stream to read from. + public CodedInputStream(Stream input) : this(input, false) + { + } + + /// + /// Creates a new reading data from the given stream. + /// + /// The stream to read from. + /// true to leave open when the returned + /// is disposed; false to dispose of the given stream when the + /// returned object is disposed. + public CodedInputStream(Stream input, bool leaveOpen) + : this(ProtoPreconditions.CheckNotNull(input, "input"), new byte[BufferSize], 0, 0, leaveOpen) + { + } + + /// + /// Creates a new CodedInputStream reading data from the given + /// stream and buffer, using the default limits. + /// + internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, bool leaveOpen) + { + this.input = input; + this.buffer = buffer; + this.state.bufferPos = bufferPos; + this.state.bufferSize = bufferSize; + this.state.sizeLimit = DefaultSizeLimit; + this.state.recursionLimit = DefaultRecursionLimit; + SegmentedBufferHelper.Initialize(this, out this.state.segmentedBufferHelper); + this.leaveOpen = leaveOpen; + + this.state.currentLimit = int.MaxValue; + } + + /// + /// Creates a new CodedInputStream reading data from the given + /// stream and buffer, using the specified limits. + /// + /// + /// This chains to the version with the default limits instead of vice versa to avoid + /// having to check that the default values are valid every time. + /// + internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, int sizeLimit, int recursionLimit, bool leaveOpen) + : this(input, buffer, bufferPos, bufferSize, leaveOpen) + { + if (sizeLimit <= 0) + { + throw new ArgumentOutOfRangeException("sizeLimit", "Size limit must be positive"); + } + if (recursionLimit <= 0) + { + throw new ArgumentOutOfRangeException("recursionLimit!", "Recursion limit must be positive"); + } + this.state.sizeLimit = sizeLimit; + this.state.recursionLimit = recursionLimit; + } + #endregion + + /// + /// Creates a with the specified size and recursion limits, reading + /// from an input stream. + /// + /// + /// This method exists separately from the constructor to reduce the number of constructor overloads. + /// It is likely to be used considerably less frequently than the constructors, as the default limits + /// are suitable for most use cases. + /// + /// The input stream to read from + /// The total limit of data to read from the stream. + /// The maximum recursion depth to allow while reading. + /// A CodedInputStream reading from with the specified size + /// and recursion limits. + public static CodedInputStream CreateWithLimits(Stream input, int sizeLimit, int recursionLimit) + { + // Note: we may want an overload accepting leaveOpen + return new CodedInputStream(input, new byte[BufferSize], 0, 0, sizeLimit, recursionLimit, false); + } + + /// + /// Returns the current position in the input stream, or the position in the input buffer + /// + public long Position + { + get + { + if (input != null) + { + return input.Position - ((state.bufferSize + state.bufferSizeAfterLimit) - state.bufferPos); + } + return state.bufferPos; + } + } + + /// + /// Returns the last tag read, or 0 if no tags have been read or we've read beyond + /// the end of the stream. + /// + internal uint LastTag { get { return state.lastTag; } } + + /// + /// Returns the size limit for this stream. + /// + /// + /// This limit is applied when reading from the underlying stream, as a sanity check. It is + /// not applied when reading from a byte array data source without an underlying stream. + /// The default value is Int32.MaxValue. + /// + /// + /// The size limit. + /// + public int SizeLimit { get { return state.sizeLimit; } } + + /// + /// Returns the recursion limit for this stream. This limit is applied whilst reading messages, + /// to avoid maliciously-recursive data. + /// + /// + /// The default limit is 100. + /// + /// + /// The recursion limit for this stream. + /// + public int RecursionLimit { get { return state.recursionLimit; } } + + /// + /// Internal-only property; when set to true, unknown fields will be discarded while parsing. + /// + internal bool DiscardUnknownFields + { + get { return state.DiscardUnknownFields; } + set { state.DiscardUnknownFields = value; } + } + + /// + /// Internal-only property; provides extension identifiers to compatible messages while parsing. + /// + internal ExtensionRegistry ExtensionRegistry + { + get { return state.ExtensionRegistry; } + set { state.ExtensionRegistry = value; } + } + + internal byte[] InternalBuffer => buffer; + + internal Stream InternalInputStream => input; + + internal ref ParserInternalState InternalState => ref state; + + /// + /// Disposes of this instance, potentially closing any underlying stream. + /// + /// + /// As there is no flushing to perform here, disposing of a which + /// was constructed with the leaveOpen option parameter set to true (or one which + /// was constructed to read from a byte array) has no effect. + /// + public void Dispose() + { + if (!leaveOpen) + { + input.Dispose(); + } + } + + #region Validation + /// + /// Verifies that the last call to ReadTag() returned tag 0 - in other words, + /// we've reached the end of the stream when we expected to. + /// + /// The + /// tag read was not the one specified + internal void CheckReadEndOfStreamTag() + { + ParsingPrimitivesMessages.CheckReadEndOfStreamTag(ref state); + } + #endregion + + #region Reading of tags etc + + /// + /// Peeks at the next field tag. This is like calling , but the + /// tag is not consumed. (So a subsequent call to will return the + /// same value.) + /// + public uint PeekTag() + { + var span = new ReadOnlySpan(buffer); + return ParsingPrimitives.PeekTag(ref span, ref state); + } + + /// + /// Reads a field tag, returning the tag of 0 for "end of stream". + /// + /// + /// If this method returns 0, it doesn't necessarily mean the end of all + /// the data in this CodedInputStream; it may be the end of the logical stream + /// for an embedded message, for example. + /// + /// The next field tag, or 0 for end of stream. (0 is never a valid tag.) + public uint ReadTag() + { + var span = new ReadOnlySpan(buffer); + return ParsingPrimitives.ParseTag(ref span, ref state); + } + + /// + /// Skips the data for the field with the tag we've just read. + /// This should be called directly after , when + /// the caller wishes to skip an unknown field. + /// + /// + /// This method throws if the last-read tag was an end-group tag. + /// If a caller wishes to skip a group, they should skip the whole group, by calling this method after reading the + /// start-group tag. This behavior allows callers to call this method on any field they don't understand, correctly + /// resulting in an error if an end-group tag has not been paired with an earlier start-group tag. + /// + /// The last tag was an end-group tag + /// The last read operation read to the end of the logical stream + public void SkipLastField() + { + var span = new ReadOnlySpan(buffer); + ParsingPrimitivesMessages.SkipLastField(ref span, ref state); + } + + /// + /// Skip a group. + /// + internal void SkipGroup(uint startGroupTag) + { + var span = new ReadOnlySpan(buffer); + ParsingPrimitivesMessages.SkipGroup(ref span, ref state, startGroupTag); + } + + /// + /// Reads a double field from the stream. + /// + public double ReadDouble() + { + var span = new ReadOnlySpan(buffer); + return ParsingPrimitives.ParseDouble(ref span, ref state); + } + + /// + /// Reads a float field from the stream. + /// + public float ReadFloat() + { + var span = new ReadOnlySpan(buffer); + return ParsingPrimitives.ParseFloat(ref span, ref state); + } + + /// + /// Reads a uint64 field from the stream. + /// + public ulong ReadUInt64() + { + return ReadRawVarint64(); + } + + /// + /// Reads an int64 field from the stream. + /// + public long ReadInt64() + { + return (long) ReadRawVarint64(); + } + + /// + /// Reads an int32 field from the stream. + /// + public int ReadInt32() + { + return (int) ReadRawVarint32(); + } + + /// + /// Reads a fixed64 field from the stream. + /// + public ulong ReadFixed64() + { + return ReadRawLittleEndian64(); + } + + /// + /// Reads a fixed32 field from the stream. + /// + public uint ReadFixed32() + { + return ReadRawLittleEndian32(); + } + + /// + /// Reads a bool field from the stream. + /// + public bool ReadBool() + { + return ReadRawVarint64() != 0; + } + + /// + /// Reads a string field from the stream. + /// + public string ReadString() + { + var span = new ReadOnlySpan(buffer); + return ParsingPrimitives.ReadString(ref span, ref state); + } + + /// + /// Reads an embedded message field value from the stream. + /// + public void ReadMessage(IMessage builder) + { + // TODO(jtattermusch): if the message doesn't implement IBufferMessage (and thus does not provide the InternalMergeFrom method), + // what we're doing here works fine, but could be more efficient. + // What happends is that we first initialize a ParseContext from the current coded input stream only to parse the length of the message, at which point + // we will need to switch back again to CodedInputStream-based parsing (which involves copying and storing the state) to be able to + // invoke the legacy MergeFrom(CodedInputStream) method. + // For now, this inefficiency is fine, considering this is only a backward-compatibility scenario (and regenerating the code fixes it). + ParseContext.Initialize(buffer.AsSpan(), ref state, out ParseContext ctx); + try + { + ParsingPrimitivesMessages.ReadMessage(ref ctx, builder); + } + finally + { + ctx.CopyStateTo(this); + } + } + + /// + /// Reads an embedded group field from the stream. + /// + public void ReadGroup(IMessage builder) + { + ParseContext.Initialize(this, out ParseContext ctx); + try + { + ParsingPrimitivesMessages.ReadGroup(ref ctx, builder); + } + finally + { + ctx.CopyStateTo(this); + } + } + + /// + /// Reads a bytes field value from the stream. + /// + public ByteString ReadBytes() + { + var span = new ReadOnlySpan(buffer); + return ParsingPrimitives.ReadBytes(ref span, ref state); + } + + /// + /// Reads a uint32 field value from the stream. + /// + public uint ReadUInt32() + { + return ReadRawVarint32(); + } + + /// + /// Reads an enum field value from the stream. + /// + public int ReadEnum() + { + // Currently just a pass-through, but it's nice to separate it logically from WriteInt32. + return (int) ReadRawVarint32(); + } + + /// + /// Reads an sfixed32 field value from the stream. + /// + public int ReadSFixed32() + { + return (int) ReadRawLittleEndian32(); + } + + /// + /// Reads an sfixed64 field value from the stream. + /// + public long ReadSFixed64() + { + return (long) ReadRawLittleEndian64(); + } + + /// + /// Reads an sint32 field value from the stream. + /// + public int ReadSInt32() + { + return ParsingPrimitives.DecodeZigZag32(ReadRawVarint32()); + } + + /// + /// Reads an sint64 field value from the stream. + /// + public long ReadSInt64() + { + return ParsingPrimitives.DecodeZigZag64(ReadRawVarint64()); + } + + /// + /// Reads a length for length-delimited data. + /// + /// + /// This is internally just reading a varint, but this method exists + /// to make the calling code clearer. + /// + public int ReadLength() + { + var span = new ReadOnlySpan(buffer); + return ParsingPrimitives.ParseLength(ref span, ref state); + } + + /// + /// Peeks at the next tag in the stream. If it matches , + /// the tag is consumed and the method returns true; otherwise, the + /// stream is left in the original position and the method returns false. + /// + public bool MaybeConsumeTag(uint tag) + { + var span = new ReadOnlySpan(buffer); + return ParsingPrimitives.MaybeConsumeTag(ref span, ref state, tag); + } + +#endregion + + #region Underlying reading primitives + + /// + /// Reads a raw Varint from the stream. If larger than 32 bits, discard the upper bits. + /// This method is optimised for the case where we've got lots of data in the buffer. + /// That means we can check the size just once, then just read directly from the buffer + /// without constant rechecking of the buffer length. + /// + internal uint ReadRawVarint32() + { + var span = new ReadOnlySpan(buffer); + return ParsingPrimitives.ParseRawVarint32(ref span, ref state); + } + + /// + /// Reads a varint from the input one byte at a time, so that it does not + /// read any bytes after the end of the varint. If you simply wrapped the + /// stream in a CodedInputStream and used ReadRawVarint32(Stream) + /// then you would probably end up reading past the end of the varint since + /// CodedInputStream buffers its input. + /// + /// + /// + internal static uint ReadRawVarint32(Stream input) + { + return ParsingPrimitives.ReadRawVarint32(input); + } + + /// + /// Reads a raw varint from the stream. + /// + internal ulong ReadRawVarint64() + { + var span = new ReadOnlySpan(buffer); + return ParsingPrimitives.ParseRawVarint64(ref span, ref state); + } + + /// + /// Reads a 32-bit little-endian integer from the stream. + /// + internal uint ReadRawLittleEndian32() + { + var span = new ReadOnlySpan(buffer); + return ParsingPrimitives.ParseRawLittleEndian32(ref span, ref state); + } + + /// + /// Reads a 64-bit little-endian integer from the stream. + /// + internal ulong ReadRawLittleEndian64() + { + var span = new ReadOnlySpan(buffer); + return ParsingPrimitives.ParseRawLittleEndian64(ref span, ref state); + } + #endregion + + #region Internal reading and buffer management + + /// + /// Sets currentLimit to (current position) + byteLimit. This is called + /// when descending into a length-delimited embedded message. The previous + /// limit is returned. + /// + /// The old limit. + internal int PushLimit(int byteLimit) + { + return SegmentedBufferHelper.PushLimit(ref state, byteLimit); + } + + /// + /// Discards the current limit, returning the previous limit. + /// + internal void PopLimit(int oldLimit) + { + SegmentedBufferHelper.PopLimit(ref state, oldLimit); + } + + /// + /// Returns whether or not all the data before the limit has been read. + /// + /// + internal bool ReachedLimit + { + get + { + return SegmentedBufferHelper.IsReachedLimit(ref state); + } + } + + /// + /// Returns true if the stream has reached the end of the input. This is the + /// case if either the end of the underlying input source has been reached or + /// the stream has reached a limit created using PushLimit. + /// + public bool IsAtEnd + { + get + { + var span = new ReadOnlySpan(buffer); + return SegmentedBufferHelper.IsAtEnd(ref span, ref state); + } + } + + /// + /// Called when buffer is empty to read more bytes from the + /// input. If is true, RefillBuffer() guarantees that + /// either there will be at least one byte in the buffer when it returns + /// or it will throw an exception. If is false, + /// RefillBuffer() returns false if no more bytes were available. + /// + /// + /// + private bool RefillBuffer(bool mustSucceed) + { + var span = new ReadOnlySpan(buffer); + return state.segmentedBufferHelper.RefillBuffer(ref span, ref state, mustSucceed); + } + + /// + /// Reads a fixed size of bytes from the input. + /// + /// + /// the end of the stream or the current limit was reached + /// + internal byte[] ReadRawBytes(int size) + { + var span = new ReadOnlySpan(buffer); + return ParsingPrimitives.ReadRawBytes(ref span, ref state, size); + } + + /// + /// Reads a top-level message or a nested message after the limits for this message have been pushed. + /// (parser will proceed until the end of the current limit) + /// NOTE: this method needs to be public because it's invoked by the generated code - e.g. msg.MergeFrom(CodedInputStream input) method + /// + public void ReadRawMessage(IMessage message) + { + ParseContext.Initialize(this, out ParseContext ctx); + try + { + ParsingPrimitivesMessages.ReadRawMessage(ref ctx, message); + } + finally + { + ctx.CopyStateTo(this); + } + } +#endregion + } +} diff --git a/csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs b/csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs index cb923549d42e..6f18afbb242a 100644 --- a/csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs +++ b/csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs @@ -1,308 +1,308 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; - -namespace Google.Protobuf -{ - // This part of CodedOutputStream provides all the static entry points that are used - // by generated code and internally to compute the size of messages prior to being - // written to an instance of CodedOutputStream. - public sealed partial class CodedOutputStream - { - private const int LittleEndian64Size = 8; - private const int LittleEndian32Size = 4; - - internal const int DoubleSize = LittleEndian64Size; - internal const int FloatSize = LittleEndian32Size; - internal const int BoolSize = 1; - - /// - /// Computes the number of bytes that would be needed to encode a - /// double field, including the tag. - /// - public static int ComputeDoubleSize(double value) - { - return DoubleSize; - } - - /// - /// Computes the number of bytes that would be needed to encode a - /// float field, including the tag. - /// - public static int ComputeFloatSize(float value) - { - return FloatSize; - } - - /// - /// Computes the number of bytes that would be needed to encode a - /// uint64 field, including the tag. - /// - public static int ComputeUInt64Size(ulong value) - { - return ComputeRawVarint64Size(value); - } - - /// - /// Computes the number of bytes that would be needed to encode an - /// int64 field, including the tag. - /// - public static int ComputeInt64Size(long value) - { - return ComputeRawVarint64Size((ulong) value); - } - - /// - /// Computes the number of bytes that would be needed to encode an - /// int32 field, including the tag. - /// - public static int ComputeInt32Size(int value) - { - if (value >= 0) - { - return ComputeRawVarint32Size((uint) value); - } - else - { - // Must sign-extend. - return 10; - } - } - - /// - /// Computes the number of bytes that would be needed to encode a - /// fixed64 field, including the tag. - /// - public static int ComputeFixed64Size(ulong value) - { - return LittleEndian64Size; - } - - /// - /// Computes the number of bytes that would be needed to encode a - /// fixed32 field, including the tag. - /// - public static int ComputeFixed32Size(uint value) - { - return LittleEndian32Size; - } - - /// - /// Computes the number of bytes that would be needed to encode a - /// bool field, including the tag. - /// - public static int ComputeBoolSize(bool value) - { - return BoolSize; - } - - /// - /// Computes the number of bytes that would be needed to encode a - /// string field, including the tag. - /// - public static int ComputeStringSize(String value) - { - int byteArraySize = WritingPrimitives.Utf8Encoding.GetByteCount(value); - return ComputeLengthSize(byteArraySize) + byteArraySize; - } - - /// - /// Computes the number of bytes that would be needed to encode a - /// group field, including the tag. - /// - public static int ComputeGroupSize(IMessage value) - { - return value.CalculateSize(); - } - - /// - /// Computes the number of bytes that would be needed to encode an - /// embedded message field, including the tag. - /// - public static int ComputeMessageSize(IMessage value) - { - int size = value.CalculateSize(); - return ComputeLengthSize(size) + size; - } - - /// - /// Computes the number of bytes that would be needed to encode a - /// bytes field, including the tag. - /// - public static int ComputeBytesSize(ByteString value) - { - return ComputeLengthSize(value.Length) + value.Length; - } - - /// - /// Computes the number of bytes that would be needed to encode a - /// uint32 field, including the tag. - /// - public static int ComputeUInt32Size(uint value) - { - return ComputeRawVarint32Size(value); - } - - /// - /// Computes the number of bytes that would be needed to encode a - /// enum field, including the tag. The caller is responsible for - /// converting the enum value to its numeric value. - /// - public static int ComputeEnumSize(int value) - { - // Currently just a pass-through, but it's nice to separate it logically. - return ComputeInt32Size(value); - } - - /// - /// Computes the number of bytes that would be needed to encode an - /// sfixed32 field, including the tag. - /// - public static int ComputeSFixed32Size(int value) - { - return LittleEndian32Size; - } - - /// - /// Computes the number of bytes that would be needed to encode an - /// sfixed64 field, including the tag. - /// - public static int ComputeSFixed64Size(long value) - { - return LittleEndian64Size; - } - - /// - /// Computes the number of bytes that would be needed to encode an - /// sint32 field, including the tag. - /// - public static int ComputeSInt32Size(int value) - { - return ComputeRawVarint32Size(WritingPrimitives.EncodeZigZag32(value)); - } - - /// - /// Computes the number of bytes that would be needed to encode an - /// sint64 field, including the tag. - /// - public static int ComputeSInt64Size(long value) - { - return ComputeRawVarint64Size(WritingPrimitives.EncodeZigZag64(value)); - } - - /// - /// Computes the number of bytes that would be needed to encode a length, - /// as written by . - /// - public static int ComputeLengthSize(int length) - { - return ComputeRawVarint32Size((uint) length); - } - - /// - /// Computes the number of bytes that would be needed to encode a varint. - /// - public static int ComputeRawVarint32Size(uint value) - { - if ((value & (0xffffffff << 7)) == 0) - { - return 1; - } - if ((value & (0xffffffff << 14)) == 0) - { - return 2; - } - if ((value & (0xffffffff << 21)) == 0) - { - return 3; - } - if ((value & (0xffffffff << 28)) == 0) - { - return 4; - } - return 5; - } - - /// - /// Computes the number of bytes that would be needed to encode a varint. - /// - public static int ComputeRawVarint64Size(ulong value) - { - if ((value & (0xffffffffffffffffL << 7)) == 0) - { - return 1; - } - if ((value & (0xffffffffffffffffL << 14)) == 0) - { - return 2; - } - if ((value & (0xffffffffffffffffL << 21)) == 0) - { - return 3; - } - if ((value & (0xffffffffffffffffL << 28)) == 0) - { - return 4; - } - if ((value & (0xffffffffffffffffL << 35)) == 0) - { - return 5; - } - if ((value & (0xffffffffffffffffL << 42)) == 0) - { - return 6; - } - if ((value & (0xffffffffffffffffL << 49)) == 0) - { - return 7; - } - if ((value & (0xffffffffffffffffL << 56)) == 0) - { - return 8; - } - if ((value & (0xffffffffffffffffL << 63)) == 0) - { - return 9; - } - return 10; - } - - /// - /// Computes the number of bytes that would be needed to encode a tag. - /// - public static int ComputeTagSize(int fieldNumber) - { - return ComputeRawVarint32Size(WireFormat.MakeTag(fieldNumber, 0)); - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; + +namespace Google.Protobuf +{ + // This part of CodedOutputStream provides all the static entry points that are used + // by generated code and internally to compute the size of messages prior to being + // written to an instance of CodedOutputStream. + public sealed partial class CodedOutputStream + { + private const int LittleEndian64Size = 8; + private const int LittleEndian32Size = 4; + + internal const int DoubleSize = LittleEndian64Size; + internal const int FloatSize = LittleEndian32Size; + internal const int BoolSize = 1; + + /// + /// Computes the number of bytes that would be needed to encode a + /// double field, including the tag. + /// + public static int ComputeDoubleSize(double value) + { + return DoubleSize; + } + + /// + /// Computes the number of bytes that would be needed to encode a + /// float field, including the tag. + /// + public static int ComputeFloatSize(float value) + { + return FloatSize; + } + + /// + /// Computes the number of bytes that would be needed to encode a + /// uint64 field, including the tag. + /// + public static int ComputeUInt64Size(ulong value) + { + return ComputeRawVarint64Size(value); + } + + /// + /// Computes the number of bytes that would be needed to encode an + /// int64 field, including the tag. + /// + public static int ComputeInt64Size(long value) + { + return ComputeRawVarint64Size((ulong) value); + } + + /// + /// Computes the number of bytes that would be needed to encode an + /// int32 field, including the tag. + /// + public static int ComputeInt32Size(int value) + { + if (value >= 0) + { + return ComputeRawVarint32Size((uint) value); + } + else + { + // Must sign-extend. + return 10; + } + } + + /// + /// Computes the number of bytes that would be needed to encode a + /// fixed64 field, including the tag. + /// + public static int ComputeFixed64Size(ulong value) + { + return LittleEndian64Size; + } + + /// + /// Computes the number of bytes that would be needed to encode a + /// fixed32 field, including the tag. + /// + public static int ComputeFixed32Size(uint value) + { + return LittleEndian32Size; + } + + /// + /// Computes the number of bytes that would be needed to encode a + /// bool field, including the tag. + /// + public static int ComputeBoolSize(bool value) + { + return BoolSize; + } + + /// + /// Computes the number of bytes that would be needed to encode a + /// string field, including the tag. + /// + public static int ComputeStringSize(String value) + { + int byteArraySize = WritingPrimitives.Utf8Encoding.GetByteCount(value); + return ComputeLengthSize(byteArraySize) + byteArraySize; + } + + /// + /// Computes the number of bytes that would be needed to encode a + /// group field, including the tag. + /// + public static int ComputeGroupSize(IMessage value) + { + return value.CalculateSize(); + } + + /// + /// Computes the number of bytes that would be needed to encode an + /// embedded message field, including the tag. + /// + public static int ComputeMessageSize(IMessage value) + { + int size = value.CalculateSize(); + return ComputeLengthSize(size) + size; + } + + /// + /// Computes the number of bytes that would be needed to encode a + /// bytes field, including the tag. + /// + public static int ComputeBytesSize(ByteString value) + { + return ComputeLengthSize(value.Length) + value.Length; + } + + /// + /// Computes the number of bytes that would be needed to encode a + /// uint32 field, including the tag. + /// + public static int ComputeUInt32Size(uint value) + { + return ComputeRawVarint32Size(value); + } + + /// + /// Computes the number of bytes that would be needed to encode a + /// enum field, including the tag. The caller is responsible for + /// converting the enum value to its numeric value. + /// + public static int ComputeEnumSize(int value) + { + // Currently just a pass-through, but it's nice to separate it logically. + return ComputeInt32Size(value); + } + + /// + /// Computes the number of bytes that would be needed to encode an + /// sfixed32 field, including the tag. + /// + public static int ComputeSFixed32Size(int value) + { + return LittleEndian32Size; + } + + /// + /// Computes the number of bytes that would be needed to encode an + /// sfixed64 field, including the tag. + /// + public static int ComputeSFixed64Size(long value) + { + return LittleEndian64Size; + } + + /// + /// Computes the number of bytes that would be needed to encode an + /// sint32 field, including the tag. + /// + public static int ComputeSInt32Size(int value) + { + return ComputeRawVarint32Size(WritingPrimitives.EncodeZigZag32(value)); + } + + /// + /// Computes the number of bytes that would be needed to encode an + /// sint64 field, including the tag. + /// + public static int ComputeSInt64Size(long value) + { + return ComputeRawVarint64Size(WritingPrimitives.EncodeZigZag64(value)); + } + + /// + /// Computes the number of bytes that would be needed to encode a length, + /// as written by . + /// + public static int ComputeLengthSize(int length) + { + return ComputeRawVarint32Size((uint) length); + } + + /// + /// Computes the number of bytes that would be needed to encode a varint. + /// + public static int ComputeRawVarint32Size(uint value) + { + if ((value & (0xffffffff << 7)) == 0) + { + return 1; + } + if ((value & (0xffffffff << 14)) == 0) + { + return 2; + } + if ((value & (0xffffffff << 21)) == 0) + { + return 3; + } + if ((value & (0xffffffff << 28)) == 0) + { + return 4; + } + return 5; + } + + /// + /// Computes the number of bytes that would be needed to encode a varint. + /// + public static int ComputeRawVarint64Size(ulong value) + { + if ((value & (0xffffffffffffffffL << 7)) == 0) + { + return 1; + } + if ((value & (0xffffffffffffffffL << 14)) == 0) + { + return 2; + } + if ((value & (0xffffffffffffffffL << 21)) == 0) + { + return 3; + } + if ((value & (0xffffffffffffffffL << 28)) == 0) + { + return 4; + } + if ((value & (0xffffffffffffffffL << 35)) == 0) + { + return 5; + } + if ((value & (0xffffffffffffffffL << 42)) == 0) + { + return 6; + } + if ((value & (0xffffffffffffffffL << 49)) == 0) + { + return 7; + } + if ((value & (0xffffffffffffffffL << 56)) == 0) + { + return 8; + } + if ((value & (0xffffffffffffffffL << 63)) == 0) + { + return 9; + } + return 10; + } + + /// + /// Computes the number of bytes that would be needed to encode a tag. + /// + public static int ComputeTagSize(int fieldNumber) + { + return ComputeRawVarint32Size(WireFormat.MakeTag(fieldNumber, 0)); + } + } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf/CodedOutputStream.cs b/csharp/src/Google.Protobuf/CodedOutputStream.cs index 20d88ea7dc9b..5b8cca1d0260 100644 --- a/csharp/src/Google.Protobuf/CodedOutputStream.cs +++ b/csharp/src/Google.Protobuf/CodedOutputStream.cs @@ -1,607 +1,607 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using Google.Protobuf.Collections; -using System; -using System.IO; -using System.Security; -using System.Text; - -namespace Google.Protobuf -{ - /// - /// Encodes and writes protocol message fields. - /// - /// - /// - /// This class is generally used by generated code to write appropriate - /// primitives to the stream. It effectively encapsulates the lowest - /// levels of protocol buffer format. Unlike some other implementations, - /// this does not include combined "write tag and value" methods. Generated - /// code knows the exact byte representations of the tags they're going to write, - /// so there's no need to re-encode them each time. Manually-written code calling - /// this class should just call one of the WriteTag overloads before each value. - /// - /// - /// Repeated fields and map fields are not handled by this class; use RepeatedField<T> - /// and MapField<TKey, TValue> to serialize such fields. - /// - /// - [SecuritySafeCritical] - public sealed partial class CodedOutputStream : IDisposable - { - /// - /// The buffer size used by CreateInstance(Stream). - /// - public static readonly int DefaultBufferSize = 4096; - - private readonly bool leaveOpen; - private readonly byte[] buffer; - private WriterInternalState state; - - private readonly Stream output; - - #region Construction - /// - /// Creates a new CodedOutputStream that writes directly to the given - /// byte array. If more bytes are written than fit in the array, - /// OutOfSpaceException will be thrown. - /// - public CodedOutputStream(byte[] flatArray) : this(flatArray, 0, flatArray.Length) - { - } - - /// - /// Creates a new CodedOutputStream that writes directly to the given - /// byte array slice. If more bytes are written than fit in the array, - /// OutOfSpaceException will be thrown. - /// - private CodedOutputStream(byte[] buffer, int offset, int length) - { - this.output = null; - this.buffer = ProtoPreconditions.CheckNotNull(buffer, nameof(buffer)); - this.state.position = offset; - this.state.limit = offset + length; - WriteBufferHelper.Initialize(this, out this.state.writeBufferHelper); - leaveOpen = true; // Simple way of avoiding trying to dispose of a null reference - } - - private CodedOutputStream(Stream output, byte[] buffer, bool leaveOpen) - { - this.output = ProtoPreconditions.CheckNotNull(output, nameof(output)); - this.buffer = buffer; - this.state.position = 0; - this.state.limit = buffer.Length; - WriteBufferHelper.Initialize(this, out this.state.writeBufferHelper); - this.leaveOpen = leaveOpen; - } - - /// - /// Creates a new which write to the given stream, and disposes of that - /// stream when the returned CodedOutputStream is disposed. - /// - /// The stream to write to. It will be disposed when the returned CodedOutputStream is disposed. - public CodedOutputStream(Stream output) : this(output, DefaultBufferSize, false) - { - } - - /// - /// Creates a new CodedOutputStream which write to the given stream and uses - /// the specified buffer size. - /// - /// The stream to write to. It will be disposed when the returned CodedOutputStream is disposed. - /// The size of buffer to use internally. - public CodedOutputStream(Stream output, int bufferSize) : this(output, new byte[bufferSize], false) - { - } - - /// - /// Creates a new CodedOutputStream which write to the given stream. - /// - /// The stream to write to. - /// If true, is left open when the returned CodedOutputStream is disposed; - /// if false, the provided stream is disposed as well. - public CodedOutputStream(Stream output, bool leaveOpen) : this(output, DefaultBufferSize, leaveOpen) - { - } - - /// - /// Creates a new CodedOutputStream which write to the given stream and uses - /// the specified buffer size. - /// - /// The stream to write to. - /// The size of buffer to use internally. - /// If true, is left open when the returned CodedOutputStream is disposed; - /// if false, the provided stream is disposed as well. - public CodedOutputStream(Stream output, int bufferSize, bool leaveOpen) : this(output, new byte[bufferSize], leaveOpen) - { - } - #endregion - - /// - /// Returns the current position in the stream, or the position in the output buffer - /// - public long Position - { - get - { - if (output != null) - { - return output.Position + state.position; - } - return state.position; - } - } - - #region Writing of values (not including tags) - - /// - /// Writes a double field value, without a tag, to the stream. - /// - /// The value to write - public void WriteDouble(double value) - { - var span = new Span(buffer); - WritingPrimitives.WriteDouble(ref span, ref state, value); - } - - /// - /// Writes a float field value, without a tag, to the stream. - /// - /// The value to write - public void WriteFloat(float value) - { - var span = new Span(buffer); - WritingPrimitives.WriteFloat(ref span, ref state, value); - } - - /// - /// Writes a uint64 field value, without a tag, to the stream. - /// - /// The value to write - public void WriteUInt64(ulong value) - { - var span = new Span(buffer); - WritingPrimitives.WriteUInt64(ref span, ref state, value); - } - - /// - /// Writes an int64 field value, without a tag, to the stream. - /// - /// The value to write - public void WriteInt64(long value) - { - var span = new Span(buffer); - WritingPrimitives.WriteInt64(ref span, ref state, value); - } - - /// - /// Writes an int32 field value, without a tag, to the stream. - /// - /// The value to write - public void WriteInt32(int value) - { - var span = new Span(buffer); - WritingPrimitives.WriteInt32(ref span, ref state, value); - } - - /// - /// Writes a fixed64 field value, without a tag, to the stream. - /// - /// The value to write - public void WriteFixed64(ulong value) - { - var span = new Span(buffer); - WritingPrimitives.WriteFixed64(ref span, ref state, value); - } - - /// - /// Writes a fixed32 field value, without a tag, to the stream. - /// - /// The value to write - public void WriteFixed32(uint value) - { - var span = new Span(buffer); - WritingPrimitives.WriteFixed32(ref span, ref state, value); - } - - /// - /// Writes a bool field value, without a tag, to the stream. - /// - /// The value to write - public void WriteBool(bool value) - { - var span = new Span(buffer); - WritingPrimitives.WriteBool(ref span, ref state, value); - } - - /// - /// Writes a string field value, without a tag, to the stream. - /// The data is length-prefixed. - /// - /// The value to write - public void WriteString(string value) - { - var span = new Span(buffer); - WritingPrimitives.WriteString(ref span, ref state, value); - } - - /// - /// Writes a message, without a tag, to the stream. - /// The data is length-prefixed. - /// - /// The value to write - public void WriteMessage(IMessage value) - { - // TODO(jtattermusch): if the message doesn't implement IBufferMessage (and thus does not provide the InternalWriteTo method), - // what we're doing here works fine, but could be more efficient. - // For now, this inefficiency is fine, considering this is only a backward-compatibility scenario (and regenerating the code fixes it). - var span = new Span(buffer); - WriteContext.Initialize(ref span, ref state, out WriteContext ctx); - try - { - WritingPrimitivesMessages.WriteMessage(ref ctx, value); - } - finally - { - ctx.CopyStateTo(this); - } - } - - /// - /// Writes a message, without a tag, to the stream. - /// Only the message data is written, without a length-delimiter. - /// - /// The value to write - public void WriteRawMessage(IMessage value) - { - // TODO(jtattermusch): if the message doesn't implement IBufferMessage (and thus does not provide the InternalWriteTo method), - // what we're doing here works fine, but could be more efficient. - // For now, this inefficiency is fine, considering this is only a backward-compatibility scenario (and regenerating the code fixes it). - var span = new Span(buffer); - WriteContext.Initialize(ref span, ref state, out WriteContext ctx); - try - { - WritingPrimitivesMessages.WriteRawMessage(ref ctx, value); - } - finally - { - ctx.CopyStateTo(this); - } - } - - /// - /// Writes a group, without a tag, to the stream. - /// - /// The value to write - public void WriteGroup(IMessage value) - { - var span = new Span(buffer); - WriteContext.Initialize(ref span, ref state, out WriteContext ctx); - try - { - WritingPrimitivesMessages.WriteGroup(ref ctx, value); - } - finally - { - ctx.CopyStateTo(this); - } - } - - /// - /// Write a byte string, without a tag, to the stream. - /// The data is length-prefixed. - /// - /// The value to write - public void WriteBytes(ByteString value) - { - var span = new Span(buffer); - WritingPrimitives.WriteBytes(ref span, ref state, value); - } - - /// - /// Writes a uint32 value, without a tag, to the stream. - /// - /// The value to write - public void WriteUInt32(uint value) - { - var span = new Span(buffer); - WritingPrimitives.WriteUInt32(ref span, ref state, value); - } - - /// - /// Writes an enum value, without a tag, to the stream. - /// - /// The value to write - public void WriteEnum(int value) - { - var span = new Span(buffer); - WritingPrimitives.WriteEnum(ref span, ref state, value); - } - - /// - /// Writes an sfixed32 value, without a tag, to the stream. - /// - /// The value to write. - public void WriteSFixed32(int value) - { - var span = new Span(buffer); - WritingPrimitives.WriteSFixed32(ref span, ref state, value); - } - - /// - /// Writes an sfixed64 value, without a tag, to the stream. - /// - /// The value to write - public void WriteSFixed64(long value) - { - var span = new Span(buffer); - WritingPrimitives.WriteSFixed64(ref span, ref state, value); - } - - /// - /// Writes an sint32 value, without a tag, to the stream. - /// - /// The value to write - public void WriteSInt32(int value) - { - var span = new Span(buffer); - WritingPrimitives.WriteSInt32(ref span, ref state, value); - } - - /// - /// Writes an sint64 value, without a tag, to the stream. - /// - /// The value to write - public void WriteSInt64(long value) - { - var span = new Span(buffer); - WritingPrimitives.WriteSInt64(ref span, ref state, value); - } - - /// - /// Writes a length (in bytes) for length-delimited data. - /// - /// - /// This method simply writes a rawint, but exists for clarity in calling code. - /// - /// Length value, in bytes. - public void WriteLength(int length) - { - var span = new Span(buffer); - WritingPrimitives.WriteLength(ref span, ref state, length); - } - - #endregion - - #region Raw tag writing - /// - /// Encodes and writes a tag. - /// - /// The number of the field to write the tag for - /// The wire format type of the tag to write - public void WriteTag(int fieldNumber, WireFormat.WireType type) - { - var span = new Span(buffer); - WritingPrimitives.WriteTag(ref span, ref state, fieldNumber, type); - } - - /// - /// Writes an already-encoded tag. - /// - /// The encoded tag - public void WriteTag(uint tag) - { - var span = new Span(buffer); - WritingPrimitives.WriteTag(ref span, ref state, tag); - } - - /// - /// Writes the given single-byte tag directly to the stream. - /// - /// The encoded tag - public void WriteRawTag(byte b1) - { - var span = new Span(buffer); - WritingPrimitives.WriteRawTag(ref span, ref state, b1); - } - - /// - /// Writes the given two-byte tag directly to the stream. - /// - /// The first byte of the encoded tag - /// The second byte of the encoded tag - public void WriteRawTag(byte b1, byte b2) - { - var span = new Span(buffer); - WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2); - } - - /// - /// Writes the given three-byte tag directly to the stream. - /// - /// The first byte of the encoded tag - /// The second byte of the encoded tag - /// The third byte of the encoded tag - public void WriteRawTag(byte b1, byte b2, byte b3) - { - var span = new Span(buffer); - WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3); - } - - /// - /// Writes the given four-byte tag directly to the stream. - /// - /// The first byte of the encoded tag - /// The second byte of the encoded tag - /// The third byte of the encoded tag - /// The fourth byte of the encoded tag - public void WriteRawTag(byte b1, byte b2, byte b3, byte b4) - { - var span = new Span(buffer); - WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3, b4); - } - - /// - /// Writes the given five-byte tag directly to the stream. - /// - /// The first byte of the encoded tag - /// The second byte of the encoded tag - /// The third byte of the encoded tag - /// The fourth byte of the encoded tag - /// The fifth byte of the encoded tag - public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5) - { - var span = new Span(buffer); - WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3, b4, b5); - } - #endregion - - #region Underlying writing primitives - - /// - /// Writes a 32 bit value as a varint. The fast route is taken when - /// there's enough buffer space left to whizz through without checking - /// for each byte; otherwise, we resort to calling WriteRawByte each time. - /// - internal void WriteRawVarint32(uint value) - { - var span = new Span(buffer); - WritingPrimitives.WriteRawVarint32(ref span, ref state, value); - } - - internal void WriteRawVarint64(ulong value) - { - var span = new Span(buffer); - WritingPrimitives.WriteRawVarint64(ref span, ref state, value); - } - - internal void WriteRawLittleEndian32(uint value) - { - var span = new Span(buffer); - WritingPrimitives.WriteRawLittleEndian32(ref span, ref state, value); - } - - internal void WriteRawLittleEndian64(ulong value) - { - var span = new Span(buffer); - WritingPrimitives.WriteRawLittleEndian64(ref span, ref state, value); - } - - /// - /// Writes out an array of bytes. - /// - internal void WriteRawBytes(byte[] value) - { - WriteRawBytes(value, 0, value.Length); - } - - /// - /// Writes out part of an array of bytes. - /// - internal void WriteRawBytes(byte[] value, int offset, int length) - { - var span = new Span(buffer); - WritingPrimitives.WriteRawBytes(ref span, ref state, value, offset, length); - } - - #endregion - - /// - /// Indicates that a CodedOutputStream wrapping a flat byte array - /// ran out of space. - /// - public sealed class OutOfSpaceException : IOException - { - internal OutOfSpaceException() - : base("CodedOutputStream was writing to a flat byte array and ran out of space.") - { - } - } - - /// - /// Flushes any buffered data and optionally closes the underlying stream, if any. - /// - /// - /// - /// By default, any underlying stream is closed by this method. To configure this behaviour, - /// use a constructor overload with a leaveOpen parameter. If this instance does not - /// have an underlying stream, this method does nothing. - /// - /// - /// For the sake of efficiency, calling this method does not prevent future write calls - but - /// if a later write ends up writing to a stream which has been disposed, that is likely to - /// fail. It is recommend that you not call any other methods after this. - /// - /// - public void Dispose() - { - Flush(); - if (!leaveOpen) - { - output.Dispose(); - } - } - - /// - /// Flushes any buffered data to the underlying stream (if there is one). - /// - public void Flush() - { - var span = new Span(buffer); - WriteBufferHelper.Flush(ref span, ref state); - } - - /// - /// Verifies that SpaceLeft returns zero. It's common to create a byte array - /// that is exactly big enough to hold a message, then write to it with - /// a CodedOutputStream. Calling CheckNoSpaceLeft after writing verifies that - /// the message was actually as big as expected, which can help finding bugs. - /// - public void CheckNoSpaceLeft() - { - WriteBufferHelper.CheckNoSpaceLeft(ref state); - } - - /// - /// If writing to a flat array, returns the space left in the array. Otherwise, - /// throws an InvalidOperationException. - /// - public int SpaceLeft => WriteBufferHelper.GetSpaceLeft(ref state); - - internal byte[] InternalBuffer => buffer; - - internal Stream InternalOutputStream => output; - - internal ref WriterInternalState InternalState => ref state; - } -} +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using Google.Protobuf.Collections; +using System; +using System.IO; +using System.Security; +using System.Text; + +namespace Google.Protobuf +{ + /// + /// Encodes and writes protocol message fields. + /// + /// + /// + /// This class is generally used by generated code to write appropriate + /// primitives to the stream. It effectively encapsulates the lowest + /// levels of protocol buffer format. Unlike some other implementations, + /// this does not include combined "write tag and value" methods. Generated + /// code knows the exact byte representations of the tags they're going to write, + /// so there's no need to re-encode them each time. Manually-written code calling + /// this class should just call one of the WriteTag overloads before each value. + /// + /// + /// Repeated fields and map fields are not handled by this class; use RepeatedField<T> + /// and MapField<TKey, TValue> to serialize such fields. + /// + /// + [SecuritySafeCritical] + public sealed partial class CodedOutputStream : IDisposable + { + /// + /// The buffer size used by CreateInstance(Stream). + /// + public static readonly int DefaultBufferSize = 4096; + + private readonly bool leaveOpen; + private readonly byte[] buffer; + private WriterInternalState state; + + private readonly Stream output; + + #region Construction + /// + /// Creates a new CodedOutputStream that writes directly to the given + /// byte array. If more bytes are written than fit in the array, + /// OutOfSpaceException will be thrown. + /// + public CodedOutputStream(byte[] flatArray) : this(flatArray, 0, flatArray.Length) + { + } + + /// + /// Creates a new CodedOutputStream that writes directly to the given + /// byte array slice. If more bytes are written than fit in the array, + /// OutOfSpaceException will be thrown. + /// + private CodedOutputStream(byte[] buffer, int offset, int length) + { + this.output = null; + this.buffer = ProtoPreconditions.CheckNotNull(buffer, nameof(buffer)); + this.state.position = offset; + this.state.limit = offset + length; + WriteBufferHelper.Initialize(this, out this.state.writeBufferHelper); + leaveOpen = true; // Simple way of avoiding trying to dispose of a null reference + } + + private CodedOutputStream(Stream output, byte[] buffer, bool leaveOpen) + { + this.output = ProtoPreconditions.CheckNotNull(output, nameof(output)); + this.buffer = buffer; + this.state.position = 0; + this.state.limit = buffer.Length; + WriteBufferHelper.Initialize(this, out this.state.writeBufferHelper); + this.leaveOpen = leaveOpen; + } + + /// + /// Creates a new which write to the given stream, and disposes of that + /// stream when the returned CodedOutputStream is disposed. + /// + /// The stream to write to. It will be disposed when the returned CodedOutputStream is disposed. + public CodedOutputStream(Stream output) : this(output, DefaultBufferSize, false) + { + } + + /// + /// Creates a new CodedOutputStream which write to the given stream and uses + /// the specified buffer size. + /// + /// The stream to write to. It will be disposed when the returned CodedOutputStream is disposed. + /// The size of buffer to use internally. + public CodedOutputStream(Stream output, int bufferSize) : this(output, new byte[bufferSize], false) + { + } + + /// + /// Creates a new CodedOutputStream which write to the given stream. + /// + /// The stream to write to. + /// If true, is left open when the returned CodedOutputStream is disposed; + /// if false, the provided stream is disposed as well. + public CodedOutputStream(Stream output, bool leaveOpen) : this(output, DefaultBufferSize, leaveOpen) + { + } + + /// + /// Creates a new CodedOutputStream which write to the given stream and uses + /// the specified buffer size. + /// + /// The stream to write to. + /// The size of buffer to use internally. + /// If true, is left open when the returned CodedOutputStream is disposed; + /// if false, the provided stream is disposed as well. + public CodedOutputStream(Stream output, int bufferSize, bool leaveOpen) : this(output, new byte[bufferSize], leaveOpen) + { + } + #endregion + + /// + /// Returns the current position in the stream, or the position in the output buffer + /// + public long Position + { + get + { + if (output != null) + { + return output.Position + state.position; + } + return state.position; + } + } + + #region Writing of values (not including tags) + + /// + /// Writes a double field value, without a tag, to the stream. + /// + /// The value to write + public void WriteDouble(double value) + { + var span = new Span(buffer); + WritingPrimitives.WriteDouble(ref span, ref state, value); + } + + /// + /// Writes a float field value, without a tag, to the stream. + /// + /// The value to write + public void WriteFloat(float value) + { + var span = new Span(buffer); + WritingPrimitives.WriteFloat(ref span, ref state, value); + } + + /// + /// Writes a uint64 field value, without a tag, to the stream. + /// + /// The value to write + public void WriteUInt64(ulong value) + { + var span = new Span(buffer); + WritingPrimitives.WriteUInt64(ref span, ref state, value); + } + + /// + /// Writes an int64 field value, without a tag, to the stream. + /// + /// The value to write + public void WriteInt64(long value) + { + var span = new Span(buffer); + WritingPrimitives.WriteInt64(ref span, ref state, value); + } + + /// + /// Writes an int32 field value, without a tag, to the stream. + /// + /// The value to write + public void WriteInt32(int value) + { + var span = new Span(buffer); + WritingPrimitives.WriteInt32(ref span, ref state, value); + } + + /// + /// Writes a fixed64 field value, without a tag, to the stream. + /// + /// The value to write + public void WriteFixed64(ulong value) + { + var span = new Span(buffer); + WritingPrimitives.WriteFixed64(ref span, ref state, value); + } + + /// + /// Writes a fixed32 field value, without a tag, to the stream. + /// + /// The value to write + public void WriteFixed32(uint value) + { + var span = new Span(buffer); + WritingPrimitives.WriteFixed32(ref span, ref state, value); + } + + /// + /// Writes a bool field value, without a tag, to the stream. + /// + /// The value to write + public void WriteBool(bool value) + { + var span = new Span(buffer); + WritingPrimitives.WriteBool(ref span, ref state, value); + } + + /// + /// Writes a string field value, without a tag, to the stream. + /// The data is length-prefixed. + /// + /// The value to write + public void WriteString(string value) + { + var span = new Span(buffer); + WritingPrimitives.WriteString(ref span, ref state, value); + } + + /// + /// Writes a message, without a tag, to the stream. + /// The data is length-prefixed. + /// + /// The value to write + public void WriteMessage(IMessage value) + { + // TODO(jtattermusch): if the message doesn't implement IBufferMessage (and thus does not provide the InternalWriteTo method), + // what we're doing here works fine, but could be more efficient. + // For now, this inefficiency is fine, considering this is only a backward-compatibility scenario (and regenerating the code fixes it). + var span = new Span(buffer); + WriteContext.Initialize(ref span, ref state, out WriteContext ctx); + try + { + WritingPrimitivesMessages.WriteMessage(ref ctx, value); + } + finally + { + ctx.CopyStateTo(this); + } + } + + /// + /// Writes a message, without a tag, to the stream. + /// Only the message data is written, without a length-delimiter. + /// + /// The value to write + public void WriteRawMessage(IMessage value) + { + // TODO(jtattermusch): if the message doesn't implement IBufferMessage (and thus does not provide the InternalWriteTo method), + // what we're doing here works fine, but could be more efficient. + // For now, this inefficiency is fine, considering this is only a backward-compatibility scenario (and regenerating the code fixes it). + var span = new Span(buffer); + WriteContext.Initialize(ref span, ref state, out WriteContext ctx); + try + { + WritingPrimitivesMessages.WriteRawMessage(ref ctx, value); + } + finally + { + ctx.CopyStateTo(this); + } + } + + /// + /// Writes a group, without a tag, to the stream. + /// + /// The value to write + public void WriteGroup(IMessage value) + { + var span = new Span(buffer); + WriteContext.Initialize(ref span, ref state, out WriteContext ctx); + try + { + WritingPrimitivesMessages.WriteGroup(ref ctx, value); + } + finally + { + ctx.CopyStateTo(this); + } + } + + /// + /// Write a byte string, without a tag, to the stream. + /// The data is length-prefixed. + /// + /// The value to write + public void WriteBytes(ByteString value) + { + var span = new Span(buffer); + WritingPrimitives.WriteBytes(ref span, ref state, value); + } + + /// + /// Writes a uint32 value, without a tag, to the stream. + /// + /// The value to write + public void WriteUInt32(uint value) + { + var span = new Span(buffer); + WritingPrimitives.WriteUInt32(ref span, ref state, value); + } + + /// + /// Writes an enum value, without a tag, to the stream. + /// + /// The value to write + public void WriteEnum(int value) + { + var span = new Span(buffer); + WritingPrimitives.WriteEnum(ref span, ref state, value); + } + + /// + /// Writes an sfixed32 value, without a tag, to the stream. + /// + /// The value to write. + public void WriteSFixed32(int value) + { + var span = new Span(buffer); + WritingPrimitives.WriteSFixed32(ref span, ref state, value); + } + + /// + /// Writes an sfixed64 value, without a tag, to the stream. + /// + /// The value to write + public void WriteSFixed64(long value) + { + var span = new Span(buffer); + WritingPrimitives.WriteSFixed64(ref span, ref state, value); + } + + /// + /// Writes an sint32 value, without a tag, to the stream. + /// + /// The value to write + public void WriteSInt32(int value) + { + var span = new Span(buffer); + WritingPrimitives.WriteSInt32(ref span, ref state, value); + } + + /// + /// Writes an sint64 value, without a tag, to the stream. + /// + /// The value to write + public void WriteSInt64(long value) + { + var span = new Span(buffer); + WritingPrimitives.WriteSInt64(ref span, ref state, value); + } + + /// + /// Writes a length (in bytes) for length-delimited data. + /// + /// + /// This method simply writes a rawint, but exists for clarity in calling code. + /// + /// Length value, in bytes. + public void WriteLength(int length) + { + var span = new Span(buffer); + WritingPrimitives.WriteLength(ref span, ref state, length); + } + + #endregion + + #region Raw tag writing + /// + /// Encodes and writes a tag. + /// + /// The number of the field to write the tag for + /// The wire format type of the tag to write + public void WriteTag(int fieldNumber, WireFormat.WireType type) + { + var span = new Span(buffer); + WritingPrimitives.WriteTag(ref span, ref state, fieldNumber, type); + } + + /// + /// Writes an already-encoded tag. + /// + /// The encoded tag + public void WriteTag(uint tag) + { + var span = new Span(buffer); + WritingPrimitives.WriteTag(ref span, ref state, tag); + } + + /// + /// Writes the given single-byte tag directly to the stream. + /// + /// The encoded tag + public void WriteRawTag(byte b1) + { + var span = new Span(buffer); + WritingPrimitives.WriteRawTag(ref span, ref state, b1); + } + + /// + /// Writes the given two-byte tag directly to the stream. + /// + /// The first byte of the encoded tag + /// The second byte of the encoded tag + public void WriteRawTag(byte b1, byte b2) + { + var span = new Span(buffer); + WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2); + } + + /// + /// Writes the given three-byte tag directly to the stream. + /// + /// The first byte of the encoded tag + /// The second byte of the encoded tag + /// The third byte of the encoded tag + public void WriteRawTag(byte b1, byte b2, byte b3) + { + var span = new Span(buffer); + WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3); + } + + /// + /// Writes the given four-byte tag directly to the stream. + /// + /// The first byte of the encoded tag + /// The second byte of the encoded tag + /// The third byte of the encoded tag + /// The fourth byte of the encoded tag + public void WriteRawTag(byte b1, byte b2, byte b3, byte b4) + { + var span = new Span(buffer); + WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3, b4); + } + + /// + /// Writes the given five-byte tag directly to the stream. + /// + /// The first byte of the encoded tag + /// The second byte of the encoded tag + /// The third byte of the encoded tag + /// The fourth byte of the encoded tag + /// The fifth byte of the encoded tag + public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5) + { + var span = new Span(buffer); + WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3, b4, b5); + } + #endregion + + #region Underlying writing primitives + + /// + /// Writes a 32 bit value as a varint. The fast route is taken when + /// there's enough buffer space left to whizz through without checking + /// for each byte; otherwise, we resort to calling WriteRawByte each time. + /// + internal void WriteRawVarint32(uint value) + { + var span = new Span(buffer); + WritingPrimitives.WriteRawVarint32(ref span, ref state, value); + } + + internal void WriteRawVarint64(ulong value) + { + var span = new Span(buffer); + WritingPrimitives.WriteRawVarint64(ref span, ref state, value); + } + + internal void WriteRawLittleEndian32(uint value) + { + var span = new Span(buffer); + WritingPrimitives.WriteRawLittleEndian32(ref span, ref state, value); + } + + internal void WriteRawLittleEndian64(ulong value) + { + var span = new Span(buffer); + WritingPrimitives.WriteRawLittleEndian64(ref span, ref state, value); + } + + /// + /// Writes out an array of bytes. + /// + internal void WriteRawBytes(byte[] value) + { + WriteRawBytes(value, 0, value.Length); + } + + /// + /// Writes out part of an array of bytes. + /// + internal void WriteRawBytes(byte[] value, int offset, int length) + { + var span = new Span(buffer); + WritingPrimitives.WriteRawBytes(ref span, ref state, value, offset, length); + } + + #endregion + + /// + /// Indicates that a CodedOutputStream wrapping a flat byte array + /// ran out of space. + /// + public sealed class OutOfSpaceException : IOException + { + internal OutOfSpaceException() + : base("CodedOutputStream was writing to a flat byte array and ran out of space.") + { + } + } + + /// + /// Flushes any buffered data and optionally closes the underlying stream, if any. + /// + /// + /// + /// By default, any underlying stream is closed by this method. To configure this behaviour, + /// use a constructor overload with a leaveOpen parameter. If this instance does not + /// have an underlying stream, this method does nothing. + /// + /// + /// For the sake of efficiency, calling this method does not prevent future write calls - but + /// if a later write ends up writing to a stream which has been disposed, that is likely to + /// fail. It is recommend that you not call any other methods after this. + /// + /// + public void Dispose() + { + Flush(); + if (!leaveOpen) + { + output.Dispose(); + } + } + + /// + /// Flushes any buffered data to the underlying stream (if there is one). + /// + public void Flush() + { + var span = new Span(buffer); + WriteBufferHelper.Flush(ref span, ref state); + } + + /// + /// Verifies that SpaceLeft returns zero. It's common to create a byte array + /// that is exactly big enough to hold a message, then write to it with + /// a CodedOutputStream. Calling CheckNoSpaceLeft after writing verifies that + /// the message was actually as big as expected, which can help finding bugs. + /// + public void CheckNoSpaceLeft() + { + WriteBufferHelper.CheckNoSpaceLeft(ref state); + } + + /// + /// If writing to a flat array, returns the space left in the array. Otherwise, + /// throws an InvalidOperationException. + /// + public int SpaceLeft => WriteBufferHelper.GetSpaceLeft(ref state); + + internal byte[] InternalBuffer => buffer; + + internal Stream InternalOutputStream => output; + + internal ref WriterInternalState InternalState => ref state; + } +} diff --git a/csharp/src/Google.Protobuf/Collections/MapField.cs b/csharp/src/Google.Protobuf/Collections/MapField.cs index 6b7d0f101a15..e5217f451418 100644 --- a/csharp/src/Google.Protobuf/Collections/MapField.cs +++ b/csharp/src/Google.Protobuf/Collections/MapField.cs @@ -1,762 +1,762 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2015 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using Google.Protobuf.Compatibility; -using Google.Protobuf.Reflection; -using System; -using System.Buffers; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Security; - -namespace Google.Protobuf.Collections -{ - /// - /// Representation of a map field in a Protocol Buffer message. - /// - /// Key type in the map. Must be a type supported by Protocol Buffer map keys. - /// Value type in the map. Must be a type supported by Protocol Buffers. - /// - /// - /// For string keys, the equality comparison is provided by . - /// - /// - /// Null values are not permitted in the map, either for wrapper types or regular messages. - /// If a map is deserialized from a data stream and the value is missing from an entry, a default value - /// is created instead. For primitive types, that is the regular default value (0, the empty string and so - /// on); for message types, an empty instance of the message is created, as if the map entry contained a 0-length - /// encoded value for the field. - /// - /// - /// This implementation does not generally prohibit the use of key/value types which are not - /// supported by Protocol Buffers (e.g. using a key type of byte) but nor does it guarantee - /// that all operations will work in such cases. - /// - /// - /// The order in which entries are returned when iterating over this object is undefined, and may change - /// in future versions. - /// - /// - public sealed class MapField : IDeepCloneable>, IDictionary, IEquatable>, IDictionary -#if !NET35 - , IReadOnlyDictionary -#endif - { - private static readonly EqualityComparer ValueEqualityComparer = ProtobufEqualityComparers.GetEqualityComparer(); - private static readonly EqualityComparer KeyEqualityComparer = ProtobufEqualityComparers.GetEqualityComparer(); - - // TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.) - private readonly Dictionary>> map = - new Dictionary>>(KeyEqualityComparer); - private readonly LinkedList> list = new LinkedList>(); - - /// - /// Creates a deep clone of this object. - /// - /// - /// A deep clone of this object. - /// - public MapField Clone() - { - var clone = new MapField(); - // Keys are never cloneable. Values might be. - if (typeof(IDeepCloneable).IsAssignableFrom(typeof(TValue))) - { - foreach (var pair in list) - { - clone.Add(pair.Key, ((IDeepCloneable)pair.Value).Clone()); - } - } - else - { - // Nothing is cloneable, so we don't need to worry. - clone.Add(this); - } - return clone; - } - - /// - /// Adds the specified key/value pair to the map. - /// - /// - /// This operation fails if the key already exists in the map. To replace an existing entry, use the indexer. - /// - /// The key to add - /// The value to add. - /// The given key already exists in map. - public void Add(TKey key, TValue value) - { - // Validation of arguments happens in ContainsKey and the indexer - if (ContainsKey(key)) - { - throw new ArgumentException("Key already exists in map", nameof(key)); - } - this[key] = value; - } - - /// - /// Determines whether the specified key is present in the map. - /// - /// The key to check. - /// true if the map contains the given key; false otherwise. - public bool ContainsKey(TKey key) - { - ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key)); - return map.ContainsKey(key); - } - - private bool ContainsValue(TValue value) => - list.Any(pair => ValueEqualityComparer.Equals(pair.Value, value)); - - /// - /// Removes the entry identified by the given key from the map. - /// - /// The key indicating the entry to remove from the map. - /// true if the map contained the given key before the entry was removed; false otherwise. - public bool Remove(TKey key) - { - ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key)); - LinkedListNode> node; - if (map.TryGetValue(key, out node)) - { - map.Remove(key); - node.List.Remove(node); - return true; - } - else - { - return false; - } - } - - /// - /// Gets the value associated with the specified key. - /// - /// The key whose value to get. - /// When this method returns, the value associated with the specified key, if the key is found; - /// otherwise, the default value for the type of the parameter. - /// This parameter is passed uninitialized. - /// true if the map contains an element with the specified key; otherwise, false. - public bool TryGetValue(TKey key, out TValue value) - { - LinkedListNode> node; - if (map.TryGetValue(key, out node)) - { - value = node.Value.Value; - return true; - } - else - { - value = default(TValue); - return false; - } - } - - /// - /// Gets or sets the value associated with the specified key. - /// - /// The key of the value to get or set. - /// The property is retrieved and key does not exist in the collection. - /// The value associated with the specified key. If the specified key is not found, - /// a get operation throws a , and a set operation creates a new element with the specified key. - public TValue this[TKey key] - { - get - { - ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key)); - TValue value; - if (TryGetValue(key, out value)) - { - return value; - } - throw new KeyNotFoundException(); - } - set - { - ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key)); - // value == null check here is redundant, but avoids boxing. - if (value == null) - { - ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value)); - } - LinkedListNode> node; - var pair = new KeyValuePair(key, value); - if (map.TryGetValue(key, out node)) - { - node.Value = pair; - } - else - { - node = list.AddLast(pair); - map[key] = node; - } - } - } - - /// - /// Gets a collection containing the keys in the map. - /// - public ICollection Keys { get { return new MapView(this, pair => pair.Key, ContainsKey); } } - - /// - /// Gets a collection containing the values in the map. - /// - public ICollection Values { get { return new MapView(this, pair => pair.Value, ContainsValue); } } - - /// - /// Adds the specified entries to the map. The keys and values are not automatically cloned. - /// - /// The entries to add to the map. - public void Add(IDictionary entries) - { - ProtoPreconditions.CheckNotNull(entries, nameof(entries)); - foreach (var pair in entries) - { - Add(pair.Key, pair.Value); - } - } - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// An enumerator that can be used to iterate through the collection. - /// - public IEnumerator> GetEnumerator() - { - return list.GetEnumerator(); - } - - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An object that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// Adds the specified item to the map. - /// - /// The item to add to the map. - void ICollection>.Add(KeyValuePair item) - { - Add(item.Key, item.Value); - } - - /// - /// Removes all items from the map. - /// - public void Clear() - { - list.Clear(); - map.Clear(); - } - - /// - /// Determines whether map contains an entry equivalent to the given key/value pair. - /// - /// The key/value pair to find. - /// - bool ICollection>.Contains(KeyValuePair item) - { - TValue value; - return TryGetValue(item.Key, out value) && ValueEqualityComparer.Equals(item.Value, value); - } - - /// - /// Copies the key/value pairs in this map to an array. - /// - /// The array to copy the entries into. - /// The index of the array at which to start copying values. - void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) - { - list.CopyTo(array, arrayIndex); - } - - /// - /// Removes the specified key/value pair from the map. - /// - /// Both the key and the value must be found for the entry to be removed. - /// The key/value pair to remove. - /// true if the key/value pair was found and removed; false otherwise. - bool ICollection>.Remove(KeyValuePair item) - { - if (item.Key == null) - { - throw new ArgumentException("Key is null", nameof(item)); - } - LinkedListNode> node; - if (map.TryGetValue(item.Key, out node) && - EqualityComparer.Default.Equals(item.Value, node.Value.Value)) - { - map.Remove(item.Key); - node.List.Remove(node); - return true; - } - else - { - return false; - } - } - - /// - /// Gets the number of elements contained in the map. - /// - public int Count { get { return list.Count; } } - - /// - /// Gets a value indicating whether the map is read-only. - /// - public bool IsReadOnly { get { return false; } } - - /// - /// Determines whether the specified , is equal to this instance. - /// - /// The to compare with this instance. - /// - /// true if the specified is equal to this instance; otherwise, false. - /// - public override bool Equals(object other) - { - return Equals(other as MapField); - } - - /// - /// Returns a hash code for this instance. - /// - /// - /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. - /// - public override int GetHashCode() - { - var keyComparer = KeyEqualityComparer; - var valueComparer = ValueEqualityComparer; - int hash = 0; - foreach (var pair in list) - { - hash ^= keyComparer.GetHashCode(pair.Key) * 31 + valueComparer.GetHashCode(pair.Value); - } - return hash; - } - - /// - /// Compares this map with another for equality. - /// - /// - /// The order of the key/value pairs in the maps is not deemed significant in this comparison. - /// - /// The map to compare this with. - /// true if refers to an equal map; false otherwise. - public bool Equals(MapField other) - { - if (other == null) - { - return false; - } - if (other == this) - { - return true; - } - if (other.Count != this.Count) - { - return false; - } - var valueComparer = ValueEqualityComparer; - foreach (var pair in this) - { - TValue value; - if (!other.TryGetValue(pair.Key, out value)) - { - return false; - } - if (!valueComparer.Equals(value, pair.Value)) - { - return false; - } - } - return true; - } - - /// - /// Adds entries to the map from the given stream. - /// - /// - /// It is assumed that the stream is initially positioned after the tag specified by the codec. - /// This method will continue reading entries from the stream until the end is reached, or - /// a different tag is encountered. - /// - /// Stream to read from - /// Codec describing how the key/value pairs are encoded - public void AddEntriesFrom(CodedInputStream input, Codec codec) - { - ParseContext.Initialize(input, out ParseContext ctx); - try - { - AddEntriesFrom(ref ctx, codec); - } - finally - { - ctx.CopyStateTo(input); - } - } - - /// - /// Adds entries to the map from the given parse context. - /// - /// - /// It is assumed that the input is initially positioned after the tag specified by the codec. - /// This method will continue reading entries from the input until the end is reached, or - /// a different tag is encountered. - /// - /// Input to read from - /// Codec describing how the key/value pairs are encoded - [SecuritySafeCritical] - public void AddEntriesFrom(ref ParseContext ctx, Codec codec) - { - do - { - KeyValuePair entry = ParsingPrimitivesMessages.ReadMapEntry(ref ctx, codec); - this[entry.Key] = entry.Value; - } while (ParsingPrimitives.MaybeConsumeTag(ref ctx.buffer, ref ctx.state, codec.MapTag)); - } - - /// - /// Writes the contents of this map to the given coded output stream, using the specified codec - /// to encode each entry. - /// - /// The output stream to write to. - /// The codec to use for each entry. - public void WriteTo(CodedOutputStream output, Codec codec) - { - WriteContext.Initialize(output, out WriteContext ctx); - try - { - WriteTo(ref ctx, codec); - } - finally - { - ctx.CopyStateTo(output); - } - } - - /// - /// Writes the contents of this map to the given write context, using the specified codec - /// to encode each entry. - /// - /// The write context to write to. - /// The codec to use for each entry. - [SecuritySafeCritical] - public void WriteTo(ref WriteContext ctx, Codec codec) - { - foreach (var entry in list) - { - ctx.WriteTag(codec.MapTag); - - WritingPrimitives.WriteLength(ref ctx.buffer, ref ctx.state, CalculateEntrySize(codec, entry)); - codec.KeyCodec.WriteTagAndValue(ref ctx, entry.Key); - codec.ValueCodec.WriteTagAndValue(ref ctx, entry.Value); - } - } - - /// - /// Calculates the size of this map based on the given entry codec. - /// - /// The codec to use to encode each entry. - /// - public int CalculateSize(Codec codec) - { - if (Count == 0) - { - return 0; - } - int size = 0; - foreach (var entry in list) - { - int entrySize = CalculateEntrySize(codec, entry); - - size += CodedOutputStream.ComputeRawVarint32Size(codec.MapTag); - size += CodedOutputStream.ComputeLengthSize(entrySize) + entrySize; - } - return size; - } - - private static int CalculateEntrySize(Codec codec, KeyValuePair entry) - { - return codec.KeyCodec.CalculateSizeWithTag(entry.Key) + codec.ValueCodec.CalculateSizeWithTag(entry.Value); - } - - /// - /// Returns a string representation of this repeated field, in the same - /// way as it would be represented by the default JSON formatter. - /// - public override string ToString() - { - var writer = new StringWriter(); - JsonFormatter.Default.WriteDictionary(writer, this); - return writer.ToString(); - } - - #region IDictionary explicit interface implementation - void IDictionary.Add(object key, object value) - { - Add((TKey)key, (TValue)value); - } - - bool IDictionary.Contains(object key) - { - if (!(key is TKey)) - { - return false; - } - return ContainsKey((TKey)key); - } - - IDictionaryEnumerator IDictionary.GetEnumerator() - { - return new DictionaryEnumerator(GetEnumerator()); - } - - void IDictionary.Remove(object key) - { - ProtoPreconditions.CheckNotNull(key, nameof(key)); - if (!(key is TKey)) - { - return; - } - Remove((TKey)key); - } - - void ICollection.CopyTo(Array array, int index) - { - // This is ugly and slow as heck, but with any luck it will never be used anyway. - ICollection temp = this.Select(pair => new DictionaryEntry(pair.Key, pair.Value)).ToList(); - temp.CopyTo(array, index); - } - - bool IDictionary.IsFixedSize { get { return false; } } - - ICollection IDictionary.Keys { get { return (ICollection)Keys; } } - - ICollection IDictionary.Values { get { return (ICollection)Values; } } - - bool ICollection.IsSynchronized { get { return false; } } - - object ICollection.SyncRoot { get { return this; } } - - object IDictionary.this[object key] - { - get - { - ProtoPreconditions.CheckNotNull(key, nameof(key)); - if (!(key is TKey)) - { - return null; - } - TValue value; - TryGetValue((TKey)key, out value); - return value; - } - - set - { - this[(TKey)key] = (TValue)value; - } - } - #endregion - - #region IReadOnlyDictionary explicit interface implementation -#if !NET35 - IEnumerable IReadOnlyDictionary.Keys => Keys; - - IEnumerable IReadOnlyDictionary.Values => Values; -#endif - #endregion - - private class DictionaryEnumerator : IDictionaryEnumerator - { - private readonly IEnumerator> enumerator; - - internal DictionaryEnumerator(IEnumerator> enumerator) - { - this.enumerator = enumerator; - } - - public bool MoveNext() - { - return enumerator.MoveNext(); - } - - public void Reset() - { - enumerator.Reset(); - } - - public object Current { get { return Entry; } } - public DictionaryEntry Entry { get { return new DictionaryEntry(Key, Value); } } - public object Key { get { return enumerator.Current.Key; } } - public object Value { get { return enumerator.Current.Value; } } - } - - /// - /// A codec for a specific map field. This contains all the information required to encode and - /// decode the nested messages. - /// - public sealed class Codec - { - private readonly FieldCodec keyCodec; - private readonly FieldCodec valueCodec; - private readonly uint mapTag; - - /// - /// Creates a new entry codec based on a separate key codec and value codec, - /// and the tag to use for each map entry. - /// - /// The key codec. - /// The value codec. - /// The map tag to use to introduce each map entry. - public Codec(FieldCodec keyCodec, FieldCodec valueCodec, uint mapTag) - { - this.keyCodec = keyCodec; - this.valueCodec = valueCodec; - this.mapTag = mapTag; - } - - /// - /// The key codec. - /// - internal FieldCodec KeyCodec => keyCodec; - - /// - /// The value codec. - /// - internal FieldCodec ValueCodec => valueCodec; - - /// - /// The tag used in the enclosing message to indicate map entries. - /// - internal uint MapTag => mapTag; - } - - private class MapView : ICollection, ICollection - { - private readonly MapField parent; - private readonly Func, T> projection; - private readonly Func containsCheck; - - internal MapView( - MapField parent, - Func, T> projection, - Func containsCheck) - { - this.parent = parent; - this.projection = projection; - this.containsCheck = containsCheck; - } - - public int Count { get { return parent.Count; } } - - public bool IsReadOnly { get { return true; } } - - public bool IsSynchronized { get { return false; } } - - public object SyncRoot { get { return parent; } } - - public void Add(T item) - { - throw new NotSupportedException(); - } - - public void Clear() - { - throw new NotSupportedException(); - } - - public bool Contains(T item) - { - return containsCheck(item); - } - - public void CopyTo(T[] array, int arrayIndex) - { - if (arrayIndex < 0) - { - throw new ArgumentOutOfRangeException(nameof(arrayIndex)); - } - if (arrayIndex + Count > array.Length) - { - throw new ArgumentException("Not enough space in the array", nameof(array)); - } - foreach (var item in this) - { - array[arrayIndex++] = item; - } - } - - public IEnumerator GetEnumerator() - { - return parent.list.Select(projection).GetEnumerator(); - } - - public bool Remove(T item) - { - throw new NotSupportedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public void CopyTo(Array array, int index) - { - if (index < 0) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - if (index + Count > array.Length) - { - throw new ArgumentException("Not enough space in the array", nameof(array)); - } - foreach (var item in this) - { - array.SetValue(item, index++); - } - } - } - } -} +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using Google.Protobuf.Compatibility; +using Google.Protobuf.Reflection; +using System; +using System.Buffers; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security; + +namespace Google.Protobuf.Collections +{ + /// + /// Representation of a map field in a Protocol Buffer message. + /// + /// Key type in the map. Must be a type supported by Protocol Buffer map keys. + /// Value type in the map. Must be a type supported by Protocol Buffers. + /// + /// + /// For string keys, the equality comparison is provided by . + /// + /// + /// Null values are not permitted in the map, either for wrapper types or regular messages. + /// If a map is deserialized from a data stream and the value is missing from an entry, a default value + /// is created instead. For primitive types, that is the regular default value (0, the empty string and so + /// on); for message types, an empty instance of the message is created, as if the map entry contained a 0-length + /// encoded value for the field. + /// + /// + /// This implementation does not generally prohibit the use of key/value types which are not + /// supported by Protocol Buffers (e.g. using a key type of byte) but nor does it guarantee + /// that all operations will work in such cases. + /// + /// + /// The order in which entries are returned when iterating over this object is undefined, and may change + /// in future versions. + /// + /// + public sealed class MapField : IDeepCloneable>, IDictionary, IEquatable>, IDictionary +#if !NET35 + , IReadOnlyDictionary +#endif + { + private static readonly EqualityComparer ValueEqualityComparer = ProtobufEqualityComparers.GetEqualityComparer(); + private static readonly EqualityComparer KeyEqualityComparer = ProtobufEqualityComparers.GetEqualityComparer(); + + // TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.) + private readonly Dictionary>> map = + new Dictionary>>(KeyEqualityComparer); + private readonly LinkedList> list = new LinkedList>(); + + /// + /// Creates a deep clone of this object. + /// + /// + /// A deep clone of this object. + /// + public MapField Clone() + { + var clone = new MapField(); + // Keys are never cloneable. Values might be. + if (typeof(IDeepCloneable).IsAssignableFrom(typeof(TValue))) + { + foreach (var pair in list) + { + clone.Add(pair.Key, ((IDeepCloneable)pair.Value).Clone()); + } + } + else + { + // Nothing is cloneable, so we don't need to worry. + clone.Add(this); + } + return clone; + } + + /// + /// Adds the specified key/value pair to the map. + /// + /// + /// This operation fails if the key already exists in the map. To replace an existing entry, use the indexer. + /// + /// The key to add + /// The value to add. + /// The given key already exists in map. + public void Add(TKey key, TValue value) + { + // Validation of arguments happens in ContainsKey and the indexer + if (ContainsKey(key)) + { + throw new ArgumentException("Key already exists in map", nameof(key)); + } + this[key] = value; + } + + /// + /// Determines whether the specified key is present in the map. + /// + /// The key to check. + /// true if the map contains the given key; false otherwise. + public bool ContainsKey(TKey key) + { + ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key)); + return map.ContainsKey(key); + } + + private bool ContainsValue(TValue value) => + list.Any(pair => ValueEqualityComparer.Equals(pair.Value, value)); + + /// + /// Removes the entry identified by the given key from the map. + /// + /// The key indicating the entry to remove from the map. + /// true if the map contained the given key before the entry was removed; false otherwise. + public bool Remove(TKey key) + { + ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key)); + LinkedListNode> node; + if (map.TryGetValue(key, out node)) + { + map.Remove(key); + node.List.Remove(node); + return true; + } + else + { + return false; + } + } + + /// + /// Gets the value associated with the specified key. + /// + /// The key whose value to get. + /// When this method returns, the value associated with the specified key, if the key is found; + /// otherwise, the default value for the type of the parameter. + /// This parameter is passed uninitialized. + /// true if the map contains an element with the specified key; otherwise, false. + public bool TryGetValue(TKey key, out TValue value) + { + LinkedListNode> node; + if (map.TryGetValue(key, out node)) + { + value = node.Value.Value; + return true; + } + else + { + value = default(TValue); + return false; + } + } + + /// + /// Gets or sets the value associated with the specified key. + /// + /// The key of the value to get or set. + /// The property is retrieved and key does not exist in the collection. + /// The value associated with the specified key. If the specified key is not found, + /// a get operation throws a , and a set operation creates a new element with the specified key. + public TValue this[TKey key] + { + get + { + ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key)); + TValue value; + if (TryGetValue(key, out value)) + { + return value; + } + throw new KeyNotFoundException(); + } + set + { + ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key)); + // value == null check here is redundant, but avoids boxing. + if (value == null) + { + ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value)); + } + LinkedListNode> node; + var pair = new KeyValuePair(key, value); + if (map.TryGetValue(key, out node)) + { + node.Value = pair; + } + else + { + node = list.AddLast(pair); + map[key] = node; + } + } + } + + /// + /// Gets a collection containing the keys in the map. + /// + public ICollection Keys { get { return new MapView(this, pair => pair.Key, ContainsKey); } } + + /// + /// Gets a collection containing the values in the map. + /// + public ICollection Values { get { return new MapView(this, pair => pair.Value, ContainsValue); } } + + /// + /// Adds the specified entries to the map. The keys and values are not automatically cloned. + /// + /// The entries to add to the map. + public void Add(IDictionary entries) + { + ProtoPreconditions.CheckNotNull(entries, nameof(entries)); + foreach (var pair in entries) + { + Add(pair.Key, pair.Value); + } + } + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// An enumerator that can be used to iterate through the collection. + /// + public IEnumerator> GetEnumerator() + { + return list.GetEnumerator(); + } + + /// + /// Returns an enumerator that iterates through a collection. + /// + /// + /// An object that can be used to iterate through the collection. + /// + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Adds the specified item to the map. + /// + /// The item to add to the map. + void ICollection>.Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + /// + /// Removes all items from the map. + /// + public void Clear() + { + list.Clear(); + map.Clear(); + } + + /// + /// Determines whether map contains an entry equivalent to the given key/value pair. + /// + /// The key/value pair to find. + /// + bool ICollection>.Contains(KeyValuePair item) + { + TValue value; + return TryGetValue(item.Key, out value) && ValueEqualityComparer.Equals(item.Value, value); + } + + /// + /// Copies the key/value pairs in this map to an array. + /// + /// The array to copy the entries into. + /// The index of the array at which to start copying values. + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + list.CopyTo(array, arrayIndex); + } + + /// + /// Removes the specified key/value pair from the map. + /// + /// Both the key and the value must be found for the entry to be removed. + /// The key/value pair to remove. + /// true if the key/value pair was found and removed; false otherwise. + bool ICollection>.Remove(KeyValuePair item) + { + if (item.Key == null) + { + throw new ArgumentException("Key is null", nameof(item)); + } + LinkedListNode> node; + if (map.TryGetValue(item.Key, out node) && + EqualityComparer.Default.Equals(item.Value, node.Value.Value)) + { + map.Remove(item.Key); + node.List.Remove(node); + return true; + } + else + { + return false; + } + } + + /// + /// Gets the number of elements contained in the map. + /// + public int Count { get { return list.Count; } } + + /// + /// Gets a value indicating whether the map is read-only. + /// + public bool IsReadOnly { get { return false; } } + + /// + /// Determines whether the specified , is equal to this instance. + /// + /// The to compare with this instance. + /// + /// true if the specified is equal to this instance; otherwise, false. + /// + public override bool Equals(object other) + { + return Equals(other as MapField); + } + + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// + public override int GetHashCode() + { + var keyComparer = KeyEqualityComparer; + var valueComparer = ValueEqualityComparer; + int hash = 0; + foreach (var pair in list) + { + hash ^= keyComparer.GetHashCode(pair.Key) * 31 + valueComparer.GetHashCode(pair.Value); + } + return hash; + } + + /// + /// Compares this map with another for equality. + /// + /// + /// The order of the key/value pairs in the maps is not deemed significant in this comparison. + /// + /// The map to compare this with. + /// true if refers to an equal map; false otherwise. + public bool Equals(MapField other) + { + if (other == null) + { + return false; + } + if (other == this) + { + return true; + } + if (other.Count != this.Count) + { + return false; + } + var valueComparer = ValueEqualityComparer; + foreach (var pair in this) + { + TValue value; + if (!other.TryGetValue(pair.Key, out value)) + { + return false; + } + if (!valueComparer.Equals(value, pair.Value)) + { + return false; + } + } + return true; + } + + /// + /// Adds entries to the map from the given stream. + /// + /// + /// It is assumed that the stream is initially positioned after the tag specified by the codec. + /// This method will continue reading entries from the stream until the end is reached, or + /// a different tag is encountered. + /// + /// Stream to read from + /// Codec describing how the key/value pairs are encoded + public void AddEntriesFrom(CodedInputStream input, Codec codec) + { + ParseContext.Initialize(input, out ParseContext ctx); + try + { + AddEntriesFrom(ref ctx, codec); + } + finally + { + ctx.CopyStateTo(input); + } + } + + /// + /// Adds entries to the map from the given parse context. + /// + /// + /// It is assumed that the input is initially positioned after the tag specified by the codec. + /// This method will continue reading entries from the input until the end is reached, or + /// a different tag is encountered. + /// + /// Input to read from + /// Codec describing how the key/value pairs are encoded + [SecuritySafeCritical] + public void AddEntriesFrom(ref ParseContext ctx, Codec codec) + { + do + { + KeyValuePair entry = ParsingPrimitivesMessages.ReadMapEntry(ref ctx, codec); + this[entry.Key] = entry.Value; + } while (ParsingPrimitives.MaybeConsumeTag(ref ctx.buffer, ref ctx.state, codec.MapTag)); + } + + /// + /// Writes the contents of this map to the given coded output stream, using the specified codec + /// to encode each entry. + /// + /// The output stream to write to. + /// The codec to use for each entry. + public void WriteTo(CodedOutputStream output, Codec codec) + { + WriteContext.Initialize(output, out WriteContext ctx); + try + { + WriteTo(ref ctx, codec); + } + finally + { + ctx.CopyStateTo(output); + } + } + + /// + /// Writes the contents of this map to the given write context, using the specified codec + /// to encode each entry. + /// + /// The write context to write to. + /// The codec to use for each entry. + [SecuritySafeCritical] + public void WriteTo(ref WriteContext ctx, Codec codec) + { + foreach (var entry in list) + { + ctx.WriteTag(codec.MapTag); + + WritingPrimitives.WriteLength(ref ctx.buffer, ref ctx.state, CalculateEntrySize(codec, entry)); + codec.KeyCodec.WriteTagAndValue(ref ctx, entry.Key); + codec.ValueCodec.WriteTagAndValue(ref ctx, entry.Value); + } + } + + /// + /// Calculates the size of this map based on the given entry codec. + /// + /// The codec to use to encode each entry. + /// + public int CalculateSize(Codec codec) + { + if (Count == 0) + { + return 0; + } + int size = 0; + foreach (var entry in list) + { + int entrySize = CalculateEntrySize(codec, entry); + + size += CodedOutputStream.ComputeRawVarint32Size(codec.MapTag); + size += CodedOutputStream.ComputeLengthSize(entrySize) + entrySize; + } + return size; + } + + private static int CalculateEntrySize(Codec codec, KeyValuePair entry) + { + return codec.KeyCodec.CalculateSizeWithTag(entry.Key) + codec.ValueCodec.CalculateSizeWithTag(entry.Value); + } + + /// + /// Returns a string representation of this repeated field, in the same + /// way as it would be represented by the default JSON formatter. + /// + public override string ToString() + { + var writer = new StringWriter(); + JsonFormatter.Default.WriteDictionary(writer, this); + return writer.ToString(); + } + + #region IDictionary explicit interface implementation + void IDictionary.Add(object key, object value) + { + Add((TKey)key, (TValue)value); + } + + bool IDictionary.Contains(object key) + { + if (!(key is TKey)) + { + return false; + } + return ContainsKey((TKey)key); + } + + IDictionaryEnumerator IDictionary.GetEnumerator() + { + return new DictionaryEnumerator(GetEnumerator()); + } + + void IDictionary.Remove(object key) + { + ProtoPreconditions.CheckNotNull(key, nameof(key)); + if (!(key is TKey)) + { + return; + } + Remove((TKey)key); + } + + void ICollection.CopyTo(Array array, int index) + { + // This is ugly and slow as heck, but with any luck it will never be used anyway. + ICollection temp = this.Select(pair => new DictionaryEntry(pair.Key, pair.Value)).ToList(); + temp.CopyTo(array, index); + } + + bool IDictionary.IsFixedSize { get { return false; } } + + ICollection IDictionary.Keys { get { return (ICollection)Keys; } } + + ICollection IDictionary.Values { get { return (ICollection)Values; } } + + bool ICollection.IsSynchronized { get { return false; } } + + object ICollection.SyncRoot { get { return this; } } + + object IDictionary.this[object key] + { + get + { + ProtoPreconditions.CheckNotNull(key, nameof(key)); + if (!(key is TKey)) + { + return null; + } + TValue value; + TryGetValue((TKey)key, out value); + return value; + } + + set + { + this[(TKey)key] = (TValue)value; + } + } + #endregion + + #region IReadOnlyDictionary explicit interface implementation +#if !NET35 + IEnumerable IReadOnlyDictionary.Keys => Keys; + + IEnumerable IReadOnlyDictionary.Values => Values; +#endif + #endregion + + private class DictionaryEnumerator : IDictionaryEnumerator + { + private readonly IEnumerator> enumerator; + + internal DictionaryEnumerator(IEnumerator> enumerator) + { + this.enumerator = enumerator; + } + + public bool MoveNext() + { + return enumerator.MoveNext(); + } + + public void Reset() + { + enumerator.Reset(); + } + + public object Current { get { return Entry; } } + public DictionaryEntry Entry { get { return new DictionaryEntry(Key, Value); } } + public object Key { get { return enumerator.Current.Key; } } + public object Value { get { return enumerator.Current.Value; } } + } + + /// + /// A codec for a specific map field. This contains all the information required to encode and + /// decode the nested messages. + /// + public sealed class Codec + { + private readonly FieldCodec keyCodec; + private readonly FieldCodec valueCodec; + private readonly uint mapTag; + + /// + /// Creates a new entry codec based on a separate key codec and value codec, + /// and the tag to use for each map entry. + /// + /// The key codec. + /// The value codec. + /// The map tag to use to introduce each map entry. + public Codec(FieldCodec keyCodec, FieldCodec valueCodec, uint mapTag) + { + this.keyCodec = keyCodec; + this.valueCodec = valueCodec; + this.mapTag = mapTag; + } + + /// + /// The key codec. + /// + internal FieldCodec KeyCodec => keyCodec; + + /// + /// The value codec. + /// + internal FieldCodec ValueCodec => valueCodec; + + /// + /// The tag used in the enclosing message to indicate map entries. + /// + internal uint MapTag => mapTag; + } + + private class MapView : ICollection, ICollection + { + private readonly MapField parent; + private readonly Func, T> projection; + private readonly Func containsCheck; + + internal MapView( + MapField parent, + Func, T> projection, + Func containsCheck) + { + this.parent = parent; + this.projection = projection; + this.containsCheck = containsCheck; + } + + public int Count { get { return parent.Count; } } + + public bool IsReadOnly { get { return true; } } + + public bool IsSynchronized { get { return false; } } + + public object SyncRoot { get { return parent; } } + + public void Add(T item) + { + throw new NotSupportedException(); + } + + public void Clear() + { + throw new NotSupportedException(); + } + + public bool Contains(T item) + { + return containsCheck(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + if (arrayIndex < 0) + { + throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + } + if (arrayIndex + Count > array.Length) + { + throw new ArgumentException("Not enough space in the array", nameof(array)); + } + foreach (var item in this) + { + array[arrayIndex++] = item; + } + } + + public IEnumerator GetEnumerator() + { + return parent.list.Select(projection).GetEnumerator(); + } + + public bool Remove(T item) + { + throw new NotSupportedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void CopyTo(Array array, int index) + { + if (index < 0) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + if (index + Count > array.Length) + { + throw new ArgumentException("Not enough space in the array", nameof(array)); + } + foreach (var item in this) + { + array.SetValue(item, index++); + } + } + } + } +} diff --git a/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs b/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs index 84360667d8ae..28530a29a846 100644 --- a/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs +++ b/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs @@ -1,147 +1,147 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; - -namespace Google.Protobuf.Collections -{ - /// - /// Read-only wrapper around another dictionary. - /// - internal sealed class ReadOnlyDictionary : IDictionary - { - private readonly IDictionary wrapped; - - public ReadOnlyDictionary(IDictionary wrapped) - { - this.wrapped = wrapped; - } - - public void Add(TKey key, TValue value) - { - throw new InvalidOperationException(); - } - - public bool ContainsKey(TKey key) - { - return wrapped.ContainsKey(key); - } - - public ICollection Keys - { - get { return wrapped.Keys; } - } - - public bool Remove(TKey key) - { - throw new InvalidOperationException(); - } - - public bool TryGetValue(TKey key, out TValue value) - { - return wrapped.TryGetValue(key, out value); - } - - public ICollection Values - { - get { return wrapped.Values; } - } - - public TValue this[TKey key] - { - get { return wrapped[key]; } - set { throw new InvalidOperationException(); } - } - - public void Add(KeyValuePair item) - { - throw new InvalidOperationException(); - } - - public void Clear() - { - throw new InvalidOperationException(); - } - - public bool Contains(KeyValuePair item) - { - return wrapped.Contains(item); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - wrapped.CopyTo(array, arrayIndex); - } - - public int Count - { - get { return wrapped.Count; } - } - - public bool IsReadOnly - { - get { return true; } - } - - public bool Remove(KeyValuePair item) - { - throw new InvalidOperationException(); - } - - public IEnumerator> GetEnumerator() - { - return wrapped.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable) wrapped).GetEnumerator(); - } - - public override bool Equals(object obj) - { - return wrapped.Equals(obj); - } - - public override int GetHashCode() - { - return wrapped.GetHashCode(); - } - - public override string ToString() - { - return wrapped.ToString(); - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Google.Protobuf.Collections +{ + /// + /// Read-only wrapper around another dictionary. + /// + internal sealed class ReadOnlyDictionary : IDictionary + { + private readonly IDictionary wrapped; + + public ReadOnlyDictionary(IDictionary wrapped) + { + this.wrapped = wrapped; + } + + public void Add(TKey key, TValue value) + { + throw new InvalidOperationException(); + } + + public bool ContainsKey(TKey key) + { + return wrapped.ContainsKey(key); + } + + public ICollection Keys + { + get { return wrapped.Keys; } + } + + public bool Remove(TKey key) + { + throw new InvalidOperationException(); + } + + public bool TryGetValue(TKey key, out TValue value) + { + return wrapped.TryGetValue(key, out value); + } + + public ICollection Values + { + get { return wrapped.Values; } + } + + public TValue this[TKey key] + { + get { return wrapped[key]; } + set { throw new InvalidOperationException(); } + } + + public void Add(KeyValuePair item) + { + throw new InvalidOperationException(); + } + + public void Clear() + { + throw new InvalidOperationException(); + } + + public bool Contains(KeyValuePair item) + { + return wrapped.Contains(item); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + wrapped.CopyTo(array, arrayIndex); + } + + public int Count + { + get { return wrapped.Count; } + } + + public bool IsReadOnly + { + get { return true; } + } + + public bool Remove(KeyValuePair item) + { + throw new InvalidOperationException(); + } + + public IEnumerator> GetEnumerator() + { + return wrapped.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable) wrapped).GetEnumerator(); + } + + public override bool Equals(object obj) + { + return wrapped.Equals(obj); + } + + public override int GetHashCode() + { + return wrapped.GetHashCode(); + } + + public override string ToString() + { + return wrapped.ToString(); + } + } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs index 19114caa2475..9269c7444c10 100644 --- a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs +++ b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs @@ -1,698 +1,698 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2015 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Security; -using System.Threading; - -namespace Google.Protobuf.Collections -{ - /// - /// The contents of a repeated field: essentially, a collection with some extra - /// restrictions (no null values) and capabilities (deep cloning). - /// - /// - /// This implementation does not generally prohibit the use of types which are not - /// supported by Protocol Buffers but nor does it guarantee that all operations will work in such cases. - /// - /// The element type of the repeated field. - public sealed class RepeatedField : IList, IList, IDeepCloneable>, IEquatable> -#if !NET35 - , IReadOnlyList -#endif - { - private static readonly EqualityComparer EqualityComparer = ProtobufEqualityComparers.GetEqualityComparer(); - private static readonly T[] EmptyArray = new T[0]; - private const int MinArraySize = 8; - - private T[] array = EmptyArray; - private int count = 0; - - /// - /// Creates a deep clone of this repeated field. - /// - /// - /// If the field type is - /// a message type, each element is also cloned; otherwise, it is - /// assumed that the field type is primitive (including string and - /// bytes, both of which are immutable) and so a simple copy is - /// equivalent to a deep clone. - /// - /// A deep clone of this repeated field. - public RepeatedField Clone() - { - RepeatedField clone = new RepeatedField(); - if (array != EmptyArray) - { - clone.array = (T[])array.Clone(); - IDeepCloneable[] cloneableArray = clone.array as IDeepCloneable[]; - if (cloneableArray != null) - { - for (int i = 0; i < count; i++) - { - clone.array[i] = cloneableArray[i].Clone(); - } - } - } - clone.count = count; - return clone; - } - - /// - /// Adds the entries from the given input stream, decoding them with the specified codec. - /// - /// The input stream to read from. - /// The codec to use in order to read each entry. - public void AddEntriesFrom(CodedInputStream input, FieldCodec codec) - { - ParseContext.Initialize(input, out ParseContext ctx); - try - { - AddEntriesFrom(ref ctx, codec); - } - finally - { - ctx.CopyStateTo(input); - } - } - - /// - /// Adds the entries from the given parse context, decoding them with the specified codec. - /// - /// The input to read from. - /// The codec to use in order to read each entry. - [SecuritySafeCritical] - public void AddEntriesFrom(ref ParseContext ctx, FieldCodec codec) - { - // TODO: Inline some of the Add code, so we can avoid checking the size on every - // iteration. - uint tag = ctx.state.lastTag; - var reader = codec.ValueReader; - // Non-nullable value types can be packed or not. - if (FieldCodec.IsPackedRepeatedField(tag)) - { - int length = ctx.ReadLength(); - if (length > 0) - { - int oldLimit = SegmentedBufferHelper.PushLimit(ref ctx.state, length); - - // If the content is fixed size then we can calculate the length - // of the repeated field and pre-initialize the underlying collection. - // - // Check that the supplied length doesn't exceed the underlying buffer. - // That prevents a malicious length from initializing a very large collection. - if (codec.FixedSize > 0 && length % codec.FixedSize == 0 && ParsingPrimitives.IsDataAvailable(ref ctx.state, length)) - { - EnsureSize(count + (length / codec.FixedSize)); - - while (!SegmentedBufferHelper.IsReachedLimit(ref ctx.state)) - { - // Only FieldCodecs with a fixed size can reach here, and they are all known - // types that don't allow the user to specify a custom reader action. - // reader action will never return null. - array[count++] = reader(ref ctx); - } - } - else - { - // Content is variable size so add until we reach the limit. - while (!SegmentedBufferHelper.IsReachedLimit(ref ctx.state)) - { - Add(reader(ref ctx)); - } - } - SegmentedBufferHelper.PopLimit(ref ctx.state, oldLimit); - } - // Empty packed field. Odd, but valid - just ignore. - } - else - { - // Not packed... (possibly not packable) - do - { - Add(reader(ref ctx)); - } while (ParsingPrimitives.MaybeConsumeTag(ref ctx.buffer, ref ctx.state, tag)); - } - } - - /// - /// Calculates the size of this collection based on the given codec. - /// - /// The codec to use when encoding each field. - /// The number of bytes that would be written to an output by one of the WriteTo methods, - /// using the same codec. - public int CalculateSize(FieldCodec codec) - { - if (count == 0) - { - return 0; - } - uint tag = codec.Tag; - if (codec.PackedRepeatedField) - { - int dataSize = CalculatePackedDataSize(codec); - return CodedOutputStream.ComputeRawVarint32Size(tag) + - CodedOutputStream.ComputeLengthSize(dataSize) + - dataSize; - } - else - { - var sizeCalculator = codec.ValueSizeCalculator; - int size = count * CodedOutputStream.ComputeRawVarint32Size(tag); - if (codec.EndTag != 0) - { - size += count * CodedOutputStream.ComputeRawVarint32Size(codec.EndTag); - } - for (int i = 0; i < count; i++) - { - size += sizeCalculator(array[i]); - } - return size; - } - } - - private int CalculatePackedDataSize(FieldCodec codec) - { - int fixedSize = codec.FixedSize; - if (fixedSize == 0) - { - var calculator = codec.ValueSizeCalculator; - int tmp = 0; - for (int i = 0; i < count; i++) - { - tmp += calculator(array[i]); - } - return tmp; - } - else - { - return fixedSize * Count; - } - } - - /// - /// Writes the contents of this collection to the given , - /// encoding each value using the specified codec. - /// - /// The output stream to write to. - /// The codec to use when encoding each value. - public void WriteTo(CodedOutputStream output, FieldCodec codec) - { - WriteContext.Initialize(output, out WriteContext ctx); - try - { - WriteTo(ref ctx, codec); - } - finally - { - ctx.CopyStateTo(output); - } - } - - /// - /// Writes the contents of this collection to the given write context, - /// encoding each value using the specified codec. - /// - /// The write context to write to. - /// The codec to use when encoding each value. - [SecuritySafeCritical] - public void WriteTo(ref WriteContext ctx, FieldCodec codec) - { - if (count == 0) - { - return; - } - var writer = codec.ValueWriter; - var tag = codec.Tag; - if (codec.PackedRepeatedField) - { - // Packed primitive type - int size = CalculatePackedDataSize(codec); - ctx.WriteTag(tag); - ctx.WriteLength(size); - for (int i = 0; i < count; i++) - { - writer(ref ctx, array[i]); - } - } - else - { - // Not packed: a simple tag/value pair for each value. - // Can't use codec.WriteTagAndValue, as that omits default values. - for (int i = 0; i < count; i++) - { - ctx.WriteTag(tag); - writer(ref ctx, array[i]); - if (codec.EndTag != 0) - { - ctx.WriteTag(codec.EndTag); - } - } - } - } - - /// - /// Gets and sets the capacity of the RepeatedField's internal array. WHen set, the internal array is reallocated to the given capacity. - /// The new value is less than Count -or- when Count is less than 0. - /// - public int Capacity - { - get { return array.Length; } - set - { - if (value < count) - { - throw new ArgumentOutOfRangeException("Capacity", value, - $"Cannot set Capacity to a value smaller than the current item count, {count}"); - } - - if (value >= 0 && value != array.Length) - { - SetSize(value); - } - } - } - - // May increase the size of the internal array, but will never shrink it. - private void EnsureSize(int size) - { - if (array.Length < size) - { - size = Math.Max(size, MinArraySize); - int newSize = Math.Max(array.Length * 2, size); - SetSize(newSize); - } - } - - // Sets the internal array to an exact size. - private void SetSize(int size) - { - if (size != array.Length) - { - var tmp = new T[size]; - Array.Copy(array, 0, tmp, 0, count); - array = tmp; - } - } - - /// - /// Adds the specified item to the collection. - /// - /// The item to add. - public void Add(T item) - { - ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item)); - EnsureSize(count + 1); - array[count++] = item; - } - - /// - /// Removes all items from the collection. - /// - public void Clear() - { - array = EmptyArray; - count = 0; - } - - /// - /// Determines whether this collection contains the given item. - /// - /// The item to find. - /// true if this collection contains the given item; false otherwise. - public bool Contains(T item) - { - return IndexOf(item) != -1; - } - - /// - /// Copies this collection to the given array. - /// - /// The array to copy to. - /// The first index of the array to copy to. - public void CopyTo(T[] array, int arrayIndex) - { - Array.Copy(this.array, 0, array, arrayIndex, count); - } - - /// - /// Removes the specified item from the collection - /// - /// The item to remove. - /// true if the item was found and removed; false otherwise. - public bool Remove(T item) - { - int index = IndexOf(item); - if (index == -1) - { - return false; - } - Array.Copy(array, index + 1, array, index, count - index - 1); - count--; - array[count] = default(T); - return true; - } - - /// - /// Gets the number of elements contained in the collection. - /// - public int Count => count; - - /// - /// Gets a value indicating whether the collection is read-only. - /// - public bool IsReadOnly => false; - - /// - /// Adds all of the specified values into this collection. - /// - /// The values to add to this collection. - public void AddRange(IEnumerable values) - { - ProtoPreconditions.CheckNotNull(values, nameof(values)); - - // Optimization 1: If the collection we're adding is already a RepeatedField, - // we know the values are valid. - var otherRepeatedField = values as RepeatedField; - if (otherRepeatedField != null) - { - EnsureSize(count + otherRepeatedField.count); - Array.Copy(otherRepeatedField.array, 0, array, count, otherRepeatedField.count); - count += otherRepeatedField.count; - return; - } - - // Optimization 2: The collection is an ICollection, so we can expand - // just once and ask the collection to copy itself into the array. - var collection = values as ICollection; - if (collection != null) - { - var extraCount = collection.Count; - // For reference types and nullable value types, we need to check that there are no nulls - // present. (This isn't a thread-safe approach, but we don't advertise this is thread-safe.) - // We expect the JITter to optimize this test to true/false, so it's effectively conditional - // specialization. - if (default(T) == null) - { - // TODO: Measure whether iterating once to check and then letting the collection copy - // itself is faster or slower than iterating and adding as we go. For large - // collections this will not be great in terms of cache usage... but the optimized - // copy may be significantly faster than doing it one at a time. - foreach (var item in collection) - { - if (item == null) - { - throw new ArgumentException("Sequence contained null element", nameof(values)); - } - } - } - EnsureSize(count + extraCount); - collection.CopyTo(array, count); - count += extraCount; - return; - } - - // We *could* check for ICollection as well, but very very few collections implement - // ICollection but not ICollection. (HashSet does, for one...) - - // Fall back to a slower path of adding items one at a time. - foreach (T item in values) - { - Add(item); - } - } - - /// - /// Adds all of the specified values into this collection. This method is present to - /// allow repeated fields to be constructed from queries within collection initializers. - /// Within non-collection-initializer code, consider using the equivalent - /// method instead for clarity. - /// - /// The values to add to this collection. - public void Add(IEnumerable values) - { - AddRange(values); - } - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// An enumerator that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() - { - for (int i = 0; i < count; i++) - { - yield return array[i]; - } - } - - /// - /// Determines whether the specified , is equal to this instance. - /// - /// The to compare with this instance. - /// - /// true if the specified is equal to this instance; otherwise, false. - /// - public override bool Equals(object obj) - { - return Equals(obj as RepeatedField); - } - - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An object that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// Returns a hash code for this instance. - /// - /// - /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. - /// - public override int GetHashCode() - { - int hash = 0; - for (int i = 0; i < count; i++) - { - hash = hash * 31 + array[i].GetHashCode(); - } - return hash; - } - - /// - /// Compares this repeated field with another for equality. - /// - /// The repeated field to compare this with. - /// true if refers to an equal repeated field; false otherwise. - public bool Equals(RepeatedField other) - { - if (ReferenceEquals(other, null)) - { - return false; - } - if (ReferenceEquals(other, this)) - { - return true; - } - if (other.Count != this.Count) - { - return false; - } - EqualityComparer comparer = EqualityComparer; - for (int i = 0; i < count; i++) - { - if (!comparer.Equals(array[i], other.array[i])) - { - return false; - } - } - return true; - } - - /// - /// Returns the index of the given item within the collection, or -1 if the item is not - /// present. - /// - /// The item to find in the collection. - /// The zero-based index of the item, or -1 if it is not found. - public int IndexOf(T item) - { - ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item)); - EqualityComparer comparer = EqualityComparer; - for (int i = 0; i < count; i++) - { - if (comparer.Equals(array[i], item)) - { - return i; - } - } - return -1; - } - - /// - /// Inserts the given item at the specified index. - /// - /// The index at which to insert the item. - /// The item to insert. - public void Insert(int index, T item) - { - ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item)); - if (index < 0 || index > count) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - EnsureSize(count + 1); - Array.Copy(array, index, array, index + 1, count - index); - array[index] = item; - count++; - } - - /// - /// Removes the item at the given index. - /// - /// The zero-based index of the item to remove. - public void RemoveAt(int index) - { - if (index < 0 || index >= count) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - Array.Copy(array, index + 1, array, index, count - index - 1); - count--; - array[count] = default(T); - } - - /// - /// Returns a string representation of this repeated field, in the same - /// way as it would be represented by the default JSON formatter. - /// - public override string ToString() - { - var writer = new StringWriter(); - JsonFormatter.Default.WriteList(writer, this); - return writer.ToString(); - } - - /// - /// Gets or sets the item at the specified index. - /// - /// - /// The element at the specified index. - /// - /// The zero-based index of the element to get or set. - /// The item at the specified index. - public T this[int index] - { - get - { - if (index < 0 || index >= count) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - return array[index]; - } - set - { - if (index < 0 || index >= count) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value)); - array[index] = value; - } - } - - #region Explicit interface implementation for IList and ICollection. - bool IList.IsFixedSize => false; - - void ICollection.CopyTo(Array array, int index) - { - Array.Copy(this.array, 0, array, index, count); - } - - bool ICollection.IsSynchronized => false; - - object ICollection.SyncRoot => this; - - object IList.this[int index] - { - get { return this[index]; } - set { this[index] = (T)value; } - } - - int IList.Add(object value) - { - Add((T) value); - return count - 1; - } - - bool IList.Contains(object value) - { - return (value is T && Contains((T)value)); - } - - int IList.IndexOf(object value) - { - if (!(value is T)) - { - return -1; - } - return IndexOf((T)value); - } - - void IList.Insert(int index, object value) - { - Insert(index, (T) value); - } - - void IList.Remove(object value) - { - if (!(value is T)) - { - return; - } - Remove((T)value); - } - #endregion - } -} +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Security; +using System.Threading; + +namespace Google.Protobuf.Collections +{ + /// + /// The contents of a repeated field: essentially, a collection with some extra + /// restrictions (no null values) and capabilities (deep cloning). + /// + /// + /// This implementation does not generally prohibit the use of types which are not + /// supported by Protocol Buffers but nor does it guarantee that all operations will work in such cases. + /// + /// The element type of the repeated field. + public sealed class RepeatedField : IList, IList, IDeepCloneable>, IEquatable> +#if !NET35 + , IReadOnlyList +#endif + { + private static readonly EqualityComparer EqualityComparer = ProtobufEqualityComparers.GetEqualityComparer(); + private static readonly T[] EmptyArray = new T[0]; + private const int MinArraySize = 8; + + private T[] array = EmptyArray; + private int count = 0; + + /// + /// Creates a deep clone of this repeated field. + /// + /// + /// If the field type is + /// a message type, each element is also cloned; otherwise, it is + /// assumed that the field type is primitive (including string and + /// bytes, both of which are immutable) and so a simple copy is + /// equivalent to a deep clone. + /// + /// A deep clone of this repeated field. + public RepeatedField Clone() + { + RepeatedField clone = new RepeatedField(); + if (array != EmptyArray) + { + clone.array = (T[])array.Clone(); + IDeepCloneable[] cloneableArray = clone.array as IDeepCloneable[]; + if (cloneableArray != null) + { + for (int i = 0; i < count; i++) + { + clone.array[i] = cloneableArray[i].Clone(); + } + } + } + clone.count = count; + return clone; + } + + /// + /// Adds the entries from the given input stream, decoding them with the specified codec. + /// + /// The input stream to read from. + /// The codec to use in order to read each entry. + public void AddEntriesFrom(CodedInputStream input, FieldCodec codec) + { + ParseContext.Initialize(input, out ParseContext ctx); + try + { + AddEntriesFrom(ref ctx, codec); + } + finally + { + ctx.CopyStateTo(input); + } + } + + /// + /// Adds the entries from the given parse context, decoding them with the specified codec. + /// + /// The input to read from. + /// The codec to use in order to read each entry. + [SecuritySafeCritical] + public void AddEntriesFrom(ref ParseContext ctx, FieldCodec codec) + { + // TODO: Inline some of the Add code, so we can avoid checking the size on every + // iteration. + uint tag = ctx.state.lastTag; + var reader = codec.ValueReader; + // Non-nullable value types can be packed or not. + if (FieldCodec.IsPackedRepeatedField(tag)) + { + int length = ctx.ReadLength(); + if (length > 0) + { + int oldLimit = SegmentedBufferHelper.PushLimit(ref ctx.state, length); + + // If the content is fixed size then we can calculate the length + // of the repeated field and pre-initialize the underlying collection. + // + // Check that the supplied length doesn't exceed the underlying buffer. + // That prevents a malicious length from initializing a very large collection. + if (codec.FixedSize > 0 && length % codec.FixedSize == 0 && ParsingPrimitives.IsDataAvailable(ref ctx.state, length)) + { + EnsureSize(count + (length / codec.FixedSize)); + + while (!SegmentedBufferHelper.IsReachedLimit(ref ctx.state)) + { + // Only FieldCodecs with a fixed size can reach here, and they are all known + // types that don't allow the user to specify a custom reader action. + // reader action will never return null. + array[count++] = reader(ref ctx); + } + } + else + { + // Content is variable size so add until we reach the limit. + while (!SegmentedBufferHelper.IsReachedLimit(ref ctx.state)) + { + Add(reader(ref ctx)); + } + } + SegmentedBufferHelper.PopLimit(ref ctx.state, oldLimit); + } + // Empty packed field. Odd, but valid - just ignore. + } + else + { + // Not packed... (possibly not packable) + do + { + Add(reader(ref ctx)); + } while (ParsingPrimitives.MaybeConsumeTag(ref ctx.buffer, ref ctx.state, tag)); + } + } + + /// + /// Calculates the size of this collection based on the given codec. + /// + /// The codec to use when encoding each field. + /// The number of bytes that would be written to an output by one of the WriteTo methods, + /// using the same codec. + public int CalculateSize(FieldCodec codec) + { + if (count == 0) + { + return 0; + } + uint tag = codec.Tag; + if (codec.PackedRepeatedField) + { + int dataSize = CalculatePackedDataSize(codec); + return CodedOutputStream.ComputeRawVarint32Size(tag) + + CodedOutputStream.ComputeLengthSize(dataSize) + + dataSize; + } + else + { + var sizeCalculator = codec.ValueSizeCalculator; + int size = count * CodedOutputStream.ComputeRawVarint32Size(tag); + if (codec.EndTag != 0) + { + size += count * CodedOutputStream.ComputeRawVarint32Size(codec.EndTag); + } + for (int i = 0; i < count; i++) + { + size += sizeCalculator(array[i]); + } + return size; + } + } + + private int CalculatePackedDataSize(FieldCodec codec) + { + int fixedSize = codec.FixedSize; + if (fixedSize == 0) + { + var calculator = codec.ValueSizeCalculator; + int tmp = 0; + for (int i = 0; i < count; i++) + { + tmp += calculator(array[i]); + } + return tmp; + } + else + { + return fixedSize * Count; + } + } + + /// + /// Writes the contents of this collection to the given , + /// encoding each value using the specified codec. + /// + /// The output stream to write to. + /// The codec to use when encoding each value. + public void WriteTo(CodedOutputStream output, FieldCodec codec) + { + WriteContext.Initialize(output, out WriteContext ctx); + try + { + WriteTo(ref ctx, codec); + } + finally + { + ctx.CopyStateTo(output); + } + } + + /// + /// Writes the contents of this collection to the given write context, + /// encoding each value using the specified codec. + /// + /// The write context to write to. + /// The codec to use when encoding each value. + [SecuritySafeCritical] + public void WriteTo(ref WriteContext ctx, FieldCodec codec) + { + if (count == 0) + { + return; + } + var writer = codec.ValueWriter; + var tag = codec.Tag; + if (codec.PackedRepeatedField) + { + // Packed primitive type + int size = CalculatePackedDataSize(codec); + ctx.WriteTag(tag); + ctx.WriteLength(size); + for (int i = 0; i < count; i++) + { + writer(ref ctx, array[i]); + } + } + else + { + // Not packed: a simple tag/value pair for each value. + // Can't use codec.WriteTagAndValue, as that omits default values. + for (int i = 0; i < count; i++) + { + ctx.WriteTag(tag); + writer(ref ctx, array[i]); + if (codec.EndTag != 0) + { + ctx.WriteTag(codec.EndTag); + } + } + } + } + + /// + /// Gets and sets the capacity of the RepeatedField's internal array. WHen set, the internal array is reallocated to the given capacity. + /// The new value is less than Count -or- when Count is less than 0. + /// + public int Capacity + { + get { return array.Length; } + set + { + if (value < count) + { + throw new ArgumentOutOfRangeException("Capacity", value, + $"Cannot set Capacity to a value smaller than the current item count, {count}"); + } + + if (value >= 0 && value != array.Length) + { + SetSize(value); + } + } + } + + // May increase the size of the internal array, but will never shrink it. + private void EnsureSize(int size) + { + if (array.Length < size) + { + size = Math.Max(size, MinArraySize); + int newSize = Math.Max(array.Length * 2, size); + SetSize(newSize); + } + } + + // Sets the internal array to an exact size. + private void SetSize(int size) + { + if (size != array.Length) + { + var tmp = new T[size]; + Array.Copy(array, 0, tmp, 0, count); + array = tmp; + } + } + + /// + /// Adds the specified item to the collection. + /// + /// The item to add. + public void Add(T item) + { + ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item)); + EnsureSize(count + 1); + array[count++] = item; + } + + /// + /// Removes all items from the collection. + /// + public void Clear() + { + array = EmptyArray; + count = 0; + } + + /// + /// Determines whether this collection contains the given item. + /// + /// The item to find. + /// true if this collection contains the given item; false otherwise. + public bool Contains(T item) + { + return IndexOf(item) != -1; + } + + /// + /// Copies this collection to the given array. + /// + /// The array to copy to. + /// The first index of the array to copy to. + public void CopyTo(T[] array, int arrayIndex) + { + Array.Copy(this.array, 0, array, arrayIndex, count); + } + + /// + /// Removes the specified item from the collection + /// + /// The item to remove. + /// true if the item was found and removed; false otherwise. + public bool Remove(T item) + { + int index = IndexOf(item); + if (index == -1) + { + return false; + } + Array.Copy(array, index + 1, array, index, count - index - 1); + count--; + array[count] = default(T); + return true; + } + + /// + /// Gets the number of elements contained in the collection. + /// + public int Count => count; + + /// + /// Gets a value indicating whether the collection is read-only. + /// + public bool IsReadOnly => false; + + /// + /// Adds all of the specified values into this collection. + /// + /// The values to add to this collection. + public void AddRange(IEnumerable values) + { + ProtoPreconditions.CheckNotNull(values, nameof(values)); + + // Optimization 1: If the collection we're adding is already a RepeatedField, + // we know the values are valid. + var otherRepeatedField = values as RepeatedField; + if (otherRepeatedField != null) + { + EnsureSize(count + otherRepeatedField.count); + Array.Copy(otherRepeatedField.array, 0, array, count, otherRepeatedField.count); + count += otherRepeatedField.count; + return; + } + + // Optimization 2: The collection is an ICollection, so we can expand + // just once and ask the collection to copy itself into the array. + var collection = values as ICollection; + if (collection != null) + { + var extraCount = collection.Count; + // For reference types and nullable value types, we need to check that there are no nulls + // present. (This isn't a thread-safe approach, but we don't advertise this is thread-safe.) + // We expect the JITter to optimize this test to true/false, so it's effectively conditional + // specialization. + if (default(T) == null) + { + // TODO: Measure whether iterating once to check and then letting the collection copy + // itself is faster or slower than iterating and adding as we go. For large + // collections this will not be great in terms of cache usage... but the optimized + // copy may be significantly faster than doing it one at a time. + foreach (var item in collection) + { + if (item == null) + { + throw new ArgumentException("Sequence contained null element", nameof(values)); + } + } + } + EnsureSize(count + extraCount); + collection.CopyTo(array, count); + count += extraCount; + return; + } + + // We *could* check for ICollection as well, but very very few collections implement + // ICollection but not ICollection. (HashSet does, for one...) + + // Fall back to a slower path of adding items one at a time. + foreach (T item in values) + { + Add(item); + } + } + + /// + /// Adds all of the specified values into this collection. This method is present to + /// allow repeated fields to be constructed from queries within collection initializers. + /// Within non-collection-initializer code, consider using the equivalent + /// method instead for clarity. + /// + /// The values to add to this collection. + public void Add(IEnumerable values) + { + AddRange(values); + } + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// An enumerator that can be used to iterate through the collection. + /// + public IEnumerator GetEnumerator() + { + for (int i = 0; i < count; i++) + { + yield return array[i]; + } + } + + /// + /// Determines whether the specified , is equal to this instance. + /// + /// The to compare with this instance. + /// + /// true if the specified is equal to this instance; otherwise, false. + /// + public override bool Equals(object obj) + { + return Equals(obj as RepeatedField); + } + + /// + /// Returns an enumerator that iterates through a collection. + /// + /// + /// An object that can be used to iterate through the collection. + /// + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// + public override int GetHashCode() + { + int hash = 0; + for (int i = 0; i < count; i++) + { + hash = hash * 31 + array[i].GetHashCode(); + } + return hash; + } + + /// + /// Compares this repeated field with another for equality. + /// + /// The repeated field to compare this with. + /// true if refers to an equal repeated field; false otherwise. + public bool Equals(RepeatedField other) + { + if (ReferenceEquals(other, null)) + { + return false; + } + if (ReferenceEquals(other, this)) + { + return true; + } + if (other.Count != this.Count) + { + return false; + } + EqualityComparer comparer = EqualityComparer; + for (int i = 0; i < count; i++) + { + if (!comparer.Equals(array[i], other.array[i])) + { + return false; + } + } + return true; + } + + /// + /// Returns the index of the given item within the collection, or -1 if the item is not + /// present. + /// + /// The item to find in the collection. + /// The zero-based index of the item, or -1 if it is not found. + public int IndexOf(T item) + { + ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item)); + EqualityComparer comparer = EqualityComparer; + for (int i = 0; i < count; i++) + { + if (comparer.Equals(array[i], item)) + { + return i; + } + } + return -1; + } + + /// + /// Inserts the given item at the specified index. + /// + /// The index at which to insert the item. + /// The item to insert. + public void Insert(int index, T item) + { + ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item)); + if (index < 0 || index > count) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + EnsureSize(count + 1); + Array.Copy(array, index, array, index + 1, count - index); + array[index] = item; + count++; + } + + /// + /// Removes the item at the given index. + /// + /// The zero-based index of the item to remove. + public void RemoveAt(int index) + { + if (index < 0 || index >= count) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + Array.Copy(array, index + 1, array, index, count - index - 1); + count--; + array[count] = default(T); + } + + /// + /// Returns a string representation of this repeated field, in the same + /// way as it would be represented by the default JSON formatter. + /// + public override string ToString() + { + var writer = new StringWriter(); + JsonFormatter.Default.WriteList(writer, this); + return writer.ToString(); + } + + /// + /// Gets or sets the item at the specified index. + /// + /// + /// The element at the specified index. + /// + /// The zero-based index of the element to get or set. + /// The item at the specified index. + public T this[int index] + { + get + { + if (index < 0 || index >= count) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + return array[index]; + } + set + { + if (index < 0 || index >= count) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value)); + array[index] = value; + } + } + + #region Explicit interface implementation for IList and ICollection. + bool IList.IsFixedSize => false; + + void ICollection.CopyTo(Array array, int index) + { + Array.Copy(this.array, 0, array, index, count); + } + + bool ICollection.IsSynchronized => false; + + object ICollection.SyncRoot => this; + + object IList.this[int index] + { + get { return this[index]; } + set { this[index] = (T)value; } + } + + int IList.Add(object value) + { + Add((T) value); + return count - 1; + } + + bool IList.Contains(object value) + { + return (value is T && Contains((T)value)); + } + + int IList.IndexOf(object value) + { + if (!(value is T)) + { + return -1; + } + return IndexOf((T)value); + } + + void IList.Insert(int index, object value) + { + Insert(index, (T) value); + } + + void IList.Remove(object value) + { + if (!(value is T)) + { + return; + } + Remove((T)value); + } + #endregion + } +} diff --git a/csharp/src/Google.Protobuf/ExtensionSet.cs b/csharp/src/Google.Protobuf/ExtensionSet.cs index 4967ef646d3b..306e45e5fc05 100644 --- a/csharp/src/Google.Protobuf/ExtensionSet.cs +++ b/csharp/src/Google.Protobuf/ExtensionSet.cs @@ -1,428 +1,428 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using Google.Protobuf.Collections; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Security; - -namespace Google.Protobuf -{ - /// - /// Methods for managing s with null checking. - /// - /// Most users will not use this class directly and its API is experimental and subject to change. - /// - public static class ExtensionSet - { - private static bool TryGetValue(ref ExtensionSet set, Extension extension, out IExtensionValue value) where TTarget : IExtendableMessage - { - if (set == null) - { - value = null; - return false; - } - return set.ValuesByNumber.TryGetValue(extension.FieldNumber, out value); - } - - /// - /// Gets the value of the specified extension - /// - public static TValue Get(ref ExtensionSet set, Extension extension) where TTarget : IExtendableMessage - { - IExtensionValue value; - if (TryGetValue(ref set, extension, out value)) - { - // The stored ExtensionValue can be a different type to what is being requested. - // This happens when the same extension proto is compiled in different assemblies. - // To allow consuming assemblies to still get the value when the TValue type is - // different, this get method: - // 1. Attempts to cast the value to the expected ExtensionValue. - // This is the usual case. It is used first because it avoids possibly boxing the value. - // 2. Fallback to get the value as object from IExtensionValue then casting. - // This allows for someone to specify a TValue of object. They can then convert - // the values to bytes and reparse using expected value. - // 3. If neither of these work, throw a user friendly error that the types aren't compatible. - if (value is ExtensionValue extensionValue) - { - return extensionValue.GetValue(); - } - else if (value.GetValue() is TValue underlyingValue) - { - return underlyingValue; - } - else - { - var valueType = value.GetType().GetTypeInfo(); - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(ExtensionValue<>)) - { - var storedType = valueType.GenericTypeArguments[0]; - throw new InvalidOperationException( - "The stored extension value has a type of '" + storedType.AssemblyQualifiedName + "'. " + - "This a different from the requested type of '" + typeof(TValue).AssemblyQualifiedName + "'."); - } - else - { - throw new InvalidOperationException("Unexpected extension value type: " + valueType.AssemblyQualifiedName); - } - } - } - else - { - return extension.DefaultValue; - } - } - - /// - /// Gets the value of the specified repeated extension or null if it doesn't exist in this set - /// - public static RepeatedField Get(ref ExtensionSet set, RepeatedExtension extension) where TTarget : IExtendableMessage - { - IExtensionValue value; - if (TryGetValue(ref set, extension, out value)) - { - if (value is RepeatedExtensionValue extensionValue) - { - return extensionValue.GetValue(); - } - else - { - var valueType = value.GetType().GetTypeInfo(); - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(RepeatedExtensionValue<>)) - { - var storedType = valueType.GenericTypeArguments[0]; - throw new InvalidOperationException( - "The stored extension value has a type of '" + storedType.AssemblyQualifiedName + "'. " + - "This a different from the requested type of '" + typeof(TValue).AssemblyQualifiedName + "'."); - } - else - { - throw new InvalidOperationException("Unexpected extension value type: " + valueType.AssemblyQualifiedName); - } - } - } - else - { - return null; - } - } - - /// - /// Gets the value of the specified repeated extension, registering it if it doesn't exist - /// - public static RepeatedField GetOrInitialize(ref ExtensionSet set, RepeatedExtension extension) where TTarget : IExtendableMessage - { - IExtensionValue value; - if (set == null) - { - value = extension.CreateValue(); - set = new ExtensionSet(); - set.ValuesByNumber.Add(extension.FieldNumber, value); - } - else - { - if (!set.ValuesByNumber.TryGetValue(extension.FieldNumber, out value)) - { - value = extension.CreateValue(); - set.ValuesByNumber.Add(extension.FieldNumber, value); - } - } - - return ((RepeatedExtensionValue)value).GetValue(); - } - - /// - /// Sets the value of the specified extension. This will make a new instance of ExtensionSet if the set is null. - /// - public static void Set(ref ExtensionSet set, Extension extension, TValue value) where TTarget : IExtendableMessage - { - ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value)); - - IExtensionValue extensionValue; - if (set == null) - { - extensionValue = extension.CreateValue(); - set = new ExtensionSet(); - set.ValuesByNumber.Add(extension.FieldNumber, extensionValue); - } - else - { - if (!set.ValuesByNumber.TryGetValue(extension.FieldNumber, out extensionValue)) - { - extensionValue = extension.CreateValue(); - set.ValuesByNumber.Add(extension.FieldNumber, extensionValue); - } - } - - ((ExtensionValue)extensionValue).SetValue(value); - } - - /// - /// Gets whether the value of the specified extension is set - /// - public static bool Has(ref ExtensionSet set, Extension extension) where TTarget : IExtendableMessage - { - IExtensionValue value; - return TryGetValue(ref set, extension, out value); - } - - /// - /// Clears the value of the specified extension - /// - public static void Clear(ref ExtensionSet set, Extension extension) where TTarget : IExtendableMessage - { - if (set == null) - { - return; - } - set.ValuesByNumber.Remove(extension.FieldNumber); - if (set.ValuesByNumber.Count == 0) - { - set = null; - } - } - - /// - /// Clears the value of the specified extension - /// - public static void Clear(ref ExtensionSet set, RepeatedExtension extension) where TTarget : IExtendableMessage - { - if (set == null) - { - return; - } - set.ValuesByNumber.Remove(extension.FieldNumber); - if (set.ValuesByNumber.Count == 0) - { - set = null; - } - } - - /// - /// Tries to merge a field from the coded input, returning true if the field was merged. - /// If the set is null or the field was not otherwise merged, this returns false. - /// - public static bool TryMergeFieldFrom(ref ExtensionSet set, CodedInputStream stream) where TTarget : IExtendableMessage - { - ParseContext.Initialize(stream, out ParseContext ctx); - try - { - return TryMergeFieldFrom(ref set, ref ctx); - } - finally - { - ctx.CopyStateTo(stream); - } - } - - /// - /// Tries to merge a field from the coded input, returning true if the field was merged. - /// If the set is null or the field was not otherwise merged, this returns false. - /// - public static bool TryMergeFieldFrom(ref ExtensionSet set, ref ParseContext ctx) where TTarget : IExtendableMessage - { - Extension extension; - int lastFieldNumber = WireFormat.GetTagFieldNumber(ctx.LastTag); - - IExtensionValue extensionValue; - if (set != null && set.ValuesByNumber.TryGetValue(lastFieldNumber, out extensionValue)) - { - extensionValue.MergeFrom(ref ctx); - return true; - } - else if (ctx.ExtensionRegistry != null && ctx.ExtensionRegistry.ContainsInputField(ctx.LastTag, typeof(TTarget), out extension)) - { - IExtensionValue value = extension.CreateValue(); - value.MergeFrom(ref ctx); - set = (set ?? new ExtensionSet()); - set.ValuesByNumber.Add(extension.FieldNumber, value); - return true; - } - else - { - return false; - } - } - - /// - /// Merges the second set into the first set, creating a new instance if first is null - /// - public static void MergeFrom(ref ExtensionSet first, ExtensionSet second) where TTarget : IExtendableMessage - { - if (second == null) - { - return; - } - if (first == null) - { - first = new ExtensionSet(); - } - foreach (var pair in second.ValuesByNumber) - { - IExtensionValue value; - if (first.ValuesByNumber.TryGetValue(pair.Key, out value)) - { - value.MergeFrom(pair.Value); - } - else - { - var cloned = pair.Value.Clone(); - first.ValuesByNumber[pair.Key] = cloned; - } - } - } - - /// - /// Clones the set into a new set. If the set is null, this returns null - /// - public static ExtensionSet Clone(ExtensionSet set) where TTarget : IExtendableMessage - { - if (set == null) - { - return null; - } - - var newSet = new ExtensionSet(); - foreach (var pair in set.ValuesByNumber) - { - var cloned = pair.Value.Clone(); - newSet.ValuesByNumber[pair.Key] = cloned; - } - return newSet; - } - } - - /// - /// Used for keeping track of extensions in messages. - /// methods route to this set. - /// - /// Most users will not need to use this class directly - /// - /// The message type that extensions in this set target - public sealed class ExtensionSet where TTarget : IExtendableMessage - { - internal Dictionary ValuesByNumber { get; } = new Dictionary(); - - /// - /// Gets a hash code of the set - /// - public override int GetHashCode() - { - int ret = typeof(TTarget).GetHashCode(); - foreach (KeyValuePair field in ValuesByNumber) - { - // Use ^ here to make the field order irrelevant. - int hash = field.Key.GetHashCode() ^ field.Value.GetHashCode(); - ret ^= hash; - } - return ret; - } - - /// - /// Returns whether this set is equal to the other object - /// - public override bool Equals(object other) - { - if (ReferenceEquals(this, other)) - { - return true; - } - ExtensionSet otherSet = other as ExtensionSet; - if (ValuesByNumber.Count != otherSet.ValuesByNumber.Count) - { - return false; - } - foreach (var pair in ValuesByNumber) - { - IExtensionValue secondValue; - if (!otherSet.ValuesByNumber.TryGetValue(pair.Key, out secondValue)) - { - return false; - } - if (!pair.Value.Equals(secondValue)) - { - return false; - } - } - return true; - } - - /// - /// Calculates the size of this extension set - /// - public int CalculateSize() - { - int size = 0; - foreach (var value in ValuesByNumber.Values) - { - size += value.CalculateSize(); - } - return size; - } - - /// - /// Writes the extension values in this set to the output stream - /// - public void WriteTo(CodedOutputStream stream) - { - - WriteContext.Initialize(stream, out WriteContext ctx); - try - { - WriteTo(ref ctx); - } - finally - { - ctx.CopyStateTo(stream); - } - } - - /// - /// Writes the extension values in this set to the write context - /// - [SecuritySafeCritical] - public void WriteTo(ref WriteContext ctx) - { - foreach (var value in ValuesByNumber.Values) - { - value.WriteTo(ref ctx); - } - } - - internal bool IsInitialized() - { - return ValuesByNumber.Values.All(v => v.IsInitialized()); - } - } -} +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using Google.Protobuf.Collections; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Security; + +namespace Google.Protobuf +{ + /// + /// Methods for managing s with null checking. + /// + /// Most users will not use this class directly and its API is experimental and subject to change. + /// + public static class ExtensionSet + { + private static bool TryGetValue(ref ExtensionSet set, Extension extension, out IExtensionValue value) where TTarget : IExtendableMessage + { + if (set == null) + { + value = null; + return false; + } + return set.ValuesByNumber.TryGetValue(extension.FieldNumber, out value); + } + + /// + /// Gets the value of the specified extension + /// + public static TValue Get(ref ExtensionSet set, Extension extension) where TTarget : IExtendableMessage + { + IExtensionValue value; + if (TryGetValue(ref set, extension, out value)) + { + // The stored ExtensionValue can be a different type to what is being requested. + // This happens when the same extension proto is compiled in different assemblies. + // To allow consuming assemblies to still get the value when the TValue type is + // different, this get method: + // 1. Attempts to cast the value to the expected ExtensionValue. + // This is the usual case. It is used first because it avoids possibly boxing the value. + // 2. Fallback to get the value as object from IExtensionValue then casting. + // This allows for someone to specify a TValue of object. They can then convert + // the values to bytes and reparse using expected value. + // 3. If neither of these work, throw a user friendly error that the types aren't compatible. + if (value is ExtensionValue extensionValue) + { + return extensionValue.GetValue(); + } + else if (value.GetValue() is TValue underlyingValue) + { + return underlyingValue; + } + else + { + var valueType = value.GetType().GetTypeInfo(); + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(ExtensionValue<>)) + { + var storedType = valueType.GenericTypeArguments[0]; + throw new InvalidOperationException( + "The stored extension value has a type of '" + storedType.AssemblyQualifiedName + "'. " + + "This a different from the requested type of '" + typeof(TValue).AssemblyQualifiedName + "'."); + } + else + { + throw new InvalidOperationException("Unexpected extension value type: " + valueType.AssemblyQualifiedName); + } + } + } + else + { + return extension.DefaultValue; + } + } + + /// + /// Gets the value of the specified repeated extension or null if it doesn't exist in this set + /// + public static RepeatedField Get(ref ExtensionSet set, RepeatedExtension extension) where TTarget : IExtendableMessage + { + IExtensionValue value; + if (TryGetValue(ref set, extension, out value)) + { + if (value is RepeatedExtensionValue extensionValue) + { + return extensionValue.GetValue(); + } + else + { + var valueType = value.GetType().GetTypeInfo(); + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(RepeatedExtensionValue<>)) + { + var storedType = valueType.GenericTypeArguments[0]; + throw new InvalidOperationException( + "The stored extension value has a type of '" + storedType.AssemblyQualifiedName + "'. " + + "This a different from the requested type of '" + typeof(TValue).AssemblyQualifiedName + "'."); + } + else + { + throw new InvalidOperationException("Unexpected extension value type: " + valueType.AssemblyQualifiedName); + } + } + } + else + { + return null; + } + } + + /// + /// Gets the value of the specified repeated extension, registering it if it doesn't exist + /// + public static RepeatedField GetOrInitialize(ref ExtensionSet set, RepeatedExtension extension) where TTarget : IExtendableMessage + { + IExtensionValue value; + if (set == null) + { + value = extension.CreateValue(); + set = new ExtensionSet(); + set.ValuesByNumber.Add(extension.FieldNumber, value); + } + else + { + if (!set.ValuesByNumber.TryGetValue(extension.FieldNumber, out value)) + { + value = extension.CreateValue(); + set.ValuesByNumber.Add(extension.FieldNumber, value); + } + } + + return ((RepeatedExtensionValue)value).GetValue(); + } + + /// + /// Sets the value of the specified extension. This will make a new instance of ExtensionSet if the set is null. + /// + public static void Set(ref ExtensionSet set, Extension extension, TValue value) where TTarget : IExtendableMessage + { + ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value)); + + IExtensionValue extensionValue; + if (set == null) + { + extensionValue = extension.CreateValue(); + set = new ExtensionSet(); + set.ValuesByNumber.Add(extension.FieldNumber, extensionValue); + } + else + { + if (!set.ValuesByNumber.TryGetValue(extension.FieldNumber, out extensionValue)) + { + extensionValue = extension.CreateValue(); + set.ValuesByNumber.Add(extension.FieldNumber, extensionValue); + } + } + + ((ExtensionValue)extensionValue).SetValue(value); + } + + /// + /// Gets whether the value of the specified extension is set + /// + public static bool Has(ref ExtensionSet set, Extension extension) where TTarget : IExtendableMessage + { + IExtensionValue value; + return TryGetValue(ref set, extension, out value); + } + + /// + /// Clears the value of the specified extension + /// + public static void Clear(ref ExtensionSet set, Extension extension) where TTarget : IExtendableMessage + { + if (set == null) + { + return; + } + set.ValuesByNumber.Remove(extension.FieldNumber); + if (set.ValuesByNumber.Count == 0) + { + set = null; + } + } + + /// + /// Clears the value of the specified extension + /// + public static void Clear(ref ExtensionSet set, RepeatedExtension extension) where TTarget : IExtendableMessage + { + if (set == null) + { + return; + } + set.ValuesByNumber.Remove(extension.FieldNumber); + if (set.ValuesByNumber.Count == 0) + { + set = null; + } + } + + /// + /// Tries to merge a field from the coded input, returning true if the field was merged. + /// If the set is null or the field was not otherwise merged, this returns false. + /// + public static bool TryMergeFieldFrom(ref ExtensionSet set, CodedInputStream stream) where TTarget : IExtendableMessage + { + ParseContext.Initialize(stream, out ParseContext ctx); + try + { + return TryMergeFieldFrom(ref set, ref ctx); + } + finally + { + ctx.CopyStateTo(stream); + } + } + + /// + /// Tries to merge a field from the coded input, returning true if the field was merged. + /// If the set is null or the field was not otherwise merged, this returns false. + /// + public static bool TryMergeFieldFrom(ref ExtensionSet set, ref ParseContext ctx) where TTarget : IExtendableMessage + { + Extension extension; + int lastFieldNumber = WireFormat.GetTagFieldNumber(ctx.LastTag); + + IExtensionValue extensionValue; + if (set != null && set.ValuesByNumber.TryGetValue(lastFieldNumber, out extensionValue)) + { + extensionValue.MergeFrom(ref ctx); + return true; + } + else if (ctx.ExtensionRegistry != null && ctx.ExtensionRegistry.ContainsInputField(ctx.LastTag, typeof(TTarget), out extension)) + { + IExtensionValue value = extension.CreateValue(); + value.MergeFrom(ref ctx); + set = (set ?? new ExtensionSet()); + set.ValuesByNumber.Add(extension.FieldNumber, value); + return true; + } + else + { + return false; + } + } + + /// + /// Merges the second set into the first set, creating a new instance if first is null + /// + public static void MergeFrom(ref ExtensionSet first, ExtensionSet second) where TTarget : IExtendableMessage + { + if (second == null) + { + return; + } + if (first == null) + { + first = new ExtensionSet(); + } + foreach (var pair in second.ValuesByNumber) + { + IExtensionValue value; + if (first.ValuesByNumber.TryGetValue(pair.Key, out value)) + { + value.MergeFrom(pair.Value); + } + else + { + var cloned = pair.Value.Clone(); + first.ValuesByNumber[pair.Key] = cloned; + } + } + } + + /// + /// Clones the set into a new set. If the set is null, this returns null + /// + public static ExtensionSet Clone(ExtensionSet set) where TTarget : IExtendableMessage + { + if (set == null) + { + return null; + } + + var newSet = new ExtensionSet(); + foreach (var pair in set.ValuesByNumber) + { + var cloned = pair.Value.Clone(); + newSet.ValuesByNumber[pair.Key] = cloned; + } + return newSet; + } + } + + /// + /// Used for keeping track of extensions in messages. + /// methods route to this set. + /// + /// Most users will not need to use this class directly + /// + /// The message type that extensions in this set target + public sealed class ExtensionSet where TTarget : IExtendableMessage + { + internal Dictionary ValuesByNumber { get; } = new Dictionary(); + + /// + /// Gets a hash code of the set + /// + public override int GetHashCode() + { + int ret = typeof(TTarget).GetHashCode(); + foreach (KeyValuePair field in ValuesByNumber) + { + // Use ^ here to make the field order irrelevant. + int hash = field.Key.GetHashCode() ^ field.Value.GetHashCode(); + ret ^= hash; + } + return ret; + } + + /// + /// Returns whether this set is equal to the other object + /// + public override bool Equals(object other) + { + if (ReferenceEquals(this, other)) + { + return true; + } + ExtensionSet otherSet = other as ExtensionSet; + if (ValuesByNumber.Count != otherSet.ValuesByNumber.Count) + { + return false; + } + foreach (var pair in ValuesByNumber) + { + IExtensionValue secondValue; + if (!otherSet.ValuesByNumber.TryGetValue(pair.Key, out secondValue)) + { + return false; + } + if (!pair.Value.Equals(secondValue)) + { + return false; + } + } + return true; + } + + /// + /// Calculates the size of this extension set + /// + public int CalculateSize() + { + int size = 0; + foreach (var value in ValuesByNumber.Values) + { + size += value.CalculateSize(); + } + return size; + } + + /// + /// Writes the extension values in this set to the output stream + /// + public void WriteTo(CodedOutputStream stream) + { + + WriteContext.Initialize(stream, out WriteContext ctx); + try + { + WriteTo(ref ctx); + } + finally + { + ctx.CopyStateTo(stream); + } + } + + /// + /// Writes the extension values in this set to the write context + /// + [SecuritySafeCritical] + public void WriteTo(ref WriteContext ctx) + { + foreach (var value in ValuesByNumber.Values) + { + value.WriteTo(ref ctx); + } + } + + internal bool IsInitialized() + { + return ValuesByNumber.Values.All(v => v.IsInitialized()); + } + } +} diff --git a/csharp/src/Google.Protobuf/FrameworkPortability.cs b/csharp/src/Google.Protobuf/FrameworkPortability.cs index 9498dbe4ccc2..1606411b133f 100644 --- a/csharp/src/Google.Protobuf/FrameworkPortability.cs +++ b/csharp/src/Google.Protobuf/FrameworkPortability.cs @@ -1,49 +1,49 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.Text.RegularExpressions; - -namespace Google.Protobuf -{ - /// - /// Class containing helpful workarounds for various platform compatibility - /// - internal static class FrameworkPortability - { - // The value of RegexOptions.Compiled is 8. We can test for the presence at - // execution time using Enum.IsDefined, so a single build will do the right thing - // on each platform. (RegexOptions.Compiled isn't supported by PCLs.) - internal static readonly RegexOptions CompiledRegexWhereAvailable = - Enum.IsDefined(typeof(RegexOptions), 8) ? (RegexOptions)8 : RegexOptions.None; - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.Text.RegularExpressions; + +namespace Google.Protobuf +{ + /// + /// Class containing helpful workarounds for various platform compatibility + /// + internal static class FrameworkPortability + { + // The value of RegexOptions.Compiled is 8. We can test for the presence at + // execution time using Enum.IsDefined, so a single build will do the right thing + // on each platform. (RegexOptions.Compiled isn't supported by PCLs.) + internal static readonly RegexOptions CompiledRegexWhereAvailable = + Enum.IsDefined(typeof(RegexOptions), 8) ? (RegexOptions)8 : RegexOptions.None; + } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf/IMessage.cs b/csharp/src/Google.Protobuf/IMessage.cs index d089f9463985..3e644c177382 100644 --- a/csharp/src/Google.Protobuf/IMessage.cs +++ b/csharp/src/Google.Protobuf/IMessage.cs @@ -1,87 +1,87 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using Google.Protobuf.Reflection; - -namespace Google.Protobuf -{ - /// - /// Interface for a Protocol Buffers message, supporting - /// basic operations required for serialization. - /// - public interface IMessage - { - /// - /// Merges the data from the specified coded input stream with the current message. - /// - /// See the user guide for precise merge semantics. - /// - void MergeFrom(CodedInputStream input); - - /// - /// Writes the data to the given coded output stream. - /// - /// Coded output stream to write the data to. Must not be null. - void WriteTo(CodedOutputStream output); - - /// - /// Calculates the size of this message in Protocol Buffer wire format, in bytes. - /// - /// The number of bytes required to write this message - /// to a coded output stream. - int CalculateSize(); - - /// - /// Descriptor for this message. All instances are expected to return the same descriptor, - /// and for generated types this will be an explicitly-implemented member, returning the - /// same value as the static property declared on the type. - /// - MessageDescriptor Descriptor { get; } - } - - /// - /// Generic interface for a Protocol Buffers message, - /// where the type parameter is expected to be the same type as - /// the implementation class. - /// - /// The message type. - public interface IMessage : IMessage, IEquatable, IDeepCloneable where T : IMessage - { - /// - /// Merges the given message into this one. - /// - /// See the user guide for precise merge semantics. - /// The message to merge with this one. Must not be null. - void MergeFrom(T message); - } -} +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using Google.Protobuf.Reflection; + +namespace Google.Protobuf +{ + /// + /// Interface for a Protocol Buffers message, supporting + /// basic operations required for serialization. + /// + public interface IMessage + { + /// + /// Merges the data from the specified coded input stream with the current message. + /// + /// See the user guide for precise merge semantics. + /// + void MergeFrom(CodedInputStream input); + + /// + /// Writes the data to the given coded output stream. + /// + /// Coded output stream to write the data to. Must not be null. + void WriteTo(CodedOutputStream output); + + /// + /// Calculates the size of this message in Protocol Buffer wire format, in bytes. + /// + /// The number of bytes required to write this message + /// to a coded output stream. + int CalculateSize(); + + /// + /// Descriptor for this message. All instances are expected to return the same descriptor, + /// and for generated types this will be an explicitly-implemented member, returning the + /// same value as the static property declared on the type. + /// + MessageDescriptor Descriptor { get; } + } + + /// + /// Generic interface for a Protocol Buffers message, + /// where the type parameter is expected to be the same type as + /// the implementation class. + /// + /// The message type. + public interface IMessage : IMessage, IEquatable, IDeepCloneable where T : IMessage + { + /// + /// Merges the given message into this one. + /// + /// See the user guide for precise merge semantics. + /// The message to merge with this one. Must not be null. + void MergeFrom(T message); + } +} diff --git a/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs b/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs index c5ffe9bbf83d..6a3dbd6809b8 100644 --- a/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs +++ b/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs @@ -1,140 +1,140 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; -using System.IO; - -namespace Google.Protobuf -{ - /// - /// Thrown when a protocol message being parsed is invalid in some way, - /// e.g. it contains a malformed varint or a negative byte length. - /// - public sealed class InvalidProtocolBufferException : IOException - { - internal InvalidProtocolBufferException(string message) - : base(message) - { - } - - internal InvalidProtocolBufferException(string message, Exception innerException) - : base(message, innerException) - { - } - - internal static InvalidProtocolBufferException MoreDataAvailable() - { - return new InvalidProtocolBufferException( - "Completed reading a message while more data was available in the stream."); - } - - internal static InvalidProtocolBufferException TruncatedMessage() - { - return new InvalidProtocolBufferException( - "While parsing a protocol message, the input ended unexpectedly " + - "in the middle of a field. This could mean either that the " + - "input has been truncated or that an embedded message " + - "misreported its own length."); - } - - internal static InvalidProtocolBufferException NegativeSize() - { - return new InvalidProtocolBufferException( - "CodedInputStream encountered an embedded string or message " + - "which claimed to have negative size."); - } - - internal static InvalidProtocolBufferException MalformedVarint() - { - return new InvalidProtocolBufferException( - "CodedInputStream encountered a malformed varint."); - } - - /// - /// Creates an exception for an error condition of an invalid tag being encountered. - /// - internal static InvalidProtocolBufferException InvalidTag() - { - return new InvalidProtocolBufferException( - "Protocol message contained an invalid tag (zero)."); - } - - internal static InvalidProtocolBufferException InvalidWireType() - { - return new InvalidProtocolBufferException( - "Protocol message contained a tag with an invalid wire type."); - } - - internal static InvalidProtocolBufferException InvalidBase64(Exception innerException) - { - return new InvalidProtocolBufferException("Invalid base64 data", innerException); - } - - internal static InvalidProtocolBufferException InvalidEndTag() - { - return new InvalidProtocolBufferException( - "Protocol message end-group tag did not match expected tag."); - } - - internal static InvalidProtocolBufferException RecursionLimitExceeded() - { - return new InvalidProtocolBufferException( - "Protocol message had too many levels of nesting. May be malicious. " + - "Use CodedInputStream.SetRecursionLimit() to increase the depth limit."); - } - - internal static InvalidProtocolBufferException JsonRecursionLimitExceeded() - { - return new InvalidProtocolBufferException( - "Protocol message had too many levels of nesting. May be malicious. " + - "Use JsonParser.Settings to increase the depth limit."); - } - - internal static InvalidProtocolBufferException SizeLimitExceeded() - { - return new InvalidProtocolBufferException( - "Protocol message was too large. May be malicious. " + - "Use CodedInputStream.SetSizeLimit() to increase the size limit."); - } - - internal static InvalidProtocolBufferException InvalidMessageStreamTag() - { - return new InvalidProtocolBufferException( - "Stream of protocol messages had invalid tag. Expected tag is length-delimited field 1."); - } - - internal static InvalidProtocolBufferException MissingFields() - { - return new InvalidProtocolBufferException("Message was missing required fields"); - } -} +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.IO; + +namespace Google.Protobuf +{ + /// + /// Thrown when a protocol message being parsed is invalid in some way, + /// e.g. it contains a malformed varint or a negative byte length. + /// + public sealed class InvalidProtocolBufferException : IOException + { + internal InvalidProtocolBufferException(string message) + : base(message) + { + } + + internal InvalidProtocolBufferException(string message, Exception innerException) + : base(message, innerException) + { + } + + internal static InvalidProtocolBufferException MoreDataAvailable() + { + return new InvalidProtocolBufferException( + "Completed reading a message while more data was available in the stream."); + } + + internal static InvalidProtocolBufferException TruncatedMessage() + { + return new InvalidProtocolBufferException( + "While parsing a protocol message, the input ended unexpectedly " + + "in the middle of a field. This could mean either that the " + + "input has been truncated or that an embedded message " + + "misreported its own length."); + } + + internal static InvalidProtocolBufferException NegativeSize() + { + return new InvalidProtocolBufferException( + "CodedInputStream encountered an embedded string or message " + + "which claimed to have negative size."); + } + + internal static InvalidProtocolBufferException MalformedVarint() + { + return new InvalidProtocolBufferException( + "CodedInputStream encountered a malformed varint."); + } + + /// + /// Creates an exception for an error condition of an invalid tag being encountered. + /// + internal static InvalidProtocolBufferException InvalidTag() + { + return new InvalidProtocolBufferException( + "Protocol message contained an invalid tag (zero)."); + } + + internal static InvalidProtocolBufferException InvalidWireType() + { + return new InvalidProtocolBufferException( + "Protocol message contained a tag with an invalid wire type."); + } + + internal static InvalidProtocolBufferException InvalidBase64(Exception innerException) + { + return new InvalidProtocolBufferException("Invalid base64 data", innerException); + } + + internal static InvalidProtocolBufferException InvalidEndTag() + { + return new InvalidProtocolBufferException( + "Protocol message end-group tag did not match expected tag."); + } + + internal static InvalidProtocolBufferException RecursionLimitExceeded() + { + return new InvalidProtocolBufferException( + "Protocol message had too many levels of nesting. May be malicious. " + + "Use CodedInputStream.SetRecursionLimit() to increase the depth limit."); + } + + internal static InvalidProtocolBufferException JsonRecursionLimitExceeded() + { + return new InvalidProtocolBufferException( + "Protocol message had too many levels of nesting. May be malicious. " + + "Use JsonParser.Settings to increase the depth limit."); + } + + internal static InvalidProtocolBufferException SizeLimitExceeded() + { + return new InvalidProtocolBufferException( + "Protocol message was too large. May be malicious. " + + "Use CodedInputStream.SetSizeLimit() to increase the size limit."); + } + + internal static InvalidProtocolBufferException InvalidMessageStreamTag() + { + return new InvalidProtocolBufferException( + "Stream of protocol messages had invalid tag. Expected tag is length-delimited field 1."); + } + + internal static InvalidProtocolBufferException MissingFields() + { + return new InvalidProtocolBufferException("Message was missing required fields"); + } +} } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs index db7dc5c809bc..16f7c5a4e44a 100644 --- a/csharp/src/Google.Protobuf/JsonFormatter.cs +++ b/csharp/src/Google.Protobuf/JsonFormatter.cs @@ -1,4 +1,4 @@ -#region Copyright notice and license +#region Copyright notice and license // Protocol Buffers - Google's data interchange format // Copyright 2015 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ @@ -233,13 +233,13 @@ private bool WriteMessageFields(TextWriter writer, IMessage message, bool assume writer.Write(PropertySeparator); } - if (settings.PreserveProtoFieldNames) - { - WriteString(writer, accessor.Descriptor.Name); + if (settings.PreserveProtoFieldNames) + { + WriteString(writer, accessor.Descriptor.Name); } - else - { - WriteString(writer, accessor.Descriptor.JsonName); + else + { + WriteString(writer, accessor.Descriptor.JsonName); } writer.Write(NameValueSeparator); WriteValue(writer, value); @@ -823,8 +823,8 @@ static Settings() /// public bool FormatEnumsAsIntegers { get; } - /// - /// Whether to use the original proto field names as defined in the .proto file. Defaults to false. + /// + /// Whether to use the original proto field names as defined in the .proto file. Defaults to false. /// public bool PreserveProtoFieldNames { get; } @@ -884,9 +884,9 @@ private Settings(bool formatDefaultValues, /// true to format the enums as integers; false to format enums as enum names. public Settings WithFormatEnumsAsIntegers(bool formatEnumsAsIntegers) => new Settings(FormatDefaultValues, TypeRegistry, formatEnumsAsIntegers, PreserveProtoFieldNames); - /// - /// Creates a new object with the specified field name formatting option and the current settings. - /// + /// + /// Creates a new object with the specified field name formatting option and the current settings. + /// /// true to preserve proto field names; false to convert them to lowerCamelCase. public Settings WithPreserveProtoFieldNames(bool preserveProtoFieldNames) => new Settings(FormatDefaultValues, TypeRegistry, FormatEnumsAsIntegers, preserveProtoFieldNames); } diff --git a/csharp/src/Google.Protobuf/ObjectIntPair.cs b/csharp/src/Google.Protobuf/ObjectIntPair.cs index b98d93a517c4..b61fc6862f34 100644 --- a/csharp/src/Google.Protobuf/ObjectIntPair.cs +++ b/csharp/src/Google.Protobuf/ObjectIntPair.cs @@ -1,40 +1,40 @@ -using System; - -namespace Google.Protobuf -{ +using System; + +namespace Google.Protobuf +{ /// /// Struct used to hold the keys for the fieldByNumber table in DescriptorPool and the keys for the /// extensionByNumber table in ExtensionRegistry. - /// - internal struct ObjectIntPair : IEquatable> where T : class - { - private readonly int number; - private readonly T obj; - - internal ObjectIntPair(T obj, int number) - { - this.number = number; - this.obj = obj; - } - - public bool Equals(ObjectIntPair other) - { - return obj == other.obj - && number == other.number; - } - - public override bool Equals(object obj) - { - if (obj is ObjectIntPair) - { - return Equals((ObjectIntPair)obj); - } - return false; - } - - public override int GetHashCode() - { - return obj.GetHashCode() * ((1 << 16) - 1) + number; - } - } -} + /// + internal struct ObjectIntPair : IEquatable> where T : class + { + private readonly int number; + private readonly T obj; + + internal ObjectIntPair(T obj, int number) + { + this.number = number; + this.obj = obj; + } + + public bool Equals(ObjectIntPair other) + { + return obj == other.obj + && number == other.number; + } + + public override bool Equals(object obj) + { + if (obj is ObjectIntPair) + { + return Equals((ObjectIntPair)obj); + } + return false; + } + + public override int GetHashCode() + { + return obj.GetHashCode() * ((1 << 16) - 1) + number; + } + } +} diff --git a/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs b/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs index 130bcf00041d..4328e2e923d9 100644 --- a/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs +++ b/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs @@ -1,56 +1,56 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System.Runtime.CompilerServices; -using System.Security; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. - -#if !NCRUNCH -[assembly: AllowPartiallyTrustedCallers] -#endif - -[assembly: InternalsVisibleTo("Google.Protobuf.Test, PublicKey=" + - "002400000480000094000000060200000024000052534131000400000100010025800fbcfc63a1" + - "7c66b303aae80b03a6beaa176bb6bef883be436f2a1579edd80ce23edf151a1f4ced97af83abcd" + - "981207041fd5b2da3b498346fcfcd94910d52f25537c4a43ce3fbe17dc7d43e6cbdb4d8f1242dc" + - "b6bd9b5906be74da8daa7d7280f97130f318a16c07baf118839b156299a48522f9fae2371c9665" + - "c5ae9cb6")] - -[assembly: InternalsVisibleTo("Google.Protobuf.Benchmarks, PublicKey=" + - "002400000480000094000000060200000024000052534131000400000100010025800fbcfc63a1" + - "7c66b303aae80b03a6beaa176bb6bef883be436f2a1579edd80ce23edf151a1f4ced97af83abcd" + - "981207041fd5b2da3b498346fcfcd94910d52f25537c4a43ce3fbe17dc7d43e6cbdb4d8f1242dc" + - "b6bd9b5906be74da8daa7d7280f97130f318a16c07baf118839b156299a48522f9fae2371c9665" + - "c5ae9cb6")] +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System.Runtime.CompilerServices; +using System.Security; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. + +#if !NCRUNCH +[assembly: AllowPartiallyTrustedCallers] +#endif + +[assembly: InternalsVisibleTo("Google.Protobuf.Test, PublicKey=" + + "002400000480000094000000060200000024000052534131000400000100010025800fbcfc63a1" + + "7c66b303aae80b03a6beaa176bb6bef883be436f2a1579edd80ce23edf151a1f4ced97af83abcd" + + "981207041fd5b2da3b498346fcfcd94910d52f25537c4a43ce3fbe17dc7d43e6cbdb4d8f1242dc" + + "b6bd9b5906be74da8daa7d7280f97130f318a16c07baf118839b156299a48522f9fae2371c9665" + + "c5ae9cb6")] + +[assembly: InternalsVisibleTo("Google.Protobuf.Benchmarks, PublicKey=" + + "002400000480000094000000060200000024000052534131000400000100010025800fbcfc63a1" + + "7c66b303aae80b03a6beaa176bb6bef883be436f2a1579edd80ce23edf151a1f4ced97af83abcd" + + "981207041fd5b2da3b498346fcfcd94910d52f25537c4a43ce3fbe17dc7d43e6cbdb4d8f1242dc" + + "b6bd9b5906be74da8daa7d7280f97130f318a16c07baf118839b156299a48522f9fae2371c9665" + + "c5ae9cb6")] diff --git a/csharp/src/Google.Protobuf/ProtoPreconditions.cs b/csharp/src/Google.Protobuf/ProtoPreconditions.cs index 590a3bb20fc9..1814b8b7e9f3 100644 --- a/csharp/src/Google.Protobuf/ProtoPreconditions.cs +++ b/csharp/src/Google.Protobuf/ProtoPreconditions.cs @@ -1,79 +1,79 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -using System; - -namespace Google.Protobuf -{ - /// - /// Helper methods for throwing exceptions when preconditions are not met. - /// - /// - /// This class is used internally and by generated code; it is not particularly - /// expected to be used from application code, although nothing prevents it - /// from being used that way. - /// - public static class ProtoPreconditions - { - /// - /// Throws an ArgumentNullException if the given value is null, otherwise - /// return the value to the caller. - /// - public static T CheckNotNull(T value, string name) where T : class - { - if (value == null) - { - throw new ArgumentNullException(name); - } - return value; - } - - /// - /// Throws an ArgumentNullException if the given value is null, otherwise - /// return the value to the caller. - /// - /// - /// This is equivalent to but without the type parameter - /// constraint. In most cases, the constraint is useful to prevent you from calling CheckNotNull - /// with a value type - but it gets in the way if either you want to use it with a nullable - /// value type, or you want to use it with an unconstrained type parameter. - /// - internal static T CheckNotNullUnconstrained(T value, string name) - { - if (value == null) - { - throw new ArgumentNullException(name); - } - return value; - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; + +namespace Google.Protobuf +{ + /// + /// Helper methods for throwing exceptions when preconditions are not met. + /// + /// + /// This class is used internally and by generated code; it is not particularly + /// expected to be used from application code, although nothing prevents it + /// from being used that way. + /// + public static class ProtoPreconditions + { + /// + /// Throws an ArgumentNullException if the given value is null, otherwise + /// return the value to the caller. + /// + public static T CheckNotNull(T value, string name) where T : class + { + if (value == null) + { + throw new ArgumentNullException(name); + } + return value; + } + + /// + /// Throws an ArgumentNullException if the given value is null, otherwise + /// return the value to the caller. + /// + /// + /// This is equivalent to but without the type parameter + /// constraint. In most cases, the constraint is useful to prevent you from calling CheckNotNull + /// with a value type - but it gets in the way if either you want to use it with a nullable + /// value type, or you want to use it with an unconstrained type parameter. + /// + internal static T CheckNotNullUnconstrained(T value, string name) + { + if (value == null) + { + throw new ArgumentNullException(name); + } + return value; + } + } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs index 49f259982acb..5e7b6d5a1ee5 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs @@ -1,4 +1,4 @@ -#region Copyright notice and license +#region Copyright notice and license // Protocol Buffers - Google's data interchange format // Copyright 2015 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ @@ -67,15 +67,15 @@ public static string GetTypeName(string typeUrl) return lastSlash == -1 ? "" : typeUrl.Substring(lastSlash + 1); } - /// - /// Returns a bool indictating whether this Any message is of the target message type - /// - /// The descriptor of the message type + /// + /// Returns a bool indictating whether this Any message is of the target message type + /// + /// The descriptor of the message type /// true if the type name matches the descriptor's full name or false otherwise - public bool Is(MessageDescriptor descriptor) - { - ProtoPreconditions.CheckNotNull(descriptor, nameof(descriptor)); - return GetTypeName(TypeUrl) == descriptor.FullName; + public bool Is(MessageDescriptor descriptor) + { + ProtoPreconditions.CheckNotNull(descriptor, nameof(descriptor)); + return GetTypeName(TypeUrl) == descriptor.FullName; } /// diff --git a/csharp/src/Google.Protobuf/WireFormat.cs b/csharp/src/Google.Protobuf/WireFormat.cs index 201fd16e0d02..7cd2adab48ac 100644 --- a/csharp/src/Google.Protobuf/WireFormat.cs +++ b/csharp/src/Google.Protobuf/WireFormat.cs @@ -1,104 +1,104 @@ -#region Copyright notice and license -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Google.Protobuf -{ - /// - /// This class is used internally by the Protocol Buffer Library and generated - /// message implementations. It is public only for the sake of those generated - /// messages. Others should not use this class directly. - /// - /// This class contains constants and helper functions useful for dealing with - /// the Protocol Buffer wire format. - /// - /// - public static class WireFormat - { - /// - /// Wire types within protobuf encoding. - /// - public enum WireType : uint - { - /// - /// Variable-length integer. - /// - Varint = 0, - /// - /// A fixed-length 64-bit value. - /// - Fixed64 = 1, - /// - /// A length-delimited value, i.e. a length followed by that many bytes of data. - /// - LengthDelimited = 2, - /// - /// A "start group" value - /// - StartGroup = 3, - /// - /// An "end group" value - /// - EndGroup = 4, - /// - /// A fixed-length 32-bit value. - /// - Fixed32 = 5 - } - - private const int TagTypeBits = 3; - private const uint TagTypeMask = (1 << TagTypeBits) - 1; - - /// - /// Given a tag value, determines the wire type (lower 3 bits). - /// - public static WireType GetTagWireType(uint tag) - { - return (WireType) (tag & TagTypeMask); - } - - /// - /// Given a tag value, determines the field number (the upper 29 bits). - /// - public static int GetTagFieldNumber(uint tag) - { - return (int) (tag >> TagTypeBits); - } - - /// - /// Makes a tag value given a field number and wire type. - /// - public static uint MakeTag(int fieldNumber, WireType wireType) - { - return (uint) (fieldNumber << TagTypeBits) | (uint) wireType; - } - } +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +namespace Google.Protobuf +{ + /// + /// This class is used internally by the Protocol Buffer Library and generated + /// message implementations. It is public only for the sake of those generated + /// messages. Others should not use this class directly. + /// + /// This class contains constants and helper functions useful for dealing with + /// the Protocol Buffer wire format. + /// + /// + public static class WireFormat + { + /// + /// Wire types within protobuf encoding. + /// + public enum WireType : uint + { + /// + /// Variable-length integer. + /// + Varint = 0, + /// + /// A fixed-length 64-bit value. + /// + Fixed64 = 1, + /// + /// A length-delimited value, i.e. a length followed by that many bytes of data. + /// + LengthDelimited = 2, + /// + /// A "start group" value + /// + StartGroup = 3, + /// + /// An "end group" value + /// + EndGroup = 4, + /// + /// A fixed-length 32-bit value. + /// + Fixed32 = 5 + } + + private const int TagTypeBits = 3; + private const uint TagTypeMask = (1 << TagTypeBits) - 1; + + /// + /// Given a tag value, determines the wire type (lower 3 bits). + /// + public static WireType GetTagWireType(uint tag) + { + return (WireType) (tag & TagTypeMask); + } + + /// + /// Given a tag value, determines the field number (the upper 29 bits). + /// + public static int GetTagFieldNumber(uint tag) + { + return (int) (tag >> TagTypeBits); + } + + /// + /// Makes a tag value given a field number and wire type. + /// + public static uint MakeTag(int fieldNumber, WireType wireType) + { + return (uint) (fieldNumber << TagTypeBits) | (uint) wireType; + } + } } \ No newline at end of file From afb0ca40b3a1d9940a3022dac9df3bed68d6708d Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Mon, 28 Mar 2022 11:32:29 +0100 Subject: [PATCH 20/54] Change C# editor config to use LF by default --- csharp/.editorconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/csharp/.editorconfig b/csharp/.editorconfig index a59f5a597255..5e2afd0bee75 100644 --- a/csharp/.editorconfig +++ b/csharp/.editorconfig @@ -12,7 +12,6 @@ indent_style = space tab_width = 4 # New line preferences -# See https://github.com/protocolbuffers/protobuf/issues/9526 -#end_of_line = lf +end_of_line = lf insert_final_newline = false trim_trailing_whitespace = true \ No newline at end of file From 9f597a4c5976f4e435f54eca988bf6bccd3e3213 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Mon, 28 Mar 2022 11:38:50 +0100 Subject: [PATCH 21/54] Add regression test for https://github.com/protocolbuffers/protobuf/issues/9526 --- tests.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests.sh b/tests.sh index 73460fda3da0..a41f69fc6c59 100755 --- a/tests.sh +++ b/tests.sh @@ -165,6 +165,14 @@ build_csharp() { # Run csharp compatibility test between last released and the current version. csharp/compatibility_tests/v3.0.0/test.sh $LAST_RELEASED + + # Regression test for https://github.com/protocolbuffers/protobuf/issues/9526 + # - all line endings in .proto and .cs (and .csproj) files should be LF. + if git ls-files --eol csharp | grep -E '\.cs|\.proto' | grep -v w/lf + then + echo "The files listed above have mixed or CRLF line endings; please change to LF." + exit 1 + fi } build_golang() { From a3347c27a3e4f2263bf91d4a5fb5a5b28fba459e Mon Sep 17 00:00:00 2001 From: "David L. Jones" Date: Tue, 29 Mar 2022 11:48:16 -0700 Subject: [PATCH 22/54] Factor out test libraries in the cmake build. (#9689) This change adds separate libraries for common test utilities and test proto definitions, which are shared by different test targets. Without this change, cmake fails when generating Xcode files with the error: ``` CMake Error in CMakeLists.txt: The custom command generating .../protobuf/src/google/protobuf/unittest_lite.pb.cc is attached to multiple targets: tests lite-test lite-arena-test but none of these is a common dependency of the other(s). This is not allowed by the Xcode "new build system". ``` --- cmake/tests.cmake | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/cmake/tests.cmake b/cmake/tests.cmake index 75ad3a62ce87..28551f52c3a4 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -127,6 +127,9 @@ set(common_lite_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/test_util_lite.cc ) +add_library(protobuf-lite-test-common ${protobuf_SHARED_OR_STATIC} + ${common_lite_test_files} ${lite_test_proto_files}) + set(common_test_files ${common_lite_test_files} ${protobuf_SOURCE_DIR}/src/google/protobuf/map_test_util.inc @@ -137,6 +140,9 @@ set(common_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/testing/googletest.cc ) +add_library(protobuf-test-common ${protobuf_SHARED_OR_STATIC} + ${common_test_files} ${tests_proto_files}) + set(tests_files ${protobuf_SOURCE_DIR}/src/google/protobuf/any_test.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_unittest.cc @@ -233,13 +239,13 @@ if(MINGW) endif() -add_executable(tests ${tests_files} ${common_test_files} ${tests_proto_files} ${lite_test_proto_files}) +add_executable(tests ${tests_files}) if (MSVC) target_compile_options(tests PRIVATE /wd4146 # unary minus operator applied to unsigned type, result still unsigned ) endif() -target_link_libraries(tests libprotoc libprotobuf GTest::gmock_main) +target_link_libraries(tests protobuf-lite-test-common protobuf-test-common libprotoc libprotobuf GTest::gmock_main) set(test_plugin_files ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/mock_code_generator.cc @@ -254,14 +260,14 @@ target_link_libraries(test_plugin libprotoc libprotobuf GTest::gmock) set(lite_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/lite_unittest.cc ) -add_executable(lite-test ${lite_test_files} ${common_lite_test_files} ${lite_test_proto_files}) -target_link_libraries(lite-test libprotobuf-lite GTest::gmock_main) +add_executable(lite-test ${lite_test_files}) +target_link_libraries(lite-test protobuf-lite-test-common libprotobuf-lite GTest::gmock_main) set(lite_arena_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/lite_arena_unittest.cc ) -add_executable(lite-arena-test ${lite_arena_test_files} ${common_lite_test_files} ${lite_test_proto_files}) -target_link_libraries(lite-arena-test libprotobuf-lite GTest::gmock_main) +add_executable(lite-arena-test ${lite_arena_test_files}) +target_link_libraries(lite-arena-test protobuf-lite-test-common libprotobuf-lite GTest::gmock_main) add_custom_target(check COMMAND tests From 6b2627718b9121858e126d65e48a19d66c7707ed Mon Sep 17 00:00:00 2001 From: Jason Lunn Date: Tue, 29 Mar 2022 19:01:05 +0000 Subject: [PATCH 23/54] Add JRuby 9.3.4.0 to Dockerfile and use it for 9.3.x testing. --- kokoro/linux/dockerfile/test/ruby/Dockerfile | 1 + tests.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/kokoro/linux/dockerfile/test/ruby/Dockerfile b/kokoro/linux/dockerfile/test/ruby/Dockerfile index 914cd4b4b907..0e34fe55b9be 100644 --- a/kokoro/linux/dockerfile/test/ruby/Dockerfile +++ b/kokoro/linux/dockerfile/test/ruby/Dockerfile @@ -38,6 +38,7 @@ RUN /bin/bash -l -c "rvm install 3.0.0" RUN /bin/bash -l -c "rvm install 3.1.0" RUN /bin/bash -l -c "rvm install jruby-9.2.20.1" RUN /bin/bash -l -c "rvm install jruby-9.3.3.0" +RUN /bin/bash -l -c "rvm install jruby-9.3.4.0" RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc" RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc" diff --git a/tests.sh b/tests.sh index a41f69fc6c59..2b08a1eb7c52 100755 --- a/tests.sh +++ b/tests.sh @@ -444,7 +444,7 @@ build_jruby92() { build_jruby93() { internal_build_cpp # For conformance tests. internal_build_java jdk8 && cd .. # For Maven protobuf jar with local changes - cd ruby && bash travis-test.sh jruby-9.3.3.0 && cd .. + cd ruby && bash travis-test.sh jruby-9.3.4.0 && cd .. } build_javascript() { From faa42e900cad226eec6df2781336224d0b3ea5e7 Mon Sep 17 00:00:00 2001 From: Adam Cozzette Date: Tue, 29 Mar 2022 15:50:39 -0400 Subject: [PATCH 24/54] Revert "Use repo-relative labels wherever possible (#9187)" (#9696) This reverts commit 11de748d66a0b358b01c2ca1a03b6455b33f808b. --- protobuf.bzl | 10 +++++----- protobuf_deps.bzl | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/protobuf.bzl b/protobuf.bzl index ffd7c8df6748..8e173fd7d527 100644 --- a/protobuf.bzl +++ b/protobuf.bzl @@ -266,9 +266,9 @@ def cc_proto_library( deps = [], cc_libs = [], include = None, - protoc = Label("//:protoc"), + protoc = "@com_google_protobuf//:protoc", use_grpc_plugin = False, - default_runtime = Label("//:protobuf"), + default_runtime = "@com_google_protobuf//:protobuf", **kargs): """Bazel rule to create a C++ protobuf library from proto source files @@ -386,7 +386,7 @@ internal_gen_well_known_protos_java = rule( "_protoc": attr.label( executable = True, cfg = "exec", - default = "//:protoc", + default = "@com_google_protobuf//:protoc", ), }, ) @@ -493,8 +493,8 @@ def py_proto_library( py_libs = [], py_extra_srcs = [], include = None, - default_runtime = Label("//:protobuf_python"), - protoc = Label("//:protoc"), + default_runtime = "@com_google_protobuf//:protobuf_python", + protoc = "@com_google_protobuf//:protoc", use_grpc_plugin = False, **kargs): """Bazel rule to create a Python protobuf library from proto source files diff --git a/protobuf_deps.bzl b/protobuf_deps.bzl index 2bee1b763c66..54f8e2279e10 100644 --- a/protobuf_deps.bzl +++ b/protobuf_deps.bzl @@ -30,7 +30,7 @@ def protobuf_deps(): if not native.existing_rule("zlib"): http_archive( name = "zlib", - build_file = Label("//:third_party/zlib.BUILD"), + build_file = "@com_google_protobuf//:third_party/zlib.BUILD", sha256 = "629380c90a77b964d896ed37163f5c3a34f6e6d897311f1df2a7016355c45eff", strip_prefix = "zlib-1.2.11", urls = ["https://github.com/madler/zlib/archive/v1.2.11.tar.gz"], From 520c601c99012101c816b6ccc89e8d6fc28fdbb8 Mon Sep 17 00:00:00 2001 From: "David L. Jones" Date: Tue, 29 Mar 2022 14:32:10 -0700 Subject: [PATCH 25/54] Temporary Kokoro build for macos-next. (#9693) This build will be used to troubleshoot building on a newer macOS image. Once it is stable, this config will replace the "macos" build. --- kokoro/macos-next/README.md | 4 ++++ kokoro/macos-next/cpp/build.sh | 36 ++++++++++++++++++++++++++++ kokoro/macos-next/cpp/continuous.cfg | 13 ++++++++++ kokoro/macos-next/cpp/presubmit.cfg | 13 ++++++++++ 4 files changed, 66 insertions(+) create mode 100644 kokoro/macos-next/README.md create mode 100755 kokoro/macos-next/cpp/build.sh create mode 100644 kokoro/macos-next/cpp/continuous.cfg create mode 100644 kokoro/macos-next/cpp/presubmit.cfg diff --git a/kokoro/macos-next/README.md b/kokoro/macos-next/README.md new file mode 100644 index 000000000000..46578556f517 --- /dev/null +++ b/kokoro/macos-next/README.md @@ -0,0 +1,4 @@ +# macOS-next + +This builder is temporary for developing and testing builds using the "next" +macOS version without affecting the ordinary builds. diff --git a/kokoro/macos-next/cpp/build.sh b/kokoro/macos-next/cpp/build.sh new file mode 100755 index 000000000000..67466ccca1e5 --- /dev/null +++ b/kokoro/macos-next/cpp/build.sh @@ -0,0 +1,36 @@ +#!/bin/bash -ex +# +# Build file to set up and run tests + +# NOTE: in order to avoid blocking anyone, this job always succeeds for now. +exit 0 + +# Set up artifact output location +: ${KOKORO_ARTIFACTS_DIR:=/tmp/kokoro_artifacts} +: ${BUILD_LOGDIR:=$KOKORO_ARTIFACTS_DIR/logs} +mkdir -p ${BUILD_LOGDIR} + +# Change to repo root +cd $(dirname $0)/../../.. + +# Update submodules +git submodule update --init --recursive + +# Build in a separate directory +mkdir -p cmake/build +cd cmake/build + +# Print some basic info +xcode-select --print-path +xcodebuild -version +xcrun --show-sdk-path + +# Build everything first +cmake -G Xcode ../.. \ + 2>&1 | tee ${BUILD_LOGDIR}/00_configure_sponge_log.log +cmake --build . --config Debug \ + 2>&1 | tee ${BUILD_LOGDIR}/01_build_sponge_log.log + +# Run tests +ctest -C Debug --verbose --quiet \ + --output-log ${BUILD_LOGDIR}/02_test_sponge_log.log diff --git a/kokoro/macos-next/cpp/continuous.cfg b/kokoro/macos-next/cpp/continuous.cfg new file mode 100644 index 000000000000..32f1b1da5ae9 --- /dev/null +++ b/kokoro/macos-next/cpp/continuous.cfg @@ -0,0 +1,13 @@ +# Config file for running tests in Kokoro + +# Location of the build script in repository +build_file: "protobuf/kokoro/macos-next/cpp/build.sh" +timeout_mins: 1440 + +# Upload logs +action: { + define_artifacts: { + regex: "protobuf/cmake/build/**/*sponge_log.log" + regex: "protobuf/cmake/build/**/*sponge_log.xml" + } +} diff --git a/kokoro/macos-next/cpp/presubmit.cfg b/kokoro/macos-next/cpp/presubmit.cfg new file mode 100644 index 000000000000..32f1b1da5ae9 --- /dev/null +++ b/kokoro/macos-next/cpp/presubmit.cfg @@ -0,0 +1,13 @@ +# Config file for running tests in Kokoro + +# Location of the build script in repository +build_file: "protobuf/kokoro/macos-next/cpp/build.sh" +timeout_mins: 1440 + +# Upload logs +action: { + define_artifacts: { + regex: "protobuf/cmake/build/**/*sponge_log.log" + regex: "protobuf/cmake/build/**/*sponge_log.xml" + } +} From d7ef9cd2ba32ab0fd7a39a1c0dac70352bc8b700 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Wed, 16 Mar 2022 12:29:42 +0000 Subject: [PATCH 26/54] Make it easier to follow cmake/README.md instructions When following the instructions directly (for developing on Windows) we should end up with a generator that's easy to run for csharp/generate_protos.sh, and we shouldn't end up trying to stage the build output. --- .gitignore | 4 ++++ csharp/generate_protos.sh | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8afb522dae7d..8b764964d43f 100644 --- a/.gitignore +++ b/.gitignore @@ -89,6 +89,10 @@ java/**/*.iml # Windows native output. cmake/build build_msvc +# Directories suggested by cmake/README.md +/debug/ +/solution/ +/release/ # NuGet packages: we want the repository configuration, but not the # packages themselves. diff --git a/csharp/generate_protos.sh b/csharp/generate_protos.sh index b663138d1087..b021de2acad4 100755 --- a/csharp/generate_protos.sh +++ b/csharp/generate_protos.sh @@ -13,7 +13,9 @@ pushd $(dirname $0)/.. # Windows and Unix. if [ -z "$PROTOC" ]; then # TODO(jonskeet): Use an array and a for loop instead? - if [ -x cmake/build/Debug/protoc.exe ]; then + if [ -x solution/Debug/protoc.exe ]; then + PROTOC=solution/Debug/protoc.exe + elif [ -x cmake/build/Debug/protoc.exe ]; then PROTOC=cmake/build/Debug/protoc.exe elif [ -x cmake/build/Release/protoc.exe ]; then PROTOC=cmake/build/Release/protoc.exe From 81c5e1a712f09cd8995cebbc99c4e261d6a8d8c6 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Wed, 16 Mar 2022 12:32:13 +0000 Subject: [PATCH 27/54] C# generator: Append _ to the oneof case enum name if it's "None" Fixes #9605 (tests in next commit) --- .../protobuf/compiler/csharp/csharp_enum_field.cc | 2 +- .../protobuf/compiler/csharp/csharp_field_base.cc | 7 ++++++- .../protobuf/compiler/csharp/csharp_field_base.h | 1 + .../protobuf/compiler/csharp/csharp_helpers.cc | 7 +++++++ src/google/protobuf/compiler/csharp/csharp_helpers.h | 2 ++ .../protobuf/compiler/csharp/csharp_message.cc | 12 ++++++------ .../protobuf/compiler/csharp/csharp_message_field.cc | 4 ++-- .../compiler/csharp/csharp_primitive_field.cc | 4 ++-- .../protobuf/compiler/csharp/csharp_wrapper_field.cc | 4 ++-- 9 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc index 186fa27e5b36..55fb60c504a3 100644 --- a/src/google/protobuf/compiler/csharp/csharp_enum_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc @@ -109,7 +109,7 @@ void EnumOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) { printer->Print( variables_, "$oneof_name$_ = input.ReadEnum();\n" - "$oneof_name$Case_ = $oneof_property_name$OneofCase.$property_name$;\n"); + "$oneof_name$Case_ = $oneof_property_name$OneofCase.$oneof_case_name$;\n"); } void EnumOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer) { diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.cc b/src/google/protobuf/compiler/csharp/csharp_field_base.cc index 146ca9e5bde1..17847e36c99c 100644 --- a/src/google/protobuf/compiler/csharp/csharp_field_base.cc +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc @@ -130,8 +130,9 @@ void FieldGeneratorBase::SetCommonOneofFieldVariables( } else { (*variables)["has_property_check"] = oneof_name() + "Case_ == " + oneof_property_name() + - "OneofCase." + property_name(); + "OneofCase." + oneof_case_name(); } + (*variables)["oneof_case_name"] = oneof_case_name(); (*variables)["oneof_property_name"] = oneof_property_name(); } @@ -187,6 +188,10 @@ void FieldGeneratorBase::AddPublicMemberAttributes(io::Printer* printer) { WriteGeneratedCodeAttributes(printer); } +std::string FieldGeneratorBase::oneof_case_name() { + return GetOneofCaseName(descriptor_); +} + std::string FieldGeneratorBase::oneof_property_name() { return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), true); } diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.h b/src/google/protobuf/compiler/csharp/csharp_field_base.h index f875fa11ace4..c7b7469b99a5 100644 --- a/src/google/protobuf/compiler/csharp/csharp_field_base.h +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.h @@ -85,6 +85,7 @@ class FieldGeneratorBase : public SourceGeneratorBase { std::map* variables); std::string oneof_property_name(); + std::string oneof_case_name(); std::string oneof_name(); std::string property_name(); std::string name(); diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.cc b/src/google/protobuf/compiler/csharp/csharp_helpers.cc index 32ef3994f16e..73ca86805c12 100644 --- a/src/google/protobuf/compiler/csharp/csharp_helpers.cc +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc @@ -393,6 +393,13 @@ std::string GetPropertyName(const FieldDescriptor* descriptor) { return property_name; } +std::string GetOneofCaseName(const FieldDescriptor* descriptor) { + // The name in a oneof case enum is the same as for the property, but as we always have a "None" + // value as well, we need to reserve that by appending an underscore. + std::string property_name = GetPropertyName(descriptor); + return property_name == "None" ? "None_" : property_name; +} + std::string GetOutputFile(const FileDescriptor* descriptor, const std::string file_extension, const bool generate_directories, diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.h b/src/google/protobuf/compiler/csharp/csharp_helpers.h index 619e7dba3ab6..836bd5de5ed6 100644 --- a/src/google/protobuf/compiler/csharp/csharp_helpers.h +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h @@ -87,6 +87,8 @@ std::string GetFieldConstantName(const FieldDescriptor* field); std::string GetPropertyName(const FieldDescriptor* descriptor); +std::string GetOneofCaseName(const FieldDescriptor* descriptor); + int GetFixedSize(FieldDescriptor::Type type); std::string UnderscoresToCamelCase(const std::string& input, diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc index 9dbce03c0252..a119bddeeef1 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message.cc @@ -238,8 +238,8 @@ void MessageGenerator::Generate(io::Printer* printer) { printer->Print("None = 0,\n"); for (int j = 0; j < oneof->field_count(); j++) { const FieldDescriptor* field = oneof->field(j); - printer->Print("$field_property_name$ = $index$,\n", - "field_property_name", GetPropertyName(field), + printer->Print("$oneof_case_name$ = $index$,\n", + "oneof_case_name", GetOneofCaseName(field), "index", StrCat(field->number())); } printer->Outdent(); @@ -403,10 +403,10 @@ void MessageGenerator::GenerateCloningCode(io::Printer* printer) { for (int j = 0; j < oneof->field_count(); j++) { const FieldDescriptor* field = oneof->field(j); std::unique_ptr generator(CreateFieldGeneratorInternal(field)); - vars["field_property_name"] = GetPropertyName(field); + vars["oneof_case_name"] = GetOneofCaseName(field); printer->Print( vars, - "case $property_name$OneofCase.$field_property_name$:\n"); + "case $property_name$OneofCase.$oneof_case_name$:\n"); printer->Indent(); generator->GenerateCloningCode(printer); printer->Print("break;\n"); @@ -635,10 +635,10 @@ void MessageGenerator::GenerateMergingMethods(io::Printer* printer) { printer->Indent(); for (int j = 0; j < oneof->field_count(); j++) { const FieldDescriptor* field = oneof->field(j); - vars["field_property_name"] = GetPropertyName(field); + vars["oneof_case_name"] = GetOneofCaseName(field); printer->Print( vars, - "case $property_name$OneofCase.$field_property_name$:\n"); + "case $property_name$OneofCase.$oneof_case_name$:\n"); printer->Indent(); std::unique_ptr generator(CreateFieldGeneratorInternal(field)); generator->GenerateMergingCode(printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_message_field.cc index 034fbd924270..487d01ddef34 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.cc @@ -225,7 +225,7 @@ void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) { " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : null; }\n" " set {\n" " $oneof_name$_ = value;\n" - " $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$property_name$;\n" + " $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$oneof_case_name$;\n" " }\n" "}\n"); if (SupportsPresenceApi(descriptor_)) { @@ -236,7 +236,7 @@ void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) { printer->Print( variables_, "$access_level$ bool Has$property_name$ {\n" - " get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$property_name$; }\n" + " get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$oneof_case_name$; }\n" "}\n"); printer->Print( variables_, diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc index 9df1dd6abd73..e7d51168d173 100644 --- a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc @@ -296,7 +296,7 @@ void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) { } printer->Print( variables_, - " $oneof_name$Case_ = $oneof_property_name$OneofCase.$property_name$;\n" + " $oneof_name$Case_ = $oneof_property_name$OneofCase.$oneof_case_name$;\n" " }\n" "}\n"); if (SupportsPresenceApi(descriptor_)) { @@ -307,7 +307,7 @@ void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) { printer->Print( variables_, "$access_level$ bool Has$property_name$ {\n" - " get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$property_name$; }\n" + " get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$oneof_case_name$; }\n" "}\n"); printer->Print( variables_, diff --git a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc index 578f54ba697e..e638dd862aef 100644 --- a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc @@ -233,7 +233,7 @@ void WrapperOneofFieldGenerator::GenerateMembers(io::Printer* printer) { " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : ($type_name$) null; }\n" " set {\n" " $oneof_name$_ = value;\n" - " $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$property_name$;\n" + " $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$oneof_case_name$;\n" " }\n" "}\n"); if (SupportsPresenceApi(descriptor_)) { @@ -244,7 +244,7 @@ void WrapperOneofFieldGenerator::GenerateMembers(io::Printer* printer) { printer->Print( variables_, "$access_level$ bool Has$property_name$ {\n" - " get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$property_name$; }\n" + " get { return $oneof_name$Case_ == $oneof_property_name$OneofCase.$oneof_case_name$; }\n" "}\n"); printer->Print( variables_, From e2f845b2f19bd78ce1c69453452ae5645895e4fc Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Wed, 16 Mar 2022 12:33:40 +0000 Subject: [PATCH 28/54] Test proto and unit test for issue #9605 This doesn't test *all* possibilities (e.g. the field being a wrapper, or a message field, etc) - but I'm fairly confident that I found all the places referring to the case. --- csharp/protos/unittest_issues.proto | 14 ++++++++++++++ csharp/src/Google.Protobuf.Test/IssuesTest.cs | 16 ++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/csharp/protos/unittest_issues.proto b/csharp/protos/unittest_issues.proto index 388998f0a0ea..f46c20e4da1f 100644 --- a/csharp/protos/unittest_issues.proto +++ b/csharp/protos/unittest_issues.proto @@ -156,3 +156,17 @@ message MixedRegularAndOptional { string regular_field = 1; optional string optional_field = 2; } + +message OneofWithNoneField { + oneof test { + string x = 1; + string none = 2; + } +} + +message OneofWithNoneName { + oneof none { + string x = 1; + string y = 2; + } +} \ No newline at end of file diff --git a/csharp/src/Google.Protobuf.Test/IssuesTest.cs b/csharp/src/Google.Protobuf.Test/IssuesTest.cs index a46467ca0707..695398918b20 100644 --- a/csharp/src/Google.Protobuf.Test/IssuesTest.cs +++ b/csharp/src/Google.Protobuf.Test/IssuesTest.cs @@ -112,5 +112,21 @@ public void CodedInputStream_LimitReachedRightAfterTag() // See https://github.com/protocolbuffers/protobuf/pull/7289 cis.AssertNextTag(WireFormat.MakeTag(11, WireFormat.WireType.Varint)); } + + [Test] + public void NoneFieldInOneof() + { + var message = new OneofWithNoneField(); + var emptyHashCode = message.GetHashCode(); + Assert.AreEqual(OneofWithNoneField.TestOneofCase.None, message.TestCase); + message.None = "test"; + Assert.AreEqual(OneofWithNoneField.TestOneofCase.None_, message.TestCase); + Assert.AreNotEqual(emptyHashCode, message.GetHashCode()); + + var bytes = message.ToByteArray(); + var parsed = OneofWithNoneField.Parser.ParseFrom(bytes); + Assert.AreEqual(message, parsed); + Assert.AreEqual("test", parsed.None); + } } } From 9e6e4eb4256d26d11c728da8ad6979f03d432c96 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Wed, 16 Mar 2022 12:33:58 +0000 Subject: [PATCH 29/54] Generated code for test protos for issue #9605 --- .../UnittestIssues.cs | 534 +++++++++++++++++- csharp/src/Google.Protobuf.Test/testprotos.pb | Bin 343757 -> 344238 bytes 2 files changed, 528 insertions(+), 6 deletions(-) diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/UnittestIssues.cs b/csharp/src/Google.Protobuf.Test.TestProtos/UnittestIssues.cs index ec4c07b112ff..3440105514f3 100644 --- a/csharp/src/Google.Protobuf.Test.TestProtos/UnittestIssues.cs +++ b/csharp/src/Google.Protobuf.Test.TestProtos/UnittestIssues.cs @@ -54,11 +54,13 @@ static UnittestIssuesReflection() { "dEluT25lb2YSLgoKbnVsbF92YWx1ZRgCIAEoDjIaLmdvb2dsZS5wcm90b2J1", "Zi5OdWxsVmFsdWUiYAoXTWl4ZWRSZWd1bGFyQW5kT3B0aW9uYWwSFQoNcmVn", "dWxhcl9maWVsZBgBIAEoCRIbCg5vcHRpb25hbF9maWVsZBgCIAEoCUgAiAEB", - "QhEKD19vcHRpb25hbF9maWVsZCpVCgxOZWdhdGl2ZUVudW0SFgoSTkVHQVRJ", - "VkVfRU5VTV9aRVJPEAASFgoJRml2ZUJlbG93EPv//////////wESFQoITWlu", - "dXNPbmUQ////////////ASouCg5EZXByZWNhdGVkRW51bRITCg9ERVBSRUNB", - "VEVEX1pFUk8QABIHCgNvbmUQAUIdqgIaVW5pdFRlc3QuSXNzdWVzLlRlc3RQ", - "cm90b3NiBnByb3RvMw==")); + "QhEKD19vcHRpb25hbF9maWVsZCI5ChJPbmVvZldpdGhOb25lRmllbGQSCwoB", + "eBgBIAEoCUgAEg4KBG5vbmUYAiABKAlIAEIGCgR0ZXN0IjUKEU9uZW9mV2l0", + "aE5vbmVOYW1lEgsKAXgYASABKAlIABILCgF5GAIgASgJSABCBgoEbm9uZSpV", + "CgxOZWdhdGl2ZUVudW0SFgoSTkVHQVRJVkVfRU5VTV9aRVJPEAASFgoJRml2", + "ZUJlbG93EPv//////////wESFQoITWludXNPbmUQ////////////ASouCg5E", + "ZXByZWNhdGVkRW51bRITCg9ERVBSRUNBVEVEX1pFUk8QABIHCgNvbmUQAUId", + "qgIaVW5pdFRlc3QuSXNzdWVzLlRlc3RQcm90b3NiBnByb3RvMw==")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor, }, new pbr::GeneratedClrTypeInfo(new[] {typeof(global::UnitTest.Issues.TestProtos.NegativeEnum), typeof(global::UnitTest.Issues.TestProtos.DeprecatedEnum), }, null, new pbr::GeneratedClrTypeInfo[] { @@ -73,7 +75,9 @@ static UnittestIssuesReflection() { new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.OneofMerging), global::UnitTest.Issues.TestProtos.OneofMerging.Parser, new[]{ "Text", "Nested" }, new[]{ "Value" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.OneofMerging.Types.Nested), global::UnitTest.Issues.TestProtos.OneofMerging.Types.Nested.Parser, new[]{ "X", "Y" }, null, null, null, null)}), new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.NullValueOutsideStruct), global::UnitTest.Issues.TestProtos.NullValueOutsideStruct.Parser, new[]{ "StringValue", "NullValue" }, new[]{ "Value" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.NullValueNotInOneof), global::UnitTest.Issues.TestProtos.NullValueNotInOneof.Parser, new[]{ "NullValue" }, null, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.MixedRegularAndOptional), global::UnitTest.Issues.TestProtos.MixedRegularAndOptional.Parser, new[]{ "RegularField", "OptionalField" }, new[]{ "OptionalField" }, null, null, null) + new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.MixedRegularAndOptional), global::UnitTest.Issues.TestProtos.MixedRegularAndOptional.Parser, new[]{ "RegularField", "OptionalField" }, new[]{ "OptionalField" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.OneofWithNoneField), global::UnitTest.Issues.TestProtos.OneofWithNoneField.Parser, new[]{ "X", "None" }, new[]{ "Test" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.OneofWithNoneName), global::UnitTest.Issues.TestProtos.OneofWithNoneName.Parser, new[]{ "X", "Y" }, new[]{ "None" }, null, null, null) })); } #endregion @@ -3825,6 +3829,524 @@ public void MergeFrom(pb::CodedInputStream input) { } + public sealed partial class OneofWithNoneField : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new OneofWithNoneField()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[12]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public OneofWithNoneField() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public OneofWithNoneField(OneofWithNoneField other) : this() { + switch (other.TestCase) { + case TestOneofCase.X: + X = other.X; + break; + case TestOneofCase.None_: + None = other.None; + break; + } + + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public OneofWithNoneField Clone() { + return new OneofWithNoneField(this); + } + + /// Field number for the "x" field. + public const int XFieldNumber = 1; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string X { + get { return testCase_ == TestOneofCase.X ? (string) test_ : ""; } + set { + test_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + testCase_ = TestOneofCase.X; + } + } + + /// Field number for the "none" field. + public const int NoneFieldNumber = 2; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string None { + get { return testCase_ == TestOneofCase.None_ ? (string) test_ : ""; } + set { + test_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + testCase_ = TestOneofCase.None_; + } + } + + private object test_; + /// Enum of possible cases for the "test" oneof. + public enum TestOneofCase { + None = 0, + X = 1, + None_ = 2, + } + private TestOneofCase testCase_ = TestOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public TestOneofCase TestCase { + get { return testCase_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearTest() { + testCase_ = TestOneofCase.None; + test_ = null; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as OneofWithNoneField); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(OneofWithNoneField other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (X != other.X) return false; + if (None != other.None) return false; + if (TestCase != other.TestCase) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (testCase_ == TestOneofCase.X) hash ^= X.GetHashCode(); + if (testCase_ == TestOneofCase.None_) hash ^= None.GetHashCode(); + hash ^= (int) testCase_; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (testCase_ == TestOneofCase.X) { + output.WriteRawTag(10); + output.WriteString(X); + } + if (testCase_ == TestOneofCase.None_) { + output.WriteRawTag(18); + output.WriteString(None); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (testCase_ == TestOneofCase.X) { + output.WriteRawTag(10); + output.WriteString(X); + } + if (testCase_ == TestOneofCase.None_) { + output.WriteRawTag(18); + output.WriteString(None); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (testCase_ == TestOneofCase.X) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(X); + } + if (testCase_ == TestOneofCase.None_) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(None); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(OneofWithNoneField other) { + if (other == null) { + return; + } + switch (other.TestCase) { + case TestOneofCase.X: + X = other.X; + break; + case TestOneofCase.None_: + None = other.None; + break; + } + + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + X = input.ReadString(); + break; + } + case 18: { + None = input.ReadString(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + X = input.ReadString(); + break; + } + case 18: { + None = input.ReadString(); + break; + } + } + } + } + #endif + + } + + public sealed partial class OneofWithNoneName : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new OneofWithNoneName()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[13]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public OneofWithNoneName() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public OneofWithNoneName(OneofWithNoneName other) : this() { + switch (other.NoneCase) { + case NoneOneofCase.X: + X = other.X; + break; + case NoneOneofCase.Y: + Y = other.Y; + break; + } + + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public OneofWithNoneName Clone() { + return new OneofWithNoneName(this); + } + + /// Field number for the "x" field. + public const int XFieldNumber = 1; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string X { + get { return noneCase_ == NoneOneofCase.X ? (string) none_ : ""; } + set { + none_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + noneCase_ = NoneOneofCase.X; + } + } + + /// Field number for the "y" field. + public const int YFieldNumber = 2; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Y { + get { return noneCase_ == NoneOneofCase.Y ? (string) none_ : ""; } + set { + none_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + noneCase_ = NoneOneofCase.Y; + } + } + + private object none_; + /// Enum of possible cases for the "none" oneof. + public enum NoneOneofCase { + None = 0, + X = 1, + Y = 2, + } + private NoneOneofCase noneCase_ = NoneOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public NoneOneofCase NoneCase { + get { return noneCase_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearNone() { + noneCase_ = NoneOneofCase.None; + none_ = null; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as OneofWithNoneName); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(OneofWithNoneName other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (X != other.X) return false; + if (Y != other.Y) return false; + if (NoneCase != other.NoneCase) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (noneCase_ == NoneOneofCase.X) hash ^= X.GetHashCode(); + if (noneCase_ == NoneOneofCase.Y) hash ^= Y.GetHashCode(); + hash ^= (int) noneCase_; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (noneCase_ == NoneOneofCase.X) { + output.WriteRawTag(10); + output.WriteString(X); + } + if (noneCase_ == NoneOneofCase.Y) { + output.WriteRawTag(18); + output.WriteString(Y); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (noneCase_ == NoneOneofCase.X) { + output.WriteRawTag(10); + output.WriteString(X); + } + if (noneCase_ == NoneOneofCase.Y) { + output.WriteRawTag(18); + output.WriteString(Y); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (noneCase_ == NoneOneofCase.X) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(X); + } + if (noneCase_ == NoneOneofCase.Y) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Y); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(OneofWithNoneName other) { + if (other == null) { + return; + } + switch (other.NoneCase) { + case NoneOneofCase.X: + X = other.X; + break; + case NoneOneofCase.Y: + Y = other.Y; + break; + } + + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + X = input.ReadString(); + break; + } + case 18: { + Y = input.ReadString(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + X = input.ReadString(); + break; + } + case 18: { + Y = input.ReadString(); + break; + } + } + } + } + #endif + + } + #endregion } diff --git a/csharp/src/Google.Protobuf.Test/testprotos.pb b/csharp/src/Google.Protobuf.Test/testprotos.pb index 50fd48c526eab4fc16d87067a2a86264762e667b..b1dfc97ea73965f614342d5553e0cee588f33550 100644 GIT binary patch delta 543 zcmZXOze)o^5Qlg6Hs@t>o0v61w31YL0}HKEh*bm|YsC`-dMQkifDpvO2k-&%N6F<( z5aB?J1F=dczJ#T(AUJ!ujflk-zx~ZO^SytU9J)PYxQb z(|XhQb{gK@M4fwko0UsVwvKD@ipQMa#QrRkpDBXGi_;-21nJR(2LV zbTsTYx$oU>M?vo8^af!~3J z5;Hne-3P}dl4{PB7=S3wOU^P$L=$Ot06Eu0OUJ@;ic;Aff+(de5KGapK=lxE1=A8c z1htX~OJ$FMO;TY=lOu4}5@D%@1K*a*v`#F+B@Dz!8`HpUd`>ev`d jPGz`YxfZ5qP%Rw(qCjX!=yg21iDy8M)3aXUnNaN?8DLg0 delta 57 zcmZ42D0=p<$cBAun3_#CA6QevHhJ&n<($`4x!8qR85rhn&fRiesCmwb_BkgQftU%1 MnYYh5!6H-v00nv)761SM From 0dcf31d98143e5404332c8bff9624fb25a372dab Mon Sep 17 00:00:00 2001 From: "David L. Jones" Date: Wed, 30 Mar 2022 13:09:49 -0700 Subject: [PATCH 30/54] Enable builds for macos-next kokoro. (#9706) This enables build logic on the "macos-next" flavor of Kokoro tests. The current runners use Big Sur with Xcode 13.2.1. This build uses cmake to configure and drive the build through Xcode. Tests are run under ctest. --- kokoro/macos-next/cpp/build.sh | 49 ++++++++++++++++++---------- kokoro/macos-next/cpp/continuous.cfg | 6 ++-- kokoro/macos-next/cpp/presubmit.cfg | 6 ++-- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/kokoro/macos-next/cpp/build.sh b/kokoro/macos-next/cpp/build.sh index 67466ccca1e5..2059ff41c112 100755 --- a/kokoro/macos-next/cpp/build.sh +++ b/kokoro/macos-next/cpp/build.sh @@ -1,36 +1,51 @@ -#!/bin/bash -ex +#!/bin/bash -ex -o pipefail # # Build file to set up and run tests -# NOTE: in order to avoid blocking anyone, this job always succeeds for now. -exit 0 - -# Set up artifact output location -: ${KOKORO_ARTIFACTS_DIR:=/tmp/kokoro_artifacts} +# +# Set up logging output location +# +: ${KOKORO_ARTIFACTS_DIR:=/tmp/protobuf_test_logs} : ${BUILD_LOGDIR:=$KOKORO_ARTIFACTS_DIR/logs} mkdir -p ${BUILD_LOGDIR} + +# # Change to repo root -cd $(dirname $0)/../../.. +# +if [[ -h /tmpfs ]] && [[ ${PWD} == /tmpfs/src ]]; then + # Workaround for internal Kokoro bug: b/227401944 + cd /Volumes/BuildData/tmpfs/src/github/protobuf +else + cd $(dirname $0)/../../.. +fi +# # Update submodules +# git submodule update --init --recursive -# Build in a separate directory +# +# Configure and build in a separate directory +# mkdir -p cmake/build cd cmake/build -# Print some basic info -xcode-select --print-path -xcodebuild -version -xcrun --show-sdk-path - -# Build everything first cmake -G Xcode ../.. \ - 2>&1 | tee ${BUILD_LOGDIR}/00_configure_sponge_log.log + 2>&1 | tee ${BUILD_LOGDIR}/01_configure.log + +cp CMakeFiles/CMake*.log ${BUILD_LOGDIR} + cmake --build . --config Debug \ - 2>&1 | tee ${BUILD_LOGDIR}/01_build_sponge_log.log + 2>&1 | tee ${BUILD_LOGDIR}/02_build.log +# # Run tests +# ctest -C Debug --verbose --quiet \ - --output-log ${BUILD_LOGDIR}/02_test_sponge_log.log + --output-log ${BUILD_LOGDIR}/03_test.log + +# +# Compress outputs +# +gzip ${BUILD_LOGDIR}/*.log diff --git a/kokoro/macos-next/cpp/continuous.cfg b/kokoro/macos-next/cpp/continuous.cfg index 32f1b1da5ae9..3be89730e0d7 100644 --- a/kokoro/macos-next/cpp/continuous.cfg +++ b/kokoro/macos-next/cpp/continuous.cfg @@ -7,7 +7,9 @@ timeout_mins: 1440 # Upload logs action: { define_artifacts: { - regex: "protobuf/cmake/build/**/*sponge_log.log" - regex: "protobuf/cmake/build/**/*sponge_log.xml" + regex: "**/*sponge_log.log" + regex: "**/*sponge_log.xml" + regex: "logs/*.log" + regex: "logs/*.log.gz" } } diff --git a/kokoro/macos-next/cpp/presubmit.cfg b/kokoro/macos-next/cpp/presubmit.cfg index 32f1b1da5ae9..3be89730e0d7 100644 --- a/kokoro/macos-next/cpp/presubmit.cfg +++ b/kokoro/macos-next/cpp/presubmit.cfg @@ -7,7 +7,9 @@ timeout_mins: 1440 # Upload logs action: { define_artifacts: { - regex: "protobuf/cmake/build/**/*sponge_log.log" - regex: "protobuf/cmake/build/**/*sponge_log.xml" + regex: "**/*sponge_log.log" + regex: "**/*sponge_log.xml" + regex: "logs/*.log" + regex: "logs/*.log.gz" } } From 5b2c7b837364b8cf391673bcab4f2ae4ac761e10 Mon Sep 17 00:00:00 2001 From: "David L. Jones" Date: Wed, 30 Mar 2022 13:44:42 -0700 Subject: [PATCH 31/54] [CMake] Declare remaining tests, and add a test output option. (#9705) The new option will allow us to generate test XML output. CTest can discover tests from googletest, but it generates one file per case. We have several thousand cases, so one file each would be far from optimal. The approach in this change will generate one file per test (executable). --- cmake/tests.cmake | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/cmake/tests.cmake b/cmake/tests.cmake index 28551f52c3a4..0fecfa5d58fa 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -1,5 +1,7 @@ option(protobuf_USE_EXTERNAL_GTEST "Use external Google Test (i.e. not the one in third_party/googletest)" OFF) +option(protobuf_TEST_XML_OUTDIR "Output directory for XML logs from tests." "") + option(protobuf_ABSOLUTE_TEST_PLUGIN_PATH "Using absolute test_plugin path in tests" ON) mark_as_advanced(protobuf_ABSOLUTE_TEST_PLUGIN_PATH) @@ -239,6 +241,13 @@ if(MINGW) endif() +if(protobuf_TEST_XML_OUTDIR) + if(NOT "${protobuf_TEST_XML_OUTDIR}" MATCHES "[/\\]$") + string(APPEND protobuf_TEST_XML_OUTDIR "/") + endif() + set(protobuf_GTEST_ARGS "--gtest_output=xml:${protobuf_TEST_XML_OUTDIR}") +endif() + add_executable(tests ${tests_files}) if (MSVC) target_compile_options(tests PRIVATE @@ -263,17 +272,23 @@ set(lite_test_files add_executable(lite-test ${lite_test_files}) target_link_libraries(lite-test protobuf-lite-test-common libprotobuf-lite GTest::gmock_main) +add_test(NAME lite-test + COMMAND lite-test ${protobuf_GTEST_ARGS}) + set(lite_arena_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/lite_arena_unittest.cc ) add_executable(lite-arena-test ${lite_arena_test_files}) target_link_libraries(lite-arena-test protobuf-lite-test-common libprotobuf-lite GTest::gmock_main) +add_test(NAME lite-arena-test + COMMAND lite-arena-test ${protobuf_GTEST_ARGS}) + add_custom_target(check COMMAND tests DEPENDS tests test_plugin WORKING_DIRECTORY ${protobuf_SOURCE_DIR}) add_test(NAME check - COMMAND tests + COMMAND tests ${protobuf_GTEST_ARGS} WORKING_DIRECTORY "${protobuf_SOURCE_DIR}") From 61dcf50b85b7e2060e03bb99f88540d81eedb125 Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Wed, 30 Mar 2022 20:52:15 +0000 Subject: [PATCH 32/54] Update Guava to 31.1 (#9707) * start work on open source build instructions * subprojects * JDK17 * update Guava to 30.1-jre * pin dependencies --- maven_install.json | 86 +++++++++++++++++++++++----------------------- protobuf_deps.bzl | 4 +-- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/maven_install.json b/maven_install.json index 808e0130d8f6..9c5860a94824 100644 --- a/maven_install.json +++ b/maven_install.json @@ -1,10 +1,10 @@ { "dependency_tree": { "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", - "__INPUT_ARTIFACTS_HASH": -1867950668, - "__RESOLVED_ARTIFACTS_HASH": 1254982283, + "__INPUT_ARTIFACTS_HASH": -228414992, + "__RESOLVED_ARTIFACTS_HASH": -722345565, "conflict_resolution": { - "com.google.errorprone:error_prone_annotations:2.3.2": "com.google.errorprone:error_prone_annotations:2.5.1", + "com.google.errorprone:error_prone_annotations:2.3.2": "com.google.errorprone:error_prone_annotations:2.11.0", "junit:junit:4.12": "junit:junit:4.13.2" }, "dependencies": [ @@ -45,16 +45,16 @@ "url": "https://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.9/gson-2.8.9.jar" }, { - "coord": "com.google.errorprone:error_prone_annotations:2.5.1", + "coord": "com.google.errorprone:error_prone_annotations:2.11.0", "dependencies": [], "directDependencies": [], - "file": "v1/https/repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations/2.5.1/error_prone_annotations-2.5.1.jar", + "file": "v1/https/repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations/2.11.0/error_prone_annotations-2.11.0.jar", "mirror_urls": [ - "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations/2.5.1/error_prone_annotations-2.5.1.jar", - "https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.5.1/error_prone_annotations-2.5.1.jar" + "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations/2.11.0/error_prone_annotations-2.11.0.jar", + "https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.11.0/error_prone_annotations-2.11.0.jar" ], - "sha256": "ff80626baaf12a09342befd4e84cba9d50662f5fcd7f7a9b3490a6b7cf87e66c", - "url": "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations/2.5.1/error_prone_annotations-2.5.1.jar" + "sha256": "721cb91842b46fa056847d104d5225c8b8e1e8b62263b993051e1e5a0137b7ec", + "url": "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations/2.11.0/error_prone_annotations-2.11.0.jar" }, { "coord": "com.google.guava:failureaccess:1.0.1", @@ -69,59 +69,59 @@ "url": "https://repo1.maven.org/maven2/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar" }, { - "coord": "com.google.guava:guava-testlib:30.1.1-jre", + "coord": "com.google.guava:guava-testlib:31.1-jre", "dependencies": [ "com.google.code.findbugs:jsr305:3.0.2", - "com.google.errorprone:error_prone_annotations:2.5.1", + "com.google.errorprone:error_prone_annotations:2.11.0", "com.google.guava:failureaccess:1.0.1", - "com.google.guava:guava:30.1.1-jre", + "com.google.guava:guava:31.1-jre", "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava", "com.google.j2objc:j2objc-annotations:1.3", "junit:junit:4.13.2", - "org.checkerframework:checker-qual:3.9.1", + "org.checkerframework:checker-qual:3.12.0", "org.hamcrest:hamcrest-core:1.3" ], "directDependencies": [ "com.google.code.findbugs:jsr305:3.0.2", - "com.google.errorprone:error_prone_annotations:2.5.1", - "com.google.guava:guava:30.1.1-jre", + "com.google.errorprone:error_prone_annotations:2.11.0", + "com.google.guava:guava:31.1-jre", "com.google.j2objc:j2objc-annotations:1.3", "junit:junit:4.13.2", - "org.checkerframework:checker-qual:3.9.1" + "org.checkerframework:checker-qual:3.12.0" ], - "file": "v1/https/repo1.maven.org/maven2/com/google/guava/guava-testlib/30.1.1-jre/guava-testlib-30.1.1-jre.jar", + "file": "v1/https/repo1.maven.org/maven2/com/google/guava/guava-testlib/31.1-jre/guava-testlib-31.1-jre.jar", "mirror_urls": [ - "https://repo1.maven.org/maven2/com/google/guava/guava-testlib/30.1.1-jre/guava-testlib-30.1.1-jre.jar", - "https://repo.maven.apache.org/maven2/com/google/guava/guava-testlib/30.1.1-jre/guava-testlib-30.1.1-jre.jar" + "https://repo1.maven.org/maven2/com/google/guava/guava-testlib/31.1-jre/guava-testlib-31.1-jre.jar", + "https://repo.maven.apache.org/maven2/com/google/guava/guava-testlib/31.1-jre/guava-testlib-31.1-jre.jar" ], - "sha256": "8a7fc9adfa1e7441d1d30ca288c593ebc7c4a24c601d01169b781c398f24099b", - "url": "https://repo1.maven.org/maven2/com/google/guava/guava-testlib/30.1.1-jre/guava-testlib-30.1.1-jre.jar" + "sha256": "aadc71b10d5c3ac474dd16be84cfb18d257e584d1e0a59f8cab64ef4376226ce", + "url": "https://repo1.maven.org/maven2/com/google/guava/guava-testlib/31.1-jre/guava-testlib-31.1-jre.jar" }, { - "coord": "com.google.guava:guava:30.1.1-jre", + "coord": "com.google.guava:guava:31.1-jre", "dependencies": [ "com.google.code.findbugs:jsr305:3.0.2", - "com.google.errorprone:error_prone_annotations:2.5.1", + "com.google.errorprone:error_prone_annotations:2.11.0", "com.google.guava:failureaccess:1.0.1", "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava", "com.google.j2objc:j2objc-annotations:1.3", - "org.checkerframework:checker-qual:3.9.1" + "org.checkerframework:checker-qual:3.12.0" ], "directDependencies": [ "com.google.code.findbugs:jsr305:3.0.2", - "com.google.errorprone:error_prone_annotations:2.5.1", + "com.google.errorprone:error_prone_annotations:2.11.0", "com.google.guava:failureaccess:1.0.1", "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava", "com.google.j2objc:j2objc-annotations:1.3", - "org.checkerframework:checker-qual:3.9.1" + "org.checkerframework:checker-qual:3.12.0" ], - "file": "v1/https/repo1.maven.org/maven2/com/google/guava/guava/30.1.1-jre/guava-30.1.1-jre.jar", + "file": "v1/https/repo1.maven.org/maven2/com/google/guava/guava/31.1-jre/guava-31.1-jre.jar", "mirror_urls": [ - "https://repo1.maven.org/maven2/com/google/guava/guava/30.1.1-jre/guava-30.1.1-jre.jar", - "https://repo.maven.apache.org/maven2/com/google/guava/guava/30.1.1-jre/guava-30.1.1-jre.jar" + "https://repo1.maven.org/maven2/com/google/guava/guava/31.1-jre/guava-31.1-jre.jar", + "https://repo.maven.apache.org/maven2/com/google/guava/guava/31.1-jre/guava-31.1-jre.jar" ], - "sha256": "44ce229ce26d880bf3afc362bbfcec34d7e6903d195bbb1db9f3b6e0d9834f06", - "url": "https://repo1.maven.org/maven2/com/google/guava/guava/30.1.1-jre/guava-30.1.1-jre.jar" + "sha256": "a42edc9cab792e39fe39bb94f3fca655ed157ff87a8af78e1d6ba5b07c4a00ab", + "url": "https://repo1.maven.org/maven2/com/google/guava/guava/31.1-jre/guava-31.1-jre.jar" }, { "coord": "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava", @@ -151,18 +151,18 @@ "coord": "com.google.truth:truth:1.1.2", "dependencies": [ "com.google.auto.value:auto-value-annotations:1.7.4", - "com.google.errorprone:error_prone_annotations:2.5.1", - "com.google.guava:guava:30.1.1-jre", + "com.google.errorprone:error_prone_annotations:2.11.0", + "com.google.guava:guava:31.1-jre", "junit:junit:4.13.2", - "org.checkerframework:checker-qual:3.9.1", + "org.checkerframework:checker-qual:3.12.0", "org.ow2.asm:asm:9.0" ], "directDependencies": [ "com.google.auto.value:auto-value-annotations:1.7.4", - "com.google.errorprone:error_prone_annotations:2.5.1", - "com.google.guava:guava:30.1.1-jre", + "com.google.errorprone:error_prone_annotations:2.11.0", + "com.google.guava:guava:31.1-jre", "junit:junit:4.13.2", - "org.checkerframework:checker-qual:3.9.1", + "org.checkerframework:checker-qual:3.12.0", "org.ow2.asm:asm:9.0" ], "file": "v1/https/repo1.maven.org/maven2/com/google/truth/truth/1.1.2/truth-1.1.2.jar", @@ -214,16 +214,16 @@ "url": "https://repo1.maven.org/maven2/net/bytebuddy/byte-buddy/1.12.7/byte-buddy-1.12.7.jar" }, { - "coord": "org.checkerframework:checker-qual:3.9.1", + "coord": "org.checkerframework:checker-qual:3.12.0", "dependencies": [], "directDependencies": [], - "file": "v1/https/repo1.maven.org/maven2/org/checkerframework/checker-qual/3.9.1/checker-qual-3.9.1.jar", + "file": "v1/https/repo1.maven.org/maven2/org/checkerframework/checker-qual/3.12.0/checker-qual-3.12.0.jar", "mirror_urls": [ - "https://repo1.maven.org/maven2/org/checkerframework/checker-qual/3.9.1/checker-qual-3.9.1.jar", - "https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/3.9.1/checker-qual-3.9.1.jar" + "https://repo1.maven.org/maven2/org/checkerframework/checker-qual/3.12.0/checker-qual-3.12.0.jar", + "https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/3.12.0/checker-qual-3.12.0.jar" ], - "sha256": "ab0468b1ba35bb2ae45f61a60dc4960bd887660ab8f05113a662a7e675eae776", - "url": "https://repo1.maven.org/maven2/org/checkerframework/checker-qual/3.9.1/checker-qual-3.9.1.jar" + "sha256": "ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb", + "url": "https://repo1.maven.org/maven2/org/checkerframework/checker-qual/3.12.0/checker-qual-3.12.0.jar" }, { "coord": "org.hamcrest:hamcrest-core:1.3", diff --git a/protobuf_deps.bzl b/protobuf_deps.bzl index de81ae82aae6..e87b70484180 100644 --- a/protobuf_deps.bzl +++ b/protobuf_deps.bzl @@ -7,8 +7,8 @@ PROTOBUF_MAVEN_ARTIFACTS = [ "com.google.code.gson:gson:2.8.9", "com.google.errorprone:error_prone_annotations:2.3.2", "com.google.j2objc:j2objc-annotations:1.3", - "com.google.guava:guava:30.1.1-jre", - "com.google.guava:guava-testlib:30.1.1-jre", + "com.google.guava:guava:31.1-jre", + "com.google.guava:guava-testlib:31.1-jre", "com.google.truth:truth:1.1.2", "junit:junit:4.13.2", "org.mockito:mockito-core:4.3.1", From eb8976a56d3f596ada8562dcff27724fb3f3625c Mon Sep 17 00:00:00 2001 From: Gary Peck Date: Thu, 31 Mar 2022 07:45:15 -0700 Subject: [PATCH 33/54] Add pbandk to list of 3rd-party Kotlin libraries (#9712) --- .github/workflows/codespell.yml | 2 +- docs/third_party.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 497e811c8bba..41dc715db2b7 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -13,4 +13,4 @@ jobs: with: check_filenames: true skip: ./.git,./conformance/third_party,*.snk,*.pb,*.pb.cc,*.pb.h,./src/google/protobuf/testdata,./objectivec/Tests,./python/compatibility_tests/v2.5.0/tests/google/protobuf/internal,./.github/workflows/codespell.yml - ignore_words_list: "alow,alse,ba,cleare,copyable,cloneable,dedup,dur,errorprone,files',fo,fundementals,hel,importd,inout,leapyear,nd,nin,ois,ons,parseable,process',te,testof,ue,unparseable,wasn,wee,gae,keyserver,objext,od,optin,sur" + ignore_words_list: "alow,alse,ba,cleare,copyable,cloneable,dedup,dur,errorprone,files',fo,fundementals,hel,importd,inout,leapyear,nd,nin,ois,ons,parseable,process',te,testof,ue,unparseable,wasn,wee,gae,keyserver,objext,od,optin,streem,sur" diff --git a/docs/third_party.md b/docs/third_party.md index ca1415afb514..d8478e9adaa6 100644 --- a/docs/third_party.md +++ b/docs/third_party.md @@ -71,6 +71,7 @@ These are projects we know about implementing Protocol Buffers for other program * Kotlin: https://github.com/Kotlin/kotlinx.serialization * Kotlin: https://github.com/ButterCam/sisyphus * Kotlin: https://github.com/open-toast/protokt +* Kotlin Multiplatform: https://github.com/streem/pbandk * Lua: https://code.google.com/p/protoc-gen-lua/ * Lua: http://github.com/indygreg/lua-protobuf * Lua: https://github.com/Neopallium/lua-pb From 3be07ab3208ba34835091d4166d023926e302965 Mon Sep 17 00:00:00 2001 From: "David L. Jones" Date: Fri, 1 Apr 2022 13:49:14 -0700 Subject: [PATCH 34/54] [Kokoro] Emit XML test logs on macos-next. (#9709) This enables googletest XML output on the macos-next builders, and adds logic to collect the results. The log collection logic is slightly complex, but it should be reusable in other contexts. The idea is to capture stdout/stderr for build steps along with googletest XML reports into a temporary directory, then stage those into paths expected for artifacts. --- kokoro/caplog.sh | 92 ++++++++++++++++++++++++++++ kokoro/macos-next/cpp/build.sh | 62 ++++++++++--------- kokoro/macos-next/cpp/continuous.cfg | 2 - kokoro/macos-next/cpp/presubmit.cfg | 2 - 4 files changed, 125 insertions(+), 33 deletions(-) create mode 100644 kokoro/caplog.sh diff --git a/kokoro/caplog.sh b/kokoro/caplog.sh new file mode 100644 index 000000000000..fe81949ead32 --- /dev/null +++ b/kokoro/caplog.sh @@ -0,0 +1,92 @@ +# Log capturing for the Kokoro runtime environment. +# +# This script should be `source`d from Kokoro build scripts to configure log +# capturing when running under Kokoro. +# +# When not running under Kokoro, no logs will be collected. If you want to run +# locally and collect logs anyway, set the KOKORO_ARTIFACTS_DIR environment +# variable to a directory where the logs should go. +# +# The job `.cfg` file needs the following stanzas to declare the captured logs +# as outputs (yes, these are globs, not regexes): +# +# action: { +# define_artifacts: { +# regex: "**/*sponge_log.log" +# regex: "**/*sponge_log.xml" +# } +# } +# +# Use the provided functions below as build/test fixtures, e.g.: +# +# source kokoro/capture_logs.sh +# caplog build/step1 +# caplog tests/step2 +# +# If log capturing is enabled, this script will set some variables that can be +# used if necessary: +# +# CAPLOG_DIR is used for logs +# CAPLOG_CMAKE_ARGS contains extra cmake args to enable test XML output +# CAPLOG_CTEST_ARGS contains extra ctest args to capture combined test logs +# +# For example: +# +# if [[ -v CAPLOG_DIR_BUILD ]]; then +# cp extra_diagnostics.log "${CAPLOG_DIR_BUILD}/diagnostics.log" +# fi +# +# # Use ${...:-} form under `set -u`: +# caplog build/01_configure cmake -G Ninja ${CAPLOG_CMAKE_ARGS:-} +# caplog build/02_build cmake --build +# caplog test/03_test ctest ${CAPLOG_CTEST_ARGS:-} + +if [[ -z ${KOKORO_ARTIFACTS_DIR:-} ]]; then + function caplog() { shift; "$@"; } +else + + CAPLOG_DIR="$(mktemp -d)" + CAPLOG_CMAKE_ARGS="-Dprotobuf_TEST_XML_OUTDIR=${CAPLOG_DIR}/tests/" + CAPLOG_CTEST_ARGS="--verbose" + + # Captures the stdout/stderr of a command to a named log file. + # Usage: caplog NAME COMMAND [ARGS...] + function caplog() { + _name="${CAPLOG_DIR}/${1%.log}.log"; shift + mkdir -p "${_name%/*}" + date + time ( "$@" 2>&1 | tee "${_name}" ) + if [[ $? != 0 ]] ; then + cat "${_name}" + return 1 + fi + } + + # Trap handler: renames logs on script exit so they will be found by Kokoro. + function _caplog_onexit() { + _rc=$? + set +x + echo "Collecting logs [${BASH_SOURCE}]" + + find "${CAPLOG_DIR}" -type f -name '*.log' \ + | while read _textlog; do + # Ensure an XML file exists for each .log file. + touch ${_textlog%.log}.xml + done + + find "${CAPLOG_DIR}" -type f \( -name '*.xml' -or -name '*.log' \) \ + | while read _src; do + # Move to artifacts dir, preserving the path relative to CAPLOG_DIR. + # The filename changes from foo/bar.log to foo/bar/sponge_log.log. + _logfile=${_src/${CAPLOG_DIR}\//} + _stem=${KOKORO_ARTIFACTS_DIR}/${_logfile%.*} + _ext=${_logfile##*.} + mkdir -p ${_stem} + mv -v "${_src}" "${_stem}/sponge_log.${_ext}" + done + rm -rv "${CAPLOG_DIR}" + exit ${_rc} + } + trap _caplog_onexit EXIT + +fi diff --git a/kokoro/macos-next/cpp/build.sh b/kokoro/macos-next/cpp/build.sh index 2059ff41c112..490e99016140 100755 --- a/kokoro/macos-next/cpp/build.sh +++ b/kokoro/macos-next/cpp/build.sh @@ -1,51 +1,55 @@ -#!/bin/bash -ex -o pipefail +#!/bin/bash -eux # # Build file to set up and run tests -# -# Set up logging output location -# -: ${KOKORO_ARTIFACTS_DIR:=/tmp/protobuf_test_logs} -: ${BUILD_LOGDIR:=$KOKORO_ARTIFACTS_DIR/logs} -mkdir -p ${BUILD_LOGDIR} +set -o pipefail - -# -# Change to repo root -# if [[ -h /tmpfs ]] && [[ ${PWD} == /tmpfs/src ]]; then # Workaround for internal Kokoro bug: b/227401944 - cd /Volumes/BuildData/tmpfs/src/github/protobuf -else - cd $(dirname $0)/../../.. + cd /Volumes/BuildData/tmpfs/src fi +# These vars can be changed when running manually, e.g.: +# +# % BUILD_CONFIG=RelWithDebInfo path/to/build.sh + +# By default, build using Debug config. +: ${BUILD_CONFIG:=Debug} + +# By default, find the sources based on this script path. +: ${SOURCE_DIR:=$(cd $(dirname $0)/../../..; pwd)} + +# By default, put outputs under /cmake/build. +: ${BUILD_DIR:=${SOURCE_DIR}/cmake/build} + +source ${SOURCE_DIR}/kokoro/caplog.sh + # # Update submodules # -git submodule update --init --recursive +git -C "${SOURCE_DIR}" submodule update --init --recursive # # Configure and build in a separate directory # -mkdir -p cmake/build -cd cmake/build +mkdir -p "${BUILD_DIR}" -cmake -G Xcode ../.. \ - 2>&1 | tee ${BUILD_LOGDIR}/01_configure.log +caplog 01_configure \ + cmake -S "${SOURCE_DIR}" -B "${BUILD_DIR}" ${CAPLOG_CMAKE_ARGS:-} -cp CMakeFiles/CMake*.log ${BUILD_LOGDIR} +if [[ -n ${CAPLOG_DIR:-} ]]; then + mkdir -p "${CAPLOG_DIR}/CMakeFiles" + cp "${BUILD_DIR}"/CMakeFiles/CMake*.log "${CAPLOG_DIR}/CMakeFiles" +fi -cmake --build . --config Debug \ - 2>&1 | tee ${BUILD_LOGDIR}/02_build.log +caplog 02_build \ + cmake --build "${BUILD_DIR}" --config "${BUILD_CONFIG}" # # Run tests # -ctest -C Debug --verbose --quiet \ - --output-log ${BUILD_LOGDIR}/03_test.log - -# -# Compress outputs -# -gzip ${BUILD_LOGDIR}/*.log +( + cd "${BUILD_DIR}" + caplog 03_combined_testlog \ + ctest -C "${BUILD_CONFIG}" -j4 ${CAPLOG_CTEST_ARGS:-} +) diff --git a/kokoro/macos-next/cpp/continuous.cfg b/kokoro/macos-next/cpp/continuous.cfg index 3be89730e0d7..166caa5f91e2 100644 --- a/kokoro/macos-next/cpp/continuous.cfg +++ b/kokoro/macos-next/cpp/continuous.cfg @@ -9,7 +9,5 @@ action: { define_artifacts: { regex: "**/*sponge_log.log" regex: "**/*sponge_log.xml" - regex: "logs/*.log" - regex: "logs/*.log.gz" } } diff --git a/kokoro/macos-next/cpp/presubmit.cfg b/kokoro/macos-next/cpp/presubmit.cfg index 3be89730e0d7..166caa5f91e2 100644 --- a/kokoro/macos-next/cpp/presubmit.cfg +++ b/kokoro/macos-next/cpp/presubmit.cfg @@ -9,7 +9,5 @@ action: { define_artifacts: { regex: "**/*sponge_log.log" regex: "**/*sponge_log.xml" - regex: "logs/*.log" - regex: "logs/*.log.gz" } } From d85f03d66ae53e8e5bd4d41cfe9295a4514743a5 Mon Sep 17 00:00:00 2001 From: Luc Thevenard Date: Fri, 1 Apr 2022 16:47:22 -0400 Subject: [PATCH 35/54] [Ruby] Fix RepeatedField#last, #first inconsistencies --- ruby/lib/google/protobuf/repeated_field.rb | 17 +++++++++++++++-- ruby/tests/repeated_field_test.rb | 13 +++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/ruby/lib/google/protobuf/repeated_field.rb b/ruby/lib/google/protobuf/repeated_field.rb index bc9699fdfd3b..5c1e906535da 100644 --- a/ruby/lib/google/protobuf/repeated_field.rb +++ b/ruby/lib/google/protobuf/repeated_field.rb @@ -79,12 +79,25 @@ class RepeatedField def first(n=nil) - n ? self[0...n] : self[0] + if n.nil? + return self[0] + elsif n < 0 + raise ArgumentError, "negative array size" + else + return self[0...n] + end end def last(n=nil) - n ? self[(self.size-n-1)..-1] : self[-1] + if n.nil? + return self[-1] + elsif n < 0 + raise ArgumentError, "negative array size" + else + start = [self.size-n, 0].max + return self[start..-1] + end end diff --git a/ruby/tests/repeated_field_test.rb b/ruby/tests/repeated_field_test.rb index 6ad39b556300..0483efcf8c40 100755 --- a/ruby/tests/repeated_field_test.rb +++ b/ruby/tests/repeated_field_test.rb @@ -48,6 +48,10 @@ def test_first assert_equal TestMessage2.new(:foo => 1), m.repeated_msg.first assert_equal :A, m.repeated_enum.first + err = assert_raises(ArgumentError) do + m.repeated_int32.first(-1) + end + assert_equal "negative array size", err.message assert_equal [], m.repeated_int32.first(0) assert_equal [-10], m.repeated_int32.first(1) assert_equal [-10, -11], m.repeated_int32.first(2) @@ -72,6 +76,15 @@ def test_last assert_equal "foo".encode!('ASCII-8BIT'), m.repeated_bytes.last assert_equal TestMessage2.new(:foo => 2), m.repeated_msg.last assert_equal :B, m.repeated_enum.last + + err = assert_raises(ArgumentError) do + m.repeated_int32.last(-1) + end + assert_equal "negative array size", err.message + assert_equal [], m.repeated_int32.last(0) + assert_equal [-11], m.repeated_int32.last(1) + assert_equal [-10, -11], m.repeated_int32.last(2) + assert_equal [-10, -11], m.repeated_int32.last(3) end From feef319e8566372c83ba277e9d6454a01336cef4 Mon Sep 17 00:00:00 2001 From: Michele Locati Date: Sun, 3 Apr 2022 21:23:43 +0200 Subject: [PATCH 36/54] Test building packaged PHP extension --- .github/workflows/php-ext.yml | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .github/workflows/php-ext.yml diff --git a/.github/workflows/php-ext.yml b/.github/workflows/php-ext.yml new file mode 100644 index 000000000000..f24f6bf62b0d --- /dev/null +++ b/.github/workflows/php-ext.yml @@ -0,0 +1,43 @@ +name: PHP extension + +on: + - push + - pull_request + +jobs: + build-php: + name: Build PHP extension + runs-on: ubuntu-latest + container: ${{ matrix.php-image }} + strategy: + matrix: + php-image: + - php:7.4-cli + - php:8.1-cli + steps: + - name: Install git + run: | + apt-get update -q + apt-get install -qy --no-install-recommends git + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: recursive + - name: Prepare source code + run: | + rm -rf "$GITHUB_WORKSPACE/php/ext/google/protobuf/third_party" + cp -r "$GITHUB_WORKSPACE/third_party" "$GITHUB_WORKSPACE/php/ext/google/protobuf" + cp "$GITHUB_WORKSPACE/LICENSE" "$GITHUB_WORKSPACE/php/ext/google/protobuf" + - name: Create package + run: | + cd /tmp + rm -rf protobuf-*.tgz + pecl package "$GITHUB_WORKSPACE/php/ext/google/protobuf/package.xml" + - name: Compile extension + run: | + cd /tmp + MAKE="make -j$(nproc)" pecl install protobuf-*.tgz + - name: Enable extension + run: docker-php-ext-enable protobuf + - name: Inspect extension + run: php --ri protobuf From f0936d26e1031960b656698dbc21046b07eaaf11 Mon Sep 17 00:00:00 2001 From: Michele Locati Date: Sun, 3 Apr 2022 21:35:55 +0200 Subject: [PATCH 37/54] Fix building packaged PHP extension --- php/ext/google/protobuf/config.m4 | 1 + 1 file changed, 1 insertion(+) diff --git a/php/ext/google/protobuf/config.m4 b/php/ext/google/protobuf/config.m4 index 74cae3c7ef8d..01bedb8a2039 100644 --- a/php/ext/google/protobuf/config.m4 +++ b/php/ext/google/protobuf/config.m4 @@ -6,5 +6,6 @@ if test "$PHP_PROTOBUF" != "no"; then protobuf, arena.c array.c convert.c def.c map.c message.c names.c php-upb.c protobuf.c third_party/utf8_range/naive.c third_party/utf8_range/range2-neon.c third_party/utf8_range/range2-sse.c, $ext_shared, , -std=gnu99) + PHP_ADD_BUILD_DIR($ext_builddir/third_party/utf8_range) fi From 97533f52438fb0c2789021d9008f9198a9025916 Mon Sep 17 00:00:00 2001 From: Minsoo Cheong <54794500+j-min5u@users.noreply.github.com> Date: Tue, 5 Apr 2022 11:05:54 +0900 Subject: [PATCH 38/54] fix: restore val --- src/google/protobuf/compiler/java/enum_field.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/google/protobuf/compiler/java/enum_field.cc b/src/google/protobuf/compiler/java/enum_field.cc index aa6883f01150..ed3594ce70fb 100644 --- a/src/google/protobuf/compiler/java/enum_field.cc +++ b/src/google/protobuf/compiler/java/enum_field.cc @@ -283,7 +283,7 @@ void ImmutableEnumFieldGenerator::GenerateKotlinDslMembers( io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$kt_deprecation$public var $kt_name$: $kt_type$\n" + "$kt_deprecation$ var $kt_name$: $kt_type$\n" " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" @@ -1090,7 +1090,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers( WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$kt_deprecation$ $kt_name$: " + "$kt_deprecation$ val $kt_name$: " "com.google.protobuf.kotlin.DslList" "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n" " @kotlin.jvm.JvmSynthetic\n" From 92c11a45c68cb76f6e5a3ead2446ba166bf7f4c0 Mon Sep 17 00:00:00 2001 From: Minsoo Cheong <54794500+j-min5u@users.noreply.github.com> Date: Tue, 5 Apr 2022 11:16:59 +0900 Subject: [PATCH 39/54] remove public modifiers on kt variables --- src/google/protobuf/compiler/java/enum_field_lite.cc | 2 +- src/google/protobuf/compiler/java/message_field.cc | 2 +- src/google/protobuf/compiler/java/message_field_lite.cc | 2 +- src/google/protobuf/compiler/java/primitive_field.cc | 2 +- src/google/protobuf/compiler/java/primitive_field_lite.cc | 2 +- src/google/protobuf/compiler/java/string_field.cc | 2 +- src/google/protobuf/compiler/java/string_field_lite.cc | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/google/protobuf/compiler/java/enum_field_lite.cc b/src/google/protobuf/compiler/java/enum_field_lite.cc index 9fb91a7393ca..6fe683fe0be9 100644 --- a/src/google/protobuf/compiler/java/enum_field_lite.cc +++ b/src/google/protobuf/compiler/java/enum_field_lite.cc @@ -288,7 +288,7 @@ void ImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers( io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$kt_deprecation$public var $kt_name$: $kt_type$\n" + "$kt_deprecation$var $kt_name$: $kt_type$\n" " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" diff --git a/src/google/protobuf/compiler/java/message_field.cc b/src/google/protobuf/compiler/java/message_field.cc index 0579e7afed93..f3833e978cb2 100644 --- a/src/google/protobuf/compiler/java/message_field.cc +++ b/src/google/protobuf/compiler/java/message_field.cc @@ -421,7 +421,7 @@ void ImmutableMessageFieldGenerator::GenerateKotlinDslMembers( io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$kt_deprecation$public var $kt_name$: $kt_type$\n" + "$kt_deprecation$var $kt_name$: $kt_type$\n" " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" diff --git a/src/google/protobuf/compiler/java/message_field_lite.cc b/src/google/protobuf/compiler/java/message_field_lite.cc index 9759150a43d0..eb37ca682c7e 100644 --- a/src/google/protobuf/compiler/java/message_field_lite.cc +++ b/src/google/protobuf/compiler/java/message_field_lite.cc @@ -290,7 +290,7 @@ void ImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers( io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$kt_deprecation$public var $kt_name$: $kt_type$\n" + "$kt_deprecation$var $kt_name$: $kt_type$\n" " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" diff --git a/src/google/protobuf/compiler/java/primitive_field.cc b/src/google/protobuf/compiler/java/primitive_field.cc index 87d66643e62a..9ec99f953bb8 100644 --- a/src/google/protobuf/compiler/java/primitive_field.cc +++ b/src/google/protobuf/compiler/java/primitive_field.cc @@ -320,7 +320,7 @@ void ImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers( io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$kt_deprecation$public var $kt_name$: $kt_type$\n" + "$kt_deprecation$var $kt_name$: $kt_type$\n" " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" diff --git a/src/google/protobuf/compiler/java/primitive_field_lite.cc b/src/google/protobuf/compiler/java/primitive_field_lite.cc index ba75f631e34e..e323feff2ad8 100644 --- a/src/google/protobuf/compiler/java/primitive_field_lite.cc +++ b/src/google/protobuf/compiler/java/primitive_field_lite.cc @@ -325,7 +325,7 @@ void ImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers( io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$kt_deprecation$public var $kt_name$: $kt_type$\n" + "$kt_deprecation$var $kt_name$: $kt_type$\n" " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" diff --git a/src/google/protobuf/compiler/java/string_field.cc b/src/google/protobuf/compiler/java/string_field.cc index 02d54399cf4d..3228da6d4a71 100644 --- a/src/google/protobuf/compiler/java/string_field.cc +++ b/src/google/protobuf/compiler/java/string_field.cc @@ -379,7 +379,7 @@ void ImmutableStringFieldGenerator::GenerateKotlinDslMembers( io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$kt_deprecation$public var $kt_name$: kotlin.String\n" + "$kt_deprecation$var $kt_name$: kotlin.String\n" " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" diff --git a/src/google/protobuf/compiler/java/string_field_lite.cc b/src/google/protobuf/compiler/java/string_field_lite.cc index 62e8273f2d3d..8e5b230b8b3a 100644 --- a/src/google/protobuf/compiler/java/string_field_lite.cc +++ b/src/google/protobuf/compiler/java/string_field_lite.cc @@ -313,7 +313,7 @@ void ImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers( io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$kt_deprecation$public var $kt_name$: kotlin.String\n" + "$kt_deprecation$var $kt_name$: kotlin.String\n" " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" From e1d39a744fcb1628f33ec4c60b033368a506bb6e Mon Sep 17 00:00:00 2001 From: heretic Date: Tue, 5 Apr 2022 16:39:09 +0300 Subject: [PATCH 40/54] add push/pop GetObject macro --- src/google/protobuf/port_def.inc | 2 ++ src/google/protobuf/port_undef.inc | 1 + 2 files changed, 3 insertions(+) diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc index 8b8d78d421a4..657ffe722f6b 100644 --- a/src/google/protobuf/port_def.inc +++ b/src/google/protobuf/port_def.inc @@ -779,6 +779,8 @@ #undef GetClassName #pragma push_macro("GetMessage") #undef GetMessage +#pragma push_macro("GetObject") +#undef GetObject #pragma push_macro("IGNORE") #undef IGNORE #pragma push_macro("IN") diff --git a/src/google/protobuf/port_undef.inc b/src/google/protobuf/port_undef.inc index 90295ee82027..c7a102ffcc95 100644 --- a/src/google/protobuf/port_undef.inc +++ b/src/google/protobuf/port_undef.inc @@ -114,6 +114,7 @@ #pragma pop_macro("ERROR_NOT_FOUND") #pragma pop_macro("GetClassName") #pragma pop_macro("GetMessage") +#pragma pop_macro("GetObject") #pragma pop_macro("IGNORE") #pragma pop_macro("IN") #pragma pop_macro("INPUT_KEYBOARD") From 1e60bd62edcb40d51ed66a690e4b58458a9744ae Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Tue, 5 Apr 2022 10:36:07 -0400 Subject: [PATCH 41/54] Update the mac python helper scripts to python3. macOS 12.3 dropped shipping python2. Update things for python3 (mostly via 2to3). --- objectivec/DevTools/pddm.py | 11 +- objectivec/DevTools/pddm_tests.py | 166 +++++++++++++++--------------- 2 files changed, 90 insertions(+), 87 deletions(-) diff --git a/objectivec/DevTools/pddm.py b/objectivec/DevTools/pddm.py index b572cc75b618..7d0f7ab11c22 100755 --- a/objectivec/DevTools/pddm.py +++ b/objectivec/DevTools/pddm.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/python3 # # Protocol Buffers - Google's data interchange format # Copyright 2015 Google Inc. All rights reserved. @@ -134,7 +134,10 @@ def _MacroArgRefRe(macro_arg_names): class PDDMError(Exception): """Error thrown by pddm.""" - pass + + def __init__(self, message="Error"): + self.message = message + super().__init__(self.message) class MacroCollection(object): @@ -318,7 +321,7 @@ def _ReplaceArgValues(self, # Nothing to do return macro.body assert len(arg_values) == len(macro.args) - args = dict(zip(macro.args, arg_values)) + args = dict(list(zip(macro.args, arg_values))) def _lookupArg(match): val = args[match.group('name')] @@ -351,7 +354,7 @@ def _lookupArg(match): return macro_arg_ref_re.sub(_lookupArg, macro.body) def _EvalMacrosRefs(self, text, macro_stack): - macro_ref_re = _MacroRefRe(self._macros.keys()) + macro_ref_re = _MacroRefRe(list(self._macros.keys())) def _resolveMacro(match): return self._Expand(match, macro_stack) diff --git a/objectivec/DevTools/pddm_tests.py b/objectivec/DevTools/pddm_tests.py index 81842090ccaa..a6571f6f4fff 100755 --- a/objectivec/DevTools/pddm_tests.py +++ b/objectivec/DevTools/pddm_tests.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/python3 # # Protocol Buffers - Google's data interchange format # Copyright 2015 Google Inc. All rights reserved. @@ -41,24 +41,24 @@ class TestParsingMacros(unittest.TestCase): def testParseEmpty(self): - f = io.StringIO(u'') + f = io.StringIO('') result = pddm.MacroCollection(f) self.assertEqual(len(result._macros), 0) def testParseOne(self): - f = io.StringIO(u"""PDDM-DEFINE foo( ) + f = io.StringIO("""PDDM-DEFINE foo( ) body""") result = pddm.MacroCollection(f) self.assertEqual(len(result._macros), 1) macro = result._macros.get('foo') self.assertIsNotNone(macro) - self.assertEquals(macro.name, 'foo') - self.assertEquals(macro.args, tuple()) - self.assertEquals(macro.body, 'body') + self.assertEqual(macro.name, 'foo') + self.assertEqual(macro.args, tuple()) + self.assertEqual(macro.body, 'body') def testParseGeneral(self): # Tests multiple defines, spaces in all places, etc. - f = io.StringIO(u""" + f = io.StringIO(""" PDDM-DEFINE noArgs( ) body1 body2 @@ -74,21 +74,21 @@ def testParseGeneral(self): self.assertEqual(len(result._macros), 3) macro = result._macros.get('noArgs') self.assertIsNotNone(macro) - self.assertEquals(macro.name, 'noArgs') - self.assertEquals(macro.args, tuple()) - self.assertEquals(macro.body, 'body1\nbody2\n') + self.assertEqual(macro.name, 'noArgs') + self.assertEqual(macro.args, tuple()) + self.assertEqual(macro.body, 'body1\nbody2\n') macro = result._macros.get('oneArg') self.assertIsNotNone(macro) - self.assertEquals(macro.name, 'oneArg') - self.assertEquals(macro.args, ('foo',)) - self.assertEquals(macro.body, 'body3') + self.assertEqual(macro.name, 'oneArg') + self.assertEqual(macro.args, ('foo',)) + self.assertEqual(macro.body, 'body3') macro = result._macros.get('twoArgs') self.assertIsNotNone(macro) - self.assertEquals(macro.name, 'twoArgs') - self.assertEquals(macro.args, ('bar_', 'baz')) - self.assertEquals(macro.body, 'body4\nbody5') + self.assertEqual(macro.name, 'twoArgs') + self.assertEqual(macro.args, ('bar_', 'baz')) + self.assertEqual(macro.body, 'body4\nbody5') # Add into existing collection - f = io.StringIO(u""" + f = io.StringIO(""" PDDM-DEFINE another(a,b,c) body1 body2""") @@ -96,23 +96,23 @@ def testParseGeneral(self): self.assertEqual(len(result._macros), 4) macro = result._macros.get('another') self.assertIsNotNone(macro) - self.assertEquals(macro.name, 'another') - self.assertEquals(macro.args, ('a', 'b', 'c')) - self.assertEquals(macro.body, 'body1\nbody2') + self.assertEqual(macro.name, 'another') + self.assertEqual(macro.args, ('a', 'b', 'c')) + self.assertEqual(macro.body, 'body1\nbody2') def testParseDirectiveIssues(self): test_list = [ # Unknown directive - (u'PDDM-DEFINE foo()\nbody\nPDDM-DEFINED foo\nbaz', + ('PDDM-DEFINE foo()\nbody\nPDDM-DEFINED foo\nbaz', 'Hit a line with an unknown directive: '), # End without begin - (u'PDDM-DEFINE foo()\nbody\nPDDM-DEFINE-END\nPDDM-DEFINE-END\n', + ('PDDM-DEFINE foo()\nbody\nPDDM-DEFINE-END\nPDDM-DEFINE-END\n', 'Got DEFINE-END directive without an active macro: '), # Line not in macro block - (u'PDDM-DEFINE foo()\nbody\nPDDM-DEFINE-END\nmumble\n', + ('PDDM-DEFINE foo()\nbody\nPDDM-DEFINE-END\nmumble\n', 'Hit a line that wasn\'t a directive and no open macro definition: '), # Redefine macro - (u'PDDM-DEFINE foo()\nbody\nPDDM-DEFINE foo(a)\nmumble\n', + ('PDDM-DEFINE foo()\nbody\nPDDM-DEFINE foo(a)\nmumble\n', 'Attempt to redefine macro: '), ] for idx, (input_str, expected_prefix) in enumerate(test_list, 1): @@ -127,47 +127,47 @@ def testParseDirectiveIssues(self): def testParseBeginIssues(self): test_list = [ # 1. No name - (u'PDDM-DEFINE\nmumble', + ('PDDM-DEFINE\nmumble', 'Failed to parse macro definition: '), # 2. No name (with spaces) - (u'PDDM-DEFINE \nmumble', + ('PDDM-DEFINE \nmumble', 'Failed to parse macro definition: '), # 3. No open paren - (u'PDDM-DEFINE foo\nmumble', + ('PDDM-DEFINE foo\nmumble', 'Failed to parse macro definition: '), # 4. No close paren - (u'PDDM-DEFINE foo(\nmumble', + ('PDDM-DEFINE foo(\nmumble', 'Failed to parse macro definition: '), # 5. No close paren (with args) - (u'PDDM-DEFINE foo(a, b\nmumble', + ('PDDM-DEFINE foo(a, b\nmumble', 'Failed to parse macro definition: '), # 6. No name before args - (u'PDDM-DEFINE (a, b)\nmumble', + ('PDDM-DEFINE (a, b)\nmumble', 'Failed to parse macro definition: '), # 7. No name before args - (u'PDDM-DEFINE foo bar(a, b)\nmumble', + ('PDDM-DEFINE foo bar(a, b)\nmumble', 'Failed to parse macro definition: '), # 8. Empty arg name - (u'PDDM-DEFINE foo(a, ,b)\nmumble', + ('PDDM-DEFINE foo(a, ,b)\nmumble', 'Empty arg name in macro definition: '), - (u'PDDM-DEFINE foo(a,,b)\nmumble', + ('PDDM-DEFINE foo(a,,b)\nmumble', 'Empty arg name in macro definition: '), # 10. Duplicate name - (u'PDDM-DEFINE foo(a,b,a,c)\nmumble', + ('PDDM-DEFINE foo(a,b,a,c)\nmumble', 'Arg name "a" used more than once in macro definition: '), # 11. Invalid arg name - (u'PDDM-DEFINE foo(a b,c)\nmumble', + ('PDDM-DEFINE foo(a b,c)\nmumble', 'Invalid arg name "a b" in macro definition: '), - (u'PDDM-DEFINE foo(a.b,c)\nmumble', + ('PDDM-DEFINE foo(a.b,c)\nmumble', 'Invalid arg name "a.b" in macro definition: '), - (u'PDDM-DEFINE foo(a-b,c)\nmumble', + ('PDDM-DEFINE foo(a-b,c)\nmumble', 'Invalid arg name "a-b" in macro definition: '), - (u'PDDM-DEFINE foo(a,b,c.)\nmumble', + ('PDDM-DEFINE foo(a,b,c.)\nmumble', 'Invalid arg name "c." in macro definition: '), # 15. Extra stuff after the name - (u'PDDM-DEFINE foo(a,c) foo\nmumble', + ('PDDM-DEFINE foo(a,c) foo\nmumble', 'Failed to parse macro definition: '), - (u'PDDM-DEFINE foo(a,c) foo)\nmumble', + ('PDDM-DEFINE foo(a,c) foo)\nmumble', 'Failed to parse macro definition: '), ] for idx, (input_str, expected_prefix) in enumerate(test_list, 1): @@ -183,7 +183,7 @@ def testParseBeginIssues(self): class TestExpandingMacros(unittest.TestCase): def testExpandBasics(self): - f = io.StringIO(u""" + f = io.StringIO(""" PDDM-DEFINE noArgs( ) body1 body2 @@ -203,21 +203,21 @@ def testExpandBasics(self): """) mc = pddm.MacroCollection(f) test_list = [ - (u'noArgs()', + ('noArgs()', 'body1\nbody2\n'), - (u'oneArg(wee)', + ('oneArg(wee)', 'body3 wee\n'), - (u'twoArgs(having some, fun)', + ('twoArgs(having some, fun)', 'body4 having some fun\nbody5'), # One arg, pass empty. - (u'oneArg()', + ('oneArg()', 'body3 \n'), # Two args, gets empty in each slot. - (u'twoArgs(, empty)', + ('twoArgs(, empty)', 'body4 empty\nbody5'), - (u'twoArgs(empty, )', + ('twoArgs(empty, )', 'body4 empty \nbody5'), - (u'twoArgs(, )', + ('twoArgs(, )', 'body4 \nbody5'), ] for idx, (input_str, expected) in enumerate(test_list, 1): @@ -227,7 +227,7 @@ def testExpandBasics(self): (idx, result, expected)) def testExpandArgOptions(self): - f = io.StringIO(u""" + f = io.StringIO(""" PDDM-DEFINE bar(a) a-a$S-a$l-a$L-a$u-a$U PDDM-DEFINE-END @@ -240,7 +240,7 @@ def testExpandArgOptions(self): self.assertEqual(mc.Expand('bar()'), '-----') def testExpandSimpleMacroErrors(self): - f = io.StringIO(u""" + f = io.StringIO(""" PDDM-DEFINE foo(a, b) PDDM-DEFINE baz(a) @@ -249,19 +249,19 @@ def testExpandSimpleMacroErrors(self): mc = pddm.MacroCollection(f) test_list = [ # 1. Unknown macro - (u'bar()', + ('bar()', 'No macro named "bar".'), - (u'bar(a)', + ('bar(a)', 'No macro named "bar".'), # 3. Arg mismatch - (u'foo()', + ('foo()', 'Expected 2 args, got: "foo()".'), - (u'foo(a b)', + ('foo(a b)', 'Expected 2 args, got: "foo(a b)".'), - (u'foo(a,b,c)', + ('foo(a,b,c)', 'Expected 2 args, got: "foo(a,b,c)".'), # 6. Unknown option in expansion - (u'baz(mumble)', + ('baz(mumble)', 'Unknown arg option "a$z" while expanding "baz(mumble)".'), ] for idx, (input_str, expected_err) in enumerate(test_list, 1): @@ -273,7 +273,7 @@ def testExpandSimpleMacroErrors(self): 'Entry %d failed: %r' % (idx, e)) def testExpandReferences(self): - f = io.StringIO(u""" + f = io.StringIO(""" PDDM-DEFINE StartIt() foo(abc, def) foo(ghi, jkl) @@ -301,7 +301,7 @@ def testExpandReferences(self): self.assertEqual(mc.Expand('StartIt()'), expected) def testCatchRecursion(self): - f = io.StringIO(u""" + f = io.StringIO(""" PDDM-DEFINE foo(a, b) bar(1, a) bar(2, b) @@ -322,29 +322,29 @@ class TestParsingSource(unittest.TestCase): def testBasicParse(self): test_list = [ # 1. no directives - (u'a\nb\nc', + ('a\nb\nc', (3,) ), # 2. One define - (u'a\n//%PDDM-DEFINE foo()\n//%body\nc', + ('a\n//%PDDM-DEFINE foo()\n//%body\nc', (1, 2, 1) ), # 3. Two defines - (u'a\n//%PDDM-DEFINE foo()\n//%body\n//%PDDM-DEFINE bar()\n//%body2\nc', + ('a\n//%PDDM-DEFINE foo()\n//%body\n//%PDDM-DEFINE bar()\n//%body2\nc', (1, 4, 1) ), # 4. Two defines with ends - (u'a\n//%PDDM-DEFINE foo()\n//%body\n//%PDDM-DEFINE-END\n' - u'//%PDDM-DEFINE bar()\n//%body2\n//%PDDM-DEFINE-END\nc', + ('a\n//%PDDM-DEFINE foo()\n//%body\n//%PDDM-DEFINE-END\n' + '//%PDDM-DEFINE bar()\n//%body2\n//%PDDM-DEFINE-END\nc', (1, 6, 1) ), # 5. One expand, one define (that runs to end of file) - (u'a\n//%PDDM-EXPAND foo()\nbody\n//%PDDM-EXPAND-END\n' - u'//%PDDM-DEFINE bar()\n//%body2\n', + ('a\n//%PDDM-EXPAND foo()\nbody\n//%PDDM-EXPAND-END\n' + '//%PDDM-DEFINE bar()\n//%body2\n', (1, 1, 2) ), # 6. One define ended with an expand. - (u'a\nb\n//%PDDM-DEFINE bar()\n//%body2\n' - u'//%PDDM-EXPAND bar()\nbody2\n//%PDDM-EXPAND-END\n', + ('a\nb\n//%PDDM-DEFINE bar()\n//%body2\n' + '//%PDDM-EXPAND bar()\nbody2\n//%PDDM-EXPAND-END\n', (2, 2, 1) ), # 7. Two expands (one end), one define. - (u'a\n//%PDDM-EXPAND foo(1)\nbody\n//%PDDM-EXPAND foo(2)\nbody2\n//%PDDM-EXPAND-END\n' - u'//%PDDM-DEFINE foo()\n//%body2\n', + ('a\n//%PDDM-EXPAND foo(1)\nbody\n//%PDDM-EXPAND foo(2)\nbody2\n//%PDDM-EXPAND-END\n' + '//%PDDM-DEFINE foo()\n//%body2\n', (1, 2, 2) ), ] for idx, (input_str, line_counts) in enumerate(test_list, 1): @@ -362,24 +362,24 @@ def testBasicParse(self): def testErrors(self): test_list = [ # 1. Directive within expansion - (u'//%PDDM-EXPAND a()\n//%PDDM-BOGUS', + ('//%PDDM-EXPAND a()\n//%PDDM-BOGUS', 'Ran into directive ("//%PDDM-BOGUS", line 2) while in "//%PDDM-EXPAND a()".'), - (u'//%PDDM-EXPAND a()\n//%PDDM-DEFINE a()\n//%body\n', + ('//%PDDM-EXPAND a()\n//%PDDM-DEFINE a()\n//%body\n', 'Ran into directive ("//%PDDM-DEFINE", line 2) while in "//%PDDM-EXPAND a()".'), # 3. Expansion ran off end of file - (u'//%PDDM-EXPAND a()\na\nb\n', + ('//%PDDM-EXPAND a()\na\nb\n', 'Hit the end of the file while in "//%PDDM-EXPAND a()".'), # 4. Directive within define - (u'//%PDDM-DEFINE a()\n//%body\n//%PDDM-BOGUS', + ('//%PDDM-DEFINE a()\n//%body\n//%PDDM-BOGUS', 'Ran into directive ("//%PDDM-BOGUS", line 3) while in "//%PDDM-DEFINE a()".'), - (u'//%PDDM-DEFINE a()\n//%body\n//%PDDM-EXPAND-END a()', + ('//%PDDM-DEFINE a()\n//%body\n//%PDDM-EXPAND-END a()', 'Ran into directive ("//%PDDM-EXPAND-END", line 3) while in "//%PDDM-DEFINE a()".'), # 6. Directives that shouldn't start sections - (u'a\n//%PDDM-DEFINE-END a()\n//a\n', + ('a\n//%PDDM-DEFINE-END a()\n//a\n', 'Unexpected line 2: "//%PDDM-DEFINE-END a()".'), - (u'a\n//%PDDM-EXPAND-END a()\n//a\n', + ('a\n//%PDDM-EXPAND-END a()\n//a\n', 'Unexpected line 2: "//%PDDM-EXPAND-END a()".'), - (u'//%PDDM-BOGUS\n//a\n', + ('//%PDDM-BOGUS\n//a\n', 'Unexpected line 1: "//%PDDM-BOGUS".'), ] for idx, (input_str, expected_err) in enumerate(test_list, 1): @@ -395,7 +395,7 @@ class TestProcessingSource(unittest.TestCase): def testBasics(self): self.maxDiff = None - input_str = u""" + input_str = """ //%PDDM-IMPORT-DEFINES ImportFile foo //%PDDM-EXPAND mumble(abc) @@ -408,12 +408,12 @@ def testBasics(self): //%PDDM-DEFINE mumble(a_) //%a_: getName(a_) """ - input_str2 = u""" + input_str2 = """ //%PDDM-DEFINE getName(x_) //%do##x_$u##(int x_); """ - expected = u""" + expected = """ //%PDDM-IMPORT-DEFINES ImportFile foo //%PDDM-EXPAND mumble(abc) @@ -441,7 +441,7 @@ def testBasics(self): //%PDDM-DEFINE mumble(a_) //%a_: getName(a_) """ - expected_stripped = u""" + expected_stripped = """ //%PDDM-IMPORT-DEFINES ImportFile foo //%PDDM-EXPAND mumble(abc) @@ -478,7 +478,7 @@ def _Resolver(name): self.assertEqual(sf2.processed_content, expected_stripped) def testProcessFileWithMacroParseError(self): - input_str = u""" + input_str = """ foo //%PDDM-DEFINE mumble(a_) //%body @@ -498,7 +498,7 @@ def testProcessFileWithMacroParseError(self): ' Line 3: //%PDDM-DEFINE mumble(a_)') def testProcessFileWithExpandError(self): - input_str = u""" + input_str = """ foo //%PDDM-DEFINE mumble(a_) //%body From 75dd25b0fd1b23310c59a7a68719a388b3745a93 Mon Sep 17 00:00:00 2001 From: Roni Lichtman Date: Tue, 5 Apr 2022 17:46:00 +0300 Subject: [PATCH 42/54] Remove unused `HasTopLevelEnums` function This will address the following compilation error: ``` src/google/protobuf/compiler/python/python_generator.cc:95:13: warning: unused function 'HasTopLevelEnums' [-Wunused-function] ``` --- src/google/protobuf/compiler/python/generator.cc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/google/protobuf/compiler/python/generator.cc b/src/google/protobuf/compiler/python/generator.cc index 803947431fc9..7c6a412e3634 100644 --- a/src/google/protobuf/compiler/python/generator.cc +++ b/src/google/protobuf/compiler/python/generator.cc @@ -90,12 +90,6 @@ std::string ModuleAlias(const std::string& filename) { // in proto2/public/reflection.py. const char kDescriptorKey[] = "DESCRIPTOR"; - -// Does the file have top-level enums? -inline bool HasTopLevelEnums(const FileDescriptor* file) { - return file->enum_type_count() > 0; -} - // file output by this generator. void PrintTopBoilerplate(io::Printer* printer, const FileDescriptor* file, bool descriptor_proto) { From ca30339529ec44ea0e5c37e3ddd42d1f188cde41 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Tue, 5 Apr 2022 14:07:04 -0400 Subject: [PATCH 43/54] Tweak how python/python3 is used. The kokoro Mac configs seem to be pretty old without python3, tweak how things are invoked to try and better deal with those configs. --- objectivec/DevTools/full_mac_build.sh | 10 ++++++++-- objectivec/DevTools/pddm.py | 2 +- objectivec/DevTools/pddm_tests.py | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/objectivec/DevTools/full_mac_build.sh b/objectivec/DevTools/full_mac_build.sh index 49b0ff404b55..0e183f20ca18 100755 --- a/objectivec/DevTools/full_mac_build.sh +++ b/objectivec/DevTools/full_mac_build.sh @@ -234,8 +234,14 @@ fi objectivec/generate_well_known_types.sh --check-only -j "${NUM_MAKE_JOBS}" header "Checking on the ObjC Runtime Code" -objectivec/DevTools/pddm_tests.py -if ! objectivec/DevTools/pddm.py --dry-run objectivec/*.[hm] objectivec/Tests/*.[hm] ; then +# Some of the kokoro machines don't have python3 yet, so fall back to python if need be. +if hash python3 >/dev/null 2>&1 ; then + LOCAL_PYTHON=python3 +else + LOCAL_PYTHON=python +fi +"${LOCAL_PYTHON}" objectivec/DevTools/pddm_tests.py +if ! "${LOCAL_PYTHON}" objectivec/DevTools/pddm.py --dry-run objectivec/*.[hm] objectivec/Tests/*.[hm] ; then echo "" echo "Update by running:" echo " objectivec/DevTools/pddm.py objectivec/*.[hm] objectivec/Tests/*.[hm]" diff --git a/objectivec/DevTools/pddm.py b/objectivec/DevTools/pddm.py index 7d0f7ab11c22..60ff0894a108 100755 --- a/objectivec/DevTools/pddm.py +++ b/objectivec/DevTools/pddm.py @@ -1,4 +1,4 @@ -#! /usr/bin/python3 +#! /usr/bin/env python3 # # Protocol Buffers - Google's data interchange format # Copyright 2015 Google Inc. All rights reserved. diff --git a/objectivec/DevTools/pddm_tests.py b/objectivec/DevTools/pddm_tests.py index a6571f6f4fff..d5b88c93c703 100755 --- a/objectivec/DevTools/pddm_tests.py +++ b/objectivec/DevTools/pddm_tests.py @@ -1,4 +1,4 @@ -#! /usr/bin/python3 +#! /usr/bin/env python3 # # Protocol Buffers - Google's data interchange format # Copyright 2015 Google Inc. All rights reserved. From 9a4c48a5666c75e0ccb47ecd0d9d8790c4a9a76c Mon Sep 17 00:00:00 2001 From: Deanna Garcia Date: Wed, 6 Apr 2022 17:42:12 +0000 Subject: [PATCH 44/54] Add k8 toolchain --- toolchain/BUILD | 9 +++++++++ toolchain/cc_toolchain_config.bzl | 17 ++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/toolchain/BUILD b/toolchain/BUILD index ad0f295d2ec7..b171c227b9ec 100644 --- a/toolchain/BUILD +++ b/toolchain/BUILD @@ -14,6 +14,7 @@ TOOLCHAINS = { "linux-x86_64": "cc-compiler-linux-x86_64", "win32": "cc-compiler-windows-x86_32", "win64": "cc-compiler-windows-x86_64", + "k8": "cc-compiler-k8", } cc_toolchain_suite( @@ -39,6 +40,14 @@ cc_toolchain_suite( for cpu, toolchain in TOOLCHAINS.items() ] +cc_toolchain_config( + name = "k8-config", + linker_path = "/usr/bin/ld", + sysroot = "/opt/manylinux/2014/x86_64", + target_cpu = "x86_64", + target_full_name = "x86_64-linux-gnu", +) + cc_toolchain_config( name = "linux-aarch_64-config", sysroot = "/opt/manylinux/2014/aarch64", diff --git a/toolchain/cc_toolchain_config.bzl b/toolchain/cc_toolchain_config.bzl index 2d3c9b66b499..afe66a8f4d73 100644 --- a/toolchain/cc_toolchain_config.bzl +++ b/toolchain/cc_toolchain_config.bzl @@ -157,6 +157,21 @@ def _impl(ctx): ], ) + features = [linker_flags, compiler_flags, sysroot_flags] + + if "mingw" in ctx.attr.target_full_name: + features.append( + feature( + name = "targets_windows", + enabled = True, + #implies = ["copy_dynamic_libraries_to_binary"], + ) + ) + else: + features.append( + feature(name = "supports_pic", enabled = True) + ) + return cc_common.create_cc_toolchain_config_info( abi_libc_version = ctx.attr.abi_version, abi_version = ctx.attr.abi_version, @@ -169,7 +184,7 @@ def _impl(ctx): "/usr/local/include", "/usr/local/lib/clang", ], - features = [linker_flags, compiler_flags, sysroot_flags], + features = features, host_system_name = "local", target_cpu = ctx.attr.target_cpu, target_libc = ctx.attr.target_cpu, From b7980cd85928a7b78f1dbfc42a885e8f9c162235 Mon Sep 17 00:00:00 2001 From: Deanna Garcia Date: Wed, 6 Apr 2022 17:44:20 +0000 Subject: [PATCH 45/54] Removing comment --- toolchain/cc_toolchain_config.bzl | 1 - 1 file changed, 1 deletion(-) diff --git a/toolchain/cc_toolchain_config.bzl b/toolchain/cc_toolchain_config.bzl index afe66a8f4d73..685ca9c32ff0 100644 --- a/toolchain/cc_toolchain_config.bzl +++ b/toolchain/cc_toolchain_config.bzl @@ -164,7 +164,6 @@ def _impl(ctx): feature( name = "targets_windows", enabled = True, - #implies = ["copy_dynamic_libraries_to_binary"], ) ) else: From b55c8e40843855716c79aaa9a01aca89c636cf65 Mon Sep 17 00:00:00 2001 From: Derek Perez Date: Wed, 6 Apr 2022 11:35:10 -0700 Subject: [PATCH 46/54] include gen_dir irrespsective of sources_dir in protoc_gen (#9735) --- protobuf.bzl | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/protobuf.bzl b/protobuf.bzl index 8e173fd7d527..2dc4ecdee37d 100644 --- a/protobuf.bzl +++ b/protobuf.bzl @@ -79,17 +79,20 @@ def _proto_gen_impl(ctx): deps = depset(direct=ctx.files.srcs) source_dir = _SourceDir(ctx) gen_dir = _GenDir(ctx).rstrip("/") + import_flags = [] + if source_dir: has_sources = any([src.is_source for src in srcs]) - has_generated = any([not src.is_source for src in srcs]) - import_flags = [] if has_sources: import_flags += ["-I" + source_dir] - if has_generated: - import_flags += ["-I" + gen_dir] - import_flags = depset(direct=import_flags) else: - import_flags = depset(direct=["-I."]) + import_flags += ["-I."] + + has_generated = any([not src.is_source for src in srcs]) + if has_generated: + import_flags += ["-I" + gen_dir] + + import_flags = depset(direct=import_flags) for dep in ctx.attr.deps: if type(dep.proto.import_flags) == "list": @@ -163,7 +166,7 @@ def _proto_gen_impl(ctx): for out in outs: orig_command = " ".join( ["$(realpath %s)" % ctx.executable.protoc.path] + args + - import_flags_real + ["-I.", src.basename], + import_flags_real + [src.basename], ) command = ";".join([ 'CMD="%s"' % orig_command, From a8b12d5b6ea275b3ea77bdadd40e78f58ad1b508 Mon Sep 17 00:00:00 2001 From: Deanna Garcia Date: Wed, 6 Apr 2022 18:43:58 +0000 Subject: [PATCH 47/54] Consistent formatting --- toolchain/cc_toolchain_config.bzl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/toolchain/cc_toolchain_config.bzl b/toolchain/cc_toolchain_config.bzl index 685ca9c32ff0..777bb82f9a19 100644 --- a/toolchain/cc_toolchain_config.bzl +++ b/toolchain/cc_toolchain_config.bzl @@ -168,7 +168,10 @@ def _impl(ctx): ) else: features.append( - feature(name = "supports_pic", enabled = True) + feature( + name = "supports_pic", + enabled = True + ) ) return cc_common.create_cc_toolchain_config_info( From d54cafb7c8dffab9cb54d23ed3997207760773dc Mon Sep 17 00:00:00 2001 From: Luc Thevenard Date: Wed, 6 Apr 2022 15:49:08 -0400 Subject: [PATCH 48/54] Avoid negative indexes for JRuby --- ruby/lib/google/protobuf/repeated_field.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/lib/google/protobuf/repeated_field.rb b/ruby/lib/google/protobuf/repeated_field.rb index 5c1e906535da..13b9300b2efd 100644 --- a/ruby/lib/google/protobuf/repeated_field.rb +++ b/ruby/lib/google/protobuf/repeated_field.rb @@ -96,7 +96,7 @@ def last(n=nil) raise ArgumentError, "negative array size" else start = [self.size-n, 0].max - return self[start..-1] + return self[start...self.size] end end From 55177c3574ce2718acf3d91cfcfbe9d035a6836d Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Thu, 7 Apr 2022 14:02:57 +0000 Subject: [PATCH 49/54] -DfailIfNoSpecifiedTests=false (#9753) @jtattermusch @mkruskal-google --- kokoro/linux/aarch64/test_java_aarch64.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kokoro/linux/aarch64/test_java_aarch64.sh b/kokoro/linux/aarch64/test_java_aarch64.sh index 72f1c83738be..1fc324a85cf4 100755 --- a/kokoro/linux/aarch64/test_java_aarch64.sh +++ b/kokoro/linux/aarch64/test_java_aarch64.sh @@ -19,7 +19,7 @@ kokoro/linux/aarch64/dockcross_helpers/run_dockcross_manylinux2014_aarch64.sh ko # the command that will be used to build and test java under an emulator # * IsValidUtf8Test and DecodeUtf8Test tests are being skipped because that take very long under an emulator. -TEST_JAVA_COMMAND="mvn --batch-mode -DskipTests install && mvn --batch-mode -Dtest='**/*Test, !**/*IsValidUtf8Test, !**/*DecodeUtf8Test' -DfailIfNoTests=false surefire:test" +TEST_JAVA_COMMAND="mvn --batch-mode -DskipTests install && mvn --batch-mode -Dtest='**/*Test, !**/*IsValidUtf8Test, !**/*DecodeUtf8Test' -DfailIfNoTests=false -DfailIfNoSpecifiedTests=false surefire:test" # use an actual aarch64 docker image (with a real aarch64 java and maven) to run build & test protobuf java under an emulator # * mount the protobuf root as /work to be able to access the crosscompiled files From 88eb7550a66252234f1e20523feaa5075b359831 Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Thu, 7 Apr 2022 22:10:09 +0000 Subject: [PATCH 50/54] -Dsurefire.failIfNoSpecifiedTests=false (#9761) @mrkruskal --- kokoro/linux/aarch64/test_java_aarch64.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kokoro/linux/aarch64/test_java_aarch64.sh b/kokoro/linux/aarch64/test_java_aarch64.sh index 1fc324a85cf4..874c04a63879 100755 --- a/kokoro/linux/aarch64/test_java_aarch64.sh +++ b/kokoro/linux/aarch64/test_java_aarch64.sh @@ -19,7 +19,7 @@ kokoro/linux/aarch64/dockcross_helpers/run_dockcross_manylinux2014_aarch64.sh ko # the command that will be used to build and test java under an emulator # * IsValidUtf8Test and DecodeUtf8Test tests are being skipped because that take very long under an emulator. -TEST_JAVA_COMMAND="mvn --batch-mode -DskipTests install && mvn --batch-mode -Dtest='**/*Test, !**/*IsValidUtf8Test, !**/*DecodeUtf8Test' -DfailIfNoTests=false -DfailIfNoSpecifiedTests=false surefire:test" +TEST_JAVA_COMMAND="mvn --batch-mode -DskipTests install && mvn --batch-mode -Dtest='**/*Test, !**/*IsValidUtf8Test, !**/*DecodeUtf8Test' -DfailIfNoTests=false -Dsurefire.failIfNoSpecifiedTests=false surefire:test" # use an actual aarch64 docker image (with a real aarch64 java and maven) to run build & test protobuf java under an emulator # * mount the protobuf root as /work to be able to access the crosscompiled files From 85aa87cbc95edfa63df159eec5536e1d39781f11 Mon Sep 17 00:00:00 2001 From: mkruskal-google <62662355+mkruskal-google@users.noreply.github.com> Date: Thu, 7 Apr 2022 15:33:58 -0700 Subject: [PATCH 51/54] Merge 3.20.1-rc1 into main (#9760) * Fix NPE during encoding and add regression test for issue 9507. (cherry picked from commit 58e320a7323b55f65137222064ed0e72fe423e23) * Implement `respond_to?` in RubyMessage (#9677) All synthetic methods implemented by `method_missing` are now supported by `respond_to?`. Fixes issue #9202. * Fix null pointer exceptions exposed by new regression tests. * Fix clear_ on oneofs so that it is safe to call repeatedly and so that respond_to? does not depend on whether the oneof is currently cleared. * Code cleanup: reenable more tests on JRuby. * Align JRuby behavior with CRuby by throwing a RuntimeError when attempting to assign to a oneof. (cherry picked from commit 8e7f93669612a06cafc39625f61258b9d6b77a3c) * Update protobuf version * Merge pull request #9727 from mlocati/build-packaged-php-extension Fix building packaged PHP extension (cherry picked from commit 7f9901c5f640fe0fbcd5dbdd303a269908fb3b62) * Update protobuf version * Update changelogs for 3.20.1-rc1 Co-authored-by: Jason Lunn Co-authored-by: Jorg Brown --- CHANGES.txt | 8 ++++++ Protobuf-C++.podspec | 2 +- Protobuf.podspec | 2 +- configure.ac | 2 +- csharp/Google.Protobuf.Tools.nuspec | 2 +- .../Google.Protobuf/Google.Protobuf.csproj | 2 +- java/README.md | 6 ++--- java/bom/pom.xml | 2 +- java/core/pom.xml | 2 +- java/kotlin-lite/pom.xml | 2 +- java/kotlin/pom.xml | 2 +- java/lite.md | 2 +- java/lite/pom.xml | 2 +- java/pom.xml | 2 +- java/util/pom.xml | 2 +- js/package.json | 2 +- php/ext/google/protobuf/package.xml | 27 ++++++++++++++----- php/ext/google/protobuf/protobuf.h | 2 +- protobuf_version.bzl | 2 +- protoc-artifacts/pom.xml | 2 +- python/google/protobuf/__init__.py | 2 +- ruby/google-protobuf.gemspec | 2 +- ruby/pom.xml | 4 +-- src/Makefile.am | 2 +- src/google/protobuf/any.pb.h | 2 +- src/google/protobuf/api.pb.h | 2 +- src/google/protobuf/compiler/plugin.pb.h | 2 +- src/google/protobuf/descriptor.pb.h | 2 +- src/google/protobuf/duration.pb.h | 2 +- src/google/protobuf/empty.pb.h | 2 +- src/google/protobuf/field_mask.pb.h | 2 +- src/google/protobuf/port_def.inc | 4 +-- src/google/protobuf/source_context.pb.h | 2 +- src/google/protobuf/struct.pb.h | 2 +- src/google/protobuf/stubs/common.h | 4 +-- src/google/protobuf/timestamp.pb.h | 2 +- src/google/protobuf/type.pb.h | 2 +- src/google/protobuf/wrappers.pb.h | 2 +- 38 files changed, 70 insertions(+), 47 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 873c0dce6f3d..03d441f1bfaa 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,11 @@ +2022-04-05 version 3.20.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript) + + PHP + * Fix building packaged PHP extension (#9727) + + Other + * Fix versioning issues in 3.20.0 + Unreleased Changes C++ diff --git a/Protobuf-C++.podspec b/Protobuf-C++.podspec index afc0743af55c..a347abe76833 100644 --- a/Protobuf-C++.podspec +++ b/Protobuf-C++.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Protobuf-C++' - s.version = '3.20.0' + s.version = '3.20.1-rc1' s.summary = 'Protocol Buffers v3 runtime library for C++.' s.homepage = 'https://github.com/google/protobuf' s.license = 'BSD-3-Clause' diff --git a/Protobuf.podspec b/Protobuf.podspec index 92c53c915932..6c6b37bfcce0 100644 --- a/Protobuf.podspec +++ b/Protobuf.podspec @@ -5,7 +5,7 @@ # dependent projects use the :git notation to refer to the library. Pod::Spec.new do |s| s.name = 'Protobuf' - s.version = '3.20.0' + s.version = '3.20.1-rc1' s.summary = 'Protocol Buffers v.3 runtime library for Objective-C.' s.homepage = 'https://github.com/protocolbuffers/protobuf' s.license = 'BSD-3-Clause' diff --git a/configure.ac b/configure.ac index 4db50ce8afde..5de1ce20a97d 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ AC_PREREQ(2.59) # In the SVN trunk, the version should always be the next anticipated release # version with the "-pre" suffix. (We used to use "-SNAPSHOT" but this pushed # the size of one file name in the dist tarfile over the 99-char limit.) -AC_INIT([Protocol Buffers],[3.20.0],[protobuf@googlegroups.com],[protobuf]) +AC_INIT([Protocol Buffers],[3.20.1-rc-1],[protobuf@googlegroups.com],[protobuf]) AM_MAINTAINER_MODE([enable]) diff --git a/csharp/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec index 21b6a624dd4f..06081690fe55 100644 --- a/csharp/Google.Protobuf.Tools.nuspec +++ b/csharp/Google.Protobuf.Tools.nuspec @@ -5,7 +5,7 @@ Google Protocol Buffers tools Tools for Protocol Buffers - Google's data interchange format. See project site for more info. - 3.20.0 + 3.20.1-rc1 Google Inc. protobuf-packages https://github.com/protocolbuffers/protobuf/blob/master/LICENSE diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj index 22253cbc11c9..14a83a0654dc 100644 --- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj +++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj @@ -4,7 +4,7 @@ C# runtime library for Protocol Buffers - Google's data interchange format. Copyright 2015, Google Inc. Google Protocol Buffers - 3.20.0 + 3.20.1-rc1 7.2 Google Inc. diff --git a/java/README.md b/java/README.md index df68050d108a..34b543775eda 100644 --- a/java/README.md +++ b/java/README.md @@ -23,7 +23,7 @@ If you are using Maven, use the following: com.google.protobuf protobuf-java - 3.20.0 + 3.20.1-rc-1 ``` @@ -37,7 +37,7 @@ protobuf-java-util package: com.google.protobuf protobuf-java-util - 3.20.0 + 3.20.1-rc-1 ``` @@ -45,7 +45,7 @@ protobuf-java-util package: If you are using Gradle, add the following to your `build.gradle` file's dependencies: ``` - implementation 'com.google.protobuf:protobuf-java:3.20.0' + implementation 'com.google.protobuf:protobuf-java:3.20.1-rc-1' ``` Again, be sure to check that the version number matches (or is newer than) the version number of protoc that you are using. diff --git a/java/bom/pom.xml b/java/bom/pom.xml index 5ebf16a61bc8..fa31209a304c 100644 --- a/java/bom/pom.xml +++ b/java/bom/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-bom - 3.20.0 + 3.20.1-rc-1 pom Protocol Buffers [BOM] diff --git a/java/core/pom.xml b/java/core/pom.xml index 9dadd70833b5..7fd02c5210d8 100644 --- a/java/core/pom.xml +++ b/java/core/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0 + 3.20.1-rc-1 protobuf-java diff --git a/java/kotlin-lite/pom.xml b/java/kotlin-lite/pom.xml index 11a01024ffc3..2f2ddb66d295 100644 --- a/java/kotlin-lite/pom.xml +++ b/java/kotlin-lite/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0 + 3.20.1-rc-1 protobuf-kotlin-lite diff --git a/java/kotlin/pom.xml b/java/kotlin/pom.xml index fe9e0e52b5f1..d16a1e43338e 100644 --- a/java/kotlin/pom.xml +++ b/java/kotlin/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0 + 3.20.1-rc-1 protobuf-kotlin diff --git a/java/lite.md b/java/lite.md index 6fab856678c3..759d50b5b1aa 100644 --- a/java/lite.md +++ b/java/lite.md @@ -29,7 +29,7 @@ protobuf Java Lite runtime. If you are using Maven, include the following: com.google.protobuf protobuf-javalite - 3.20.0 + 3.20.1-rc-1 ``` diff --git a/java/lite/pom.xml b/java/lite/pom.xml index c2f7e376699e..a2444f0a922c 100644 --- a/java/lite/pom.xml +++ b/java/lite/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0 + 3.20.1-rc-1 protobuf-javalite diff --git a/java/pom.xml b/java/pom.xml index 82f31fb35f9a..7d53c2ef4577 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0 + 3.20.1-rc-1 pom Protocol Buffers [Parent] diff --git a/java/util/pom.xml b/java/util/pom.xml index d9eadd6c29da..75b50aa9ed4e 100644 --- a/java/util/pom.xml +++ b/java/util/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 3.20.0 + 3.20.1-rc-1 protobuf-java-util diff --git a/js/package.json b/js/package.json index e5c9a606c192..eaa973fa7a24 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "google-protobuf", - "version": "3.20.0", + "version": "3.20.1-rc.1", "description": "Protocol Buffers for JavaScript", "main": "google-protobuf.js", "files": [ diff --git a/php/ext/google/protobuf/package.xml b/php/ext/google/protobuf/package.xml index b529dc92f8e3..77cee355ccec 100644 --- a/php/ext/google/protobuf/package.xml +++ b/php/ext/google/protobuf/package.xml @@ -10,15 +10,15 @@ protobuf-opensource@google.com yes - 2022-03-25 - + 2022-04-05 + - 3.20.0 - 3.20.0 + 3.20.1RC1 + 3.20.1 - stable - stable + beta + beta BSD-3-Clause @@ -1253,5 +1253,20 @@ G A release. + + + 3.20.1RC1 + 3.20.1 + + + beta + beta + + 2022-04-05 + + BSD-3-Clause + + + diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h index 01be62af7837..f20e8ee41e5d 100644 --- a/php/ext/google/protobuf/protobuf.h +++ b/php/ext/google/protobuf/protobuf.h @@ -127,7 +127,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_setter, 0, 0, 1) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() -#define PHP_PROTOBUF_VERSION "3.20.0" +#define PHP_PROTOBUF_VERSION "3.20.1RC1" // ptr -> PHP object cache. This is a weak map that caches lazily-created // wrapper objects around upb types: diff --git a/protobuf_version.bzl b/protobuf_version.bzl index a62513fb3099..404a6437fc3c 100644 --- a/protobuf_version.bzl +++ b/protobuf_version.bzl @@ -1 +1 @@ -PROTOBUF_VERSION = '3.20.0' +PROTOBUF_VERSION = '3.20.1-rc-1' diff --git a/protoc-artifacts/pom.xml b/protoc-artifacts/pom.xml index a667c52dc84d..31f7b85bbb99 100644 --- a/protoc-artifacts/pom.xml +++ b/protoc-artifacts/pom.xml @@ -8,7 +8,7 @@ com.google.protobuf protoc - 3.20.0 + 3.20.1-rc-1 pom Protobuf Compiler diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py index 39555e643e2e..3cacc4fad62e 100644 --- a/python/google/protobuf/__init__.py +++ b/python/google/protobuf/__init__.py @@ -30,4 +30,4 @@ # Copyright 2007 Google Inc. All Rights Reserved. -__version__ = '3.20.0' +__version__ = '3.20.1rc1' diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec index fa99970d025f..3197368f6902 100644 --- a/ruby/google-protobuf.gemspec +++ b/ruby/google-protobuf.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "google-protobuf" - s.version = "3.20.0" + s.version = "3.20.1.rc.1" git_tag = "v#{s.version.to_s.sub('.rc.', '-rc')}" # Converts X.Y.Z.rc.N to vX.Y.Z-rcN, used for the git tag s.licenses = ["BSD-3-Clause"] s.summary = "Protocol Buffers" diff --git a/ruby/pom.xml b/ruby/pom.xml index 5482c6fcfbb8..de421ef4eb2c 100644 --- a/ruby/pom.xml +++ b/ruby/pom.xml @@ -9,7 +9,7 @@ com.google.protobuf.jruby protobuf-jruby - 3.20.0 + 3.20.1-rc-1 Protocol Buffer JRuby native extension Protocol Buffers are a way of encoding structured data in an efficient yet @@ -76,7 +76,7 @@ com.google.protobuf protobuf-java-util - 3.20.0 + 3.20.1-rc-1 org.jruby diff --git a/src/Makefile.am b/src/Makefile.am index 4139b09261e1..f3e3f272ce35 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,7 @@ else PTHREAD_DEF = endif -PROTOBUF_VERSION = 31:0:0 +PROTOBUF_VERSION = 31:1:0 if GCC # Turn on all warnings except for sign comparison (we ignore sign comparison diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h index c28bf72db3e4..7dd5d0f82a54 100644 --- a/src/google/protobuf/any.pb.h +++ b/src/google/protobuf/any.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3020000 < PROTOBUF_MIN_PROTOC_VERSION +#if 3020001 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h index bfbfa2c9c347..744e4677108d 100644 --- a/src/google/protobuf/api.pb.h +++ b/src/google/protobuf/api.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3020000 < PROTOBUF_MIN_PROTOC_VERSION +#if 3020001 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h index f0c325a90002..07bbaa38dbd9 100644 --- a/src/google/protobuf/compiler/plugin.pb.h +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3020000 < PROTOBUF_MIN_PROTOC_VERSION +#if 3020001 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index 4ee5e3821cdf..4cd97bc9aefb 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3020000 < PROTOBUF_MIN_PROTOC_VERSION +#if 3020001 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h index bed4ea5a991c..12633a300d84 100644 --- a/src/google/protobuf/duration.pb.h +++ b/src/google/protobuf/duration.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3020000 < PROTOBUF_MIN_PROTOC_VERSION +#if 3020001 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h index 67471da81dbf..38480a78e2d5 100644 --- a/src/google/protobuf/empty.pb.h +++ b/src/google/protobuf/empty.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3020000 < PROTOBUF_MIN_PROTOC_VERSION +#if 3020001 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h index 8af33dd44f32..ae350d561050 100644 --- a/src/google/protobuf/field_mask.pb.h +++ b/src/google/protobuf/field_mask.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3020000 < PROTOBUF_MIN_PROTOC_VERSION +#if 3020001 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc index 657ffe722f6b..d2e9f9c9c73b 100644 --- a/src/google/protobuf/port_def.inc +++ b/src/google/protobuf/port_def.inc @@ -157,7 +157,7 @@ #ifdef PROTOBUF_VERSION #error PROTOBUF_VERSION was previously defined #endif -#define PROTOBUF_VERSION 3020000 +#define PROTOBUF_VERSION 3020001 #ifdef PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC #error PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC was previously defined @@ -172,7 +172,7 @@ #ifdef PROTOBUF_VERSION_SUFFIX #error PROTOBUF_VERSION_SUFFIX was previously defined #endif -#define PROTOBUF_VERSION_SUFFIX "" +#define PROTOBUF_VERSION_SUFFIX "-rc1" #if defined(PROTOBUF_NAMESPACE) || defined(PROTOBUF_NAMESPACE_ID) #error PROTOBUF_NAMESPACE or PROTOBUF_NAMESPACE_ID was previously defined diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h index 2a9bb58ce252..275df17bbef0 100644 --- a/src/google/protobuf/source_context.pb.h +++ b/src/google/protobuf/source_context.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3020000 < PROTOBUF_MIN_PROTOC_VERSION +#if 3020001 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h index cd267b1c0e66..08d23e52da94 100644 --- a/src/google/protobuf/struct.pb.h +++ b/src/google/protobuf/struct.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3020000 < PROTOBUF_MIN_PROTOC_VERSION +#if 3020001 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index f88ab442fcad..c54468c90c61 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -82,10 +82,10 @@ namespace internal { // The current version, represented as a single integer to make comparison // easier: major * 10^6 + minor * 10^3 + micro -#define GOOGLE_PROTOBUF_VERSION 3020000 +#define GOOGLE_PROTOBUF_VERSION 3020001 // A suffix string for alpha, beta or rc releases. Empty for stable releases. -#define GOOGLE_PROTOBUF_VERSION_SUFFIX "" +#define GOOGLE_PROTOBUF_VERSION_SUFFIX "-rc1" // The minimum header version which works with the current version of // the library. This constant should only be used by protoc's C++ code diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h index 863aac9877fb..4561e681fa0f 100644 --- a/src/google/protobuf/timestamp.pb.h +++ b/src/google/protobuf/timestamp.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3020000 < PROTOBUF_MIN_PROTOC_VERSION +#if 3020001 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h index 5e9800580e51..57e98d1bfedb 100644 --- a/src/google/protobuf/type.pb.h +++ b/src/google/protobuf/type.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3020000 < PROTOBUF_MIN_PROTOC_VERSION +#if 3020001 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h index ce4d73cdb0f6..59a5ebd740a1 100644 --- a/src/google/protobuf/wrappers.pb.h +++ b/src/google/protobuf/wrappers.pb.h @@ -13,7 +13,7 @@ #error incompatible with your Protocol Buffer headers. Please update #error your headers. #endif -#if 3020000 < PROTOBUF_MIN_PROTOC_VERSION +#if 3020001 < PROTOBUF_MIN_PROTOC_VERSION #error This file was generated by an older version of protoc which is #error incompatible with your Protocol Buffer headers. Please #error regenerate this file with a newer version of protoc. From e3b00bb58a73e64dd01e250faee31e2865038cea Mon Sep 17 00:00:00 2001 From: Jeff Sawatzky <421404+jeffsawatzky@users.noreply.github.com> Date: Fri, 8 Apr 2022 12:08:38 -0400 Subject: [PATCH 52/54] Add Google Gnostic Registered Extension Number (#9754) google/gnostic's protoc-gen-openapi generator has extension support for additional openapi options. It is [currently using `1042`](https://github.com/google/gnostic/blob/master/openapiv3/annotations.proto) which is registered with grpc-gateway's protoc-gen-openapiv2 extension which probably isn't a good thing. See [here](https://github.com/google/gnostic/blob/master/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/message.proto) for an example of the extenstion in action. --- docs/options.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/options.md b/docs/options.md index e7457303409a..fd99f600ea90 100644 --- a/docs/options.md +++ b/docs/options.md @@ -308,4 +308,8 @@ with info about your project (name and website) so we can add an entry for you. 1. Protoc-gen-fieldmask * Website: https://github.com/yeqown/protoc-gen-fieldmask * Extension: 1142 - + +1. Google Gnostic + * Website: https://github.com/google/gnostic + * Extension: 1143 + From 7ffe9402db704f2480828238269ac2e0789e6b04 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Fri, 8 Apr 2022 19:11:27 +0300 Subject: [PATCH 53/54] Add micro Registered Extension Number (#9767) unistack-org/micro (microservices framework) uses protoc-gen-go-micro generator that has extension support for additional framework related options. It is currently not using any registered extension number, so i want to stabilise this and i think that this is a good thing. See here for an example of the extenstion in action. Co-authored-by: Adam Cozzette --- docs/options.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/options.md b/docs/options.md index fd99f600ea90..9b3fb8ec3964 100644 --- a/docs/options.md +++ b/docs/options.md @@ -308,8 +308,11 @@ with info about your project (name and website) so we can add an entry for you. 1. Protoc-gen-fieldmask * Website: https://github.com/yeqown/protoc-gen-fieldmask * Extension: 1142 - + 1. Google Gnostic * Website: https://github.com/google/gnostic * Extension: 1143 +1. Protoc-gen-go-micro + * Website: https://github.com/unistack-org/protoc-gen-go-micro + * Extension: 1144 \ No newline at end of file From 9bf0aca7db4eeaab9eb856eb9d5a1925d2bb33a7 Mon Sep 17 00:00:00 2001 From: Adam Cozzette Date: Fri, 8 Apr 2022 09:12:05 -0700 Subject: [PATCH 54/54] Update protobuf_deps.bzl to add a dependency on Abseil (#9752) This is the most recent Abseil LTS branch, from November 2021. We do not yet use Abseil for anything, but this change will make it possible to start using it in Bazel when we're ready. --- protobuf_deps.bzl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/protobuf_deps.bzl b/protobuf_deps.bzl index 601e6c0f6f03..de5d5363f3d7 100644 --- a/protobuf_deps.bzl +++ b/protobuf_deps.bzl @@ -27,6 +27,15 @@ def protobuf_deps(): ], ) + if not native.existing_rule("com_google_absl"): + # Abseil LTS from November 2021 + http_archive( + name = "com_google_absl", + sha256 = "b4e20d9e752a75c10636675691b1e9c2698e0764cb404987d0ffa77223041c19", + urls = ["https://github.com/abseil/abseil-cpp/archive/215105818dfde3174fe799600bb0f3cae233d0bf.zip"], + strip_prefix = "abseil-cpp-215105818dfde3174fe799600bb0f3cae233d0bf", + ) + if not native.existing_rule("zlib"): http_archive( name = "zlib",