google-protobuf 4.26.1 → 4.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of google-protobuf might be problematic. Click here for more details.

Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/ext/google/protobuf_c/convert.c +39 -14
  3. data/ext/google/protobuf_c/defs.c +327 -1
  4. data/ext/google/protobuf_c/glue.c +16 -0
  5. data/ext/google/protobuf_c/map.c +72 -20
  6. data/ext/google/protobuf_c/map.h +6 -2
  7. data/ext/google/protobuf_c/message.c +78 -50
  8. data/ext/google/protobuf_c/message.h +1 -5
  9. data/ext/google/protobuf_c/protobuf.c +11 -9
  10. data/ext/google/protobuf_c/protobuf.h +3 -7
  11. data/ext/google/protobuf_c/repeated_field.c +61 -17
  12. data/ext/google/protobuf_c/repeated_field.h +5 -1
  13. data/ext/google/protobuf_c/ruby-upb.c +1693 -475
  14. data/ext/google/protobuf_c/ruby-upb.h +2526 -1386
  15. data/ext/google/protobuf_c/shared_convert.c +5 -2
  16. data/ext/google/protobuf_c/shared_message.c +0 -30
  17. data/ext/google/protobuf_c/shared_message.h +0 -4
  18. data/lib/google/protobuf/descriptor_pb.rb +2 -1
  19. data/lib/google/protobuf/ffi/descriptor.rb +4 -3
  20. data/lib/google/protobuf/ffi/descriptor_pool.rb +3 -1
  21. data/lib/google/protobuf/ffi/enum_descriptor.rb +3 -1
  22. data/lib/google/protobuf/ffi/ffi.rb +0 -5
  23. data/lib/google/protobuf/ffi/field_descriptor.rb +4 -2
  24. data/lib/google/protobuf/ffi/file_descriptor.rb +3 -1
  25. data/lib/google/protobuf/ffi/internal/arena.rb +0 -6
  26. data/lib/google/protobuf/ffi/internal/convert.rb +14 -7
  27. data/lib/google/protobuf/ffi/map.rb +45 -21
  28. data/lib/google/protobuf/ffi/message.rb +182 -60
  29. data/lib/google/protobuf/ffi/method_descriptor.rb +114 -0
  30. data/lib/google/protobuf/ffi/oneof_descriptor.rb +3 -1
  31. data/lib/google/protobuf/ffi/repeated_field.rb +42 -16
  32. data/lib/google/protobuf/ffi/service_descriptor.rb +107 -0
  33. data/lib/google/protobuf/repeated_field.rb +3 -3
  34. data/lib/google/protobuf_ffi.rb +2 -0
  35. metadata +20 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6b75ef03befb2ebc24da2bd1395901962c7b0ba053ebf3dbf9e48c4414e89452
4
- data.tar.gz: 1ade6d79bcca36e4dafe613c0392c14d5cbadcb721c49cec0651699750b567a8
3
+ metadata.gz: 531c1d4e78630f992244bac8fac8176297a60073b58bd92d344083f478f8dcb5
4
+ data.tar.gz: de1b062231118253de9063e495ce188907760bf536a368a426d0ab1cf59ea5bb
5
5
  SHA512:
6
- metadata.gz: 87a7972ae24b8f883a5dd5fe215184afa703097f3252bc2a4a7e7306c09bdc6d23ce72ea3b0742b3e60928dc46a71fb85df600fc199802b5b8f0db88806204a9
7
- data.tar.gz: cdda124179218236560080105ba0ed5f5dde5137a01fb9db8691533cc4bdcb907d076fe24685227928f3f41cdf456c82e9d067f38ed9a01f18289d6e26504467
6
+ metadata.gz: ec022839412e0210fa1cd44b34d96defb2c83a0ca7c1b84bc62f00526f2af64d70abbfda7c405b0a8eaa718ab366a80bbbd7ee3a072144a539282adc7fb24059
7
+ data.tar.gz: 87463961cb841e762147dcdbd648557cd0a5228e122a717f6429220d485a2dea1fe32f3f1efbcb71504e2b2ad1a191810adcf4327c93bcb047bb6fb244a7748b
@@ -104,6 +104,41 @@ unknownval:
104
104
  rb_raise(rb_eRangeError, "Unknown symbol value for enum field '%s'.", name);
105
105
  }
106
106
 
107
+ VALUE Convert_CheckStringUtf8(VALUE str) {
108
+ VALUE utf8 = rb_enc_from_encoding(rb_utf8_encoding());
109
+
110
+ if (rb_obj_encoding(str) == utf8) {
111
+ // Note: Just because a string is marked as having UTF-8 encoding does
112
+ // not mean that it is *valid* UTF-8. We have to check separately
113
+ // whether it is valid.
114
+ if (rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN) {
115
+ // TODO: For now
116
+ // we only warn for this case. We will remove the warning and throw an
117
+ // exception below in the 30.x release
118
+
119
+ rb_warn(
120
+ "String is invalid UTF-8. This will be an error in a future "
121
+ "version.");
122
+ // VALUE exc = rb_const_get_at(
123
+ // rb_cEncoding, rb_intern("InvalidByteSequenceError"));
124
+ // rb_raise(exc, "String is invalid UTF-8");
125
+ }
126
+ } else {
127
+ // Note: this will not duplicate underlying string data unless
128
+ // necessary.
129
+ //
130
+ // This will throw an exception if the conversion cannot be performed:
131
+ // - Encoding::UndefinedConversionError if certain characters cannot be
132
+ // converted to UTF-8.
133
+ // - Encoding::InvalidByteSequenceError if certain characters were invalid
134
+ // in the source encoding.
135
+ str = rb_str_encode(str, utf8, 0, Qnil);
136
+ PBRUBY_ASSERT(rb_enc_str_coderange(str) != ENC_CODERANGE_BROKEN);
137
+ }
138
+
139
+ return str;
140
+ }
141
+
107
142
  upb_MessageValue Convert_RubyToUpb(VALUE value, const char* name,
108
143
  TypeInfo type_info, upb_Arena* arena) {
109
144
  upb_MessageValue ret;
@@ -137,8 +172,7 @@ upb_MessageValue Convert_RubyToUpb(VALUE value, const char* name,
137
172
  }
138
173
  break;
139
174
  }
140
- case kUpb_CType_String: {
141
- VALUE utf8 = rb_enc_from_encoding(rb_utf8_encoding());
175
+ case kUpb_CType_String:
142
176
  if (rb_obj_class(value) == rb_cSymbol) {
143
177
  value = rb_funcall(value, rb_intern("to_s"), 0);
144
178
  } else if (!rb_obj_is_kind_of(value, rb_cString)) {
@@ -147,19 +181,9 @@ upb_MessageValue Convert_RubyToUpb(VALUE value, const char* name,
147
181
  rb_class2name(CLASS_OF(value)));
148
182
  }
149
183
 
150
- if (rb_obj_encoding(value) != utf8) {
151
- // Note: this will not duplicate underlying string data unless
152
- // necessary.
153
- value = rb_str_encode(value, utf8, 0, Qnil);
154
-
155
- if (rb_enc_str_coderange(value) == ENC_CODERANGE_BROKEN) {
156
- rb_raise(rb_eEncodingError, "String is invalid UTF-8");
157
- }
158
- }
159
-
184
+ value = Convert_CheckStringUtf8(value);
160
185
  ret.str_val = Convert_StringData(value, arena);
161
186
  break;
162
- }
163
187
  case kUpb_CType_Bytes: {
164
188
  VALUE bytes = rb_enc_from_encoding(rb_ascii8bit_encoding());
165
189
  if (rb_obj_class(value) != rb_cString) {
@@ -204,7 +228,8 @@ upb_MessageValue Convert_RubyToUpb(VALUE value, const char* name,
204
228
  ret.uint64_val = NUM2ULL(value);
205
229
  break;
206
230
  default:
207
- break;
231
+ rb_raise(cTypeError, "Convert_RubyToUpb(): Unexpected type %d",
232
+ (int)type_info.type);
208
233
  }
209
234
  break;
210
235
  default:
@@ -23,6 +23,9 @@ static VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_EnumDef* def);
23
23
  static VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_FieldDef* def);
24
24
  static VALUE get_filedef_obj(VALUE descriptor_pool, const upb_FileDef* def);
25
25
  static VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_OneofDef* def);
26
+ static VALUE get_servicedef_obj(VALUE descriptor_pool,
27
+ const upb_ServiceDef* def);
28
+ static VALUE get_methoddef_obj(VALUE descriptor_pool, const upb_MethodDef* def);
26
29
 
27
30
  // A distinct object that is not accessible from Ruby. We use this as a
28
31
  // constructor argument to enforce that certain objects cannot be created from
@@ -153,6 +156,7 @@ static VALUE DescriptorPool_lookup(VALUE _self, VALUE name) {
153
156
  const upb_MessageDef* msgdef;
154
157
  const upb_EnumDef* enumdef;
155
158
  const upb_FieldDef* fielddef;
159
+ const upb_ServiceDef* servicedef;
156
160
 
157
161
  msgdef = upb_DefPool_FindMessageByName(self->symtab, name_str);
158
162
  if (msgdef) {
@@ -169,6 +173,11 @@ static VALUE DescriptorPool_lookup(VALUE _self, VALUE name) {
169
173
  return get_enumdef_obj(_self, enumdef);
170
174
  }
171
175
 
176
+ servicedef = upb_DefPool_FindServiceByName(self->symtab, name_str);
177
+ if (servicedef) {
178
+ return get_servicedef_obj(_self, servicedef);
179
+ }
180
+
172
181
  return Qnil;
173
182
  }
174
183
 
@@ -257,7 +266,20 @@ static VALUE decode_options(VALUE self, const char* option_type, int size,
257
266
  VALUE desc_rb = get_msgdef_obj(descriptor_pool, msgdef);
258
267
  const Descriptor* desc = ruby_to_Descriptor(desc_rb);
259
268
 
260
- options_rb = Message_decode_bytes(size, bytes, 0, desc->klass, true);
269
+ options_rb = Message_decode_bytes(size, bytes, 0, desc->klass, false);
270
+
271
+ // Strip features from the options proto to keep it internal.
272
+ const upb_MessageDef* decoded_desc = NULL;
273
+ upb_Message* options = Message_GetMutable(options_rb, &decoded_desc);
274
+ PBRUBY_ASSERT(options != NULL);
275
+ PBRUBY_ASSERT(decoded_desc == msgdef);
276
+ const upb_FieldDef* field =
277
+ upb_MessageDef_FindFieldByName(decoded_desc, "features");
278
+ PBRUBY_ASSERT(field != NULL);
279
+ upb_Message_ClearFieldByDef(options, field);
280
+
281
+ Message_freeze(options_rb);
282
+
261
283
  rb_ivar_set(self, options_instancevar_interned, options_rb);
262
284
  return options_rb;
263
285
  }
@@ -1294,6 +1316,298 @@ static void EnumDescriptor_register(VALUE module) {
1294
1316
  cEnumDescriptor = klass;
1295
1317
  }
1296
1318
 
1319
+ // -----------------------------------------------------------------------------
1320
+ // ServiceDescriptor
1321
+ // -----------------------------------------------------------------------------
1322
+
1323
+ typedef struct {
1324
+ const upb_ServiceDef* servicedef;
1325
+ // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
1326
+ // macro to update VALUE references, as to trigger write barriers.
1327
+ VALUE module; // begins as nil
1328
+ VALUE descriptor_pool; // Owns the upb_ServiceDef.
1329
+ } ServiceDescriptor;
1330
+
1331
+ static VALUE cServiceDescriptor = Qnil;
1332
+
1333
+ static void ServiceDescriptor_mark(void* _self) {
1334
+ ServiceDescriptor* self = _self;
1335
+ rb_gc_mark(self->module);
1336
+ rb_gc_mark(self->descriptor_pool);
1337
+ }
1338
+
1339
+ static const rb_data_type_t ServiceDescriptor_type = {
1340
+ "Google::Protobuf::ServicDescriptor",
1341
+ {ServiceDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
1342
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1343
+ };
1344
+
1345
+ static ServiceDescriptor* ruby_to_ServiceDescriptor(VALUE val) {
1346
+ ServiceDescriptor* ret;
1347
+ TypedData_Get_Struct(val, ServiceDescriptor, &ServiceDescriptor_type, ret);
1348
+ return ret;
1349
+ }
1350
+
1351
+ static VALUE ServiceDescriptor_alloc(VALUE klass) {
1352
+ ServiceDescriptor* self = ALLOC(ServiceDescriptor);
1353
+ VALUE ret = TypedData_Wrap_Struct(klass, &ServiceDescriptor_type, self);
1354
+ self->servicedef = NULL;
1355
+ self->module = Qnil;
1356
+ self->descriptor_pool = Qnil;
1357
+ return ret;
1358
+ }
1359
+
1360
+ /*
1361
+ * call-seq:
1362
+ * ServiceDescriptor.new(c_only_cookie, ptr) => ServiceDescriptor
1363
+ *
1364
+ * Creates a descriptor wrapper object. May only be called from C.
1365
+ */
1366
+ static VALUE ServiceDescriptor_initialize(VALUE _self, VALUE cookie,
1367
+ VALUE descriptor_pool, VALUE ptr) {
1368
+ ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self);
1369
+
1370
+ if (cookie != c_only_cookie) {
1371
+ rb_raise(rb_eRuntimeError,
1372
+ "Descriptor objects may not be created from Ruby.");
1373
+ }
1374
+
1375
+ RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool);
1376
+ self->servicedef = (const upb_ServiceDef*)NUM2ULL(ptr);
1377
+
1378
+ return Qnil;
1379
+ }
1380
+
1381
+ /*
1382
+ * call-seq:
1383
+ * ServiceDescriptor.name => name
1384
+ *
1385
+ * Returns the name of this service.
1386
+ */
1387
+ static VALUE ServiceDescriptor_name(VALUE _self) {
1388
+ ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self);
1389
+ return rb_str_maybe_null(upb_ServiceDef_FullName(self->servicedef));
1390
+ }
1391
+
1392
+ /*
1393
+ * call-seq:
1394
+ * ServiceDescriptor.file_descriptor
1395
+ *
1396
+ * Returns the FileDescriptor object this service belongs to.
1397
+ */
1398
+ static VALUE ServiceDescriptor_file_descriptor(VALUE _self) {
1399
+ ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self);
1400
+ return get_filedef_obj(self->descriptor_pool,
1401
+ upb_ServiceDef_File(self->servicedef));
1402
+ }
1403
+
1404
+ /*
1405
+ * call-seq:
1406
+ * ServiceDescriptor.each(&block)
1407
+ *
1408
+ * Iterates over methods in this service, yielding to the block on each one.
1409
+ */
1410
+ static VALUE ServiceDescriptor_each(VALUE _self) {
1411
+ ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self);
1412
+
1413
+ int n = upb_ServiceDef_MethodCount(self->servicedef);
1414
+ for (int i = 0; i < n; i++) {
1415
+ const upb_MethodDef* method = upb_ServiceDef_Method(self->servicedef, i);
1416
+ VALUE obj = get_methoddef_obj(self->descriptor_pool, method);
1417
+ rb_yield(obj);
1418
+ }
1419
+ return Qnil;
1420
+ }
1421
+
1422
+ /*
1423
+ * call-seq:
1424
+ * ServiceDescriptor.options => options
1425
+ *
1426
+ * Returns the `ServiceOptions` for this `ServiceDescriptor`.
1427
+ */
1428
+ static VALUE ServiceDescriptor_options(VALUE _self) {
1429
+ ServiceDescriptor* self = ruby_to_ServiceDescriptor(_self);
1430
+ const google_protobuf_ServiceOptions* opts =
1431
+ upb_ServiceDef_Options(self->servicedef);
1432
+ upb_Arena* arena = upb_Arena_New();
1433
+ size_t size;
1434
+ char* serialized =
1435
+ google_protobuf_ServiceOptions_serialize(opts, arena, &size);
1436
+ VALUE service_options = decode_options(_self, "ServiceOptions", size,
1437
+ serialized, self->descriptor_pool);
1438
+ upb_Arena_Free(arena);
1439
+ return service_options;
1440
+ }
1441
+
1442
+ static void ServiceDescriptor_register(VALUE module) {
1443
+ VALUE klass = rb_define_class_under(module, "ServiceDescriptor", rb_cObject);
1444
+ rb_define_alloc_func(klass, ServiceDescriptor_alloc);
1445
+ rb_define_method(klass, "initialize", ServiceDescriptor_initialize, 3);
1446
+ rb_define_method(klass, "name", ServiceDescriptor_name, 0);
1447
+ rb_define_method(klass, "each", ServiceDescriptor_each, 0);
1448
+ rb_define_method(klass, "file_descriptor", ServiceDescriptor_file_descriptor,
1449
+ 0);
1450
+ rb_define_method(klass, "options", ServiceDescriptor_options, 0);
1451
+ rb_include_module(klass, rb_mEnumerable);
1452
+ rb_gc_register_address(&cServiceDescriptor);
1453
+ cServiceDescriptor = klass;
1454
+ }
1455
+
1456
+ // -----------------------------------------------------------------------------
1457
+ // MethodDescriptor
1458
+ // -----------------------------------------------------------------------------
1459
+
1460
+ typedef struct {
1461
+ const upb_MethodDef* methoddef;
1462
+ // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
1463
+ // macro to update VALUE references, as to trigger write barriers.
1464
+ VALUE module; // begins as nil
1465
+ VALUE descriptor_pool; // Owns the upb_MethodDef.
1466
+ } MethodDescriptor;
1467
+
1468
+ static VALUE cMethodDescriptor = Qnil;
1469
+
1470
+ static void MethodDescriptor_mark(void* _self) {
1471
+ MethodDescriptor* self = _self;
1472
+ rb_gc_mark(self->module);
1473
+ rb_gc_mark(self->descriptor_pool);
1474
+ }
1475
+
1476
+ static const rb_data_type_t MethodDescriptor_type = {
1477
+ "Google::Protobuf::MethodDescriptor",
1478
+ {MethodDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
1479
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
1480
+ };
1481
+
1482
+ static MethodDescriptor* ruby_to_MethodDescriptor(VALUE val) {
1483
+ MethodDescriptor* ret;
1484
+ TypedData_Get_Struct(val, MethodDescriptor, &MethodDescriptor_type, ret);
1485
+ return ret;
1486
+ }
1487
+
1488
+ static VALUE MethodDescriptor_alloc(VALUE klass) {
1489
+ MethodDescriptor* self = ALLOC(MethodDescriptor);
1490
+ VALUE ret = TypedData_Wrap_Struct(klass, &MethodDescriptor_type, self);
1491
+ self->methoddef = NULL;
1492
+ self->module = Qnil;
1493
+ self->descriptor_pool = Qnil;
1494
+ return ret;
1495
+ }
1496
+
1497
+ /*
1498
+ * call-seq:
1499
+ * MethodDescriptor.new(c_only_cookie, ptr) => MethodDescriptor
1500
+ *
1501
+ * Creates a descriptor wrapper object. May only be called from C.
1502
+ */
1503
+ static VALUE MethodDescriptor_initialize(VALUE _self, VALUE cookie,
1504
+ VALUE descriptor_pool, VALUE ptr) {
1505
+ MethodDescriptor* self = ruby_to_MethodDescriptor(_self);
1506
+
1507
+ if (cookie != c_only_cookie) {
1508
+ rb_raise(rb_eRuntimeError,
1509
+ "Descriptor objects may not be created from Ruby.");
1510
+ }
1511
+
1512
+ RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool);
1513
+ self->methoddef = (const upb_MethodDef*)NUM2ULL(ptr);
1514
+
1515
+ return Qnil;
1516
+ }
1517
+
1518
+ /*
1519
+ * call-seq:
1520
+ * MethodDescriptor.name => name
1521
+ *
1522
+ * Returns the name of this method
1523
+ */
1524
+ static VALUE MethodDescriptor_name(VALUE _self) {
1525
+ MethodDescriptor* self = ruby_to_MethodDescriptor(_self);
1526
+ return rb_str_maybe_null(upb_MethodDef_Name(self->methoddef));
1527
+ }
1528
+
1529
+ /*
1530
+ * call-seq:
1531
+ * MethodDescriptor.options => options
1532
+ *
1533
+ * Returns the `MethodOptions` for this `MethodDescriptor`.
1534
+ */
1535
+ static VALUE MethodDescriptor_options(VALUE _self) {
1536
+ MethodDescriptor* self = ruby_to_MethodDescriptor(_self);
1537
+ const google_protobuf_MethodOptions* opts =
1538
+ upb_MethodDef_Options(self->methoddef);
1539
+ upb_Arena* arena = upb_Arena_New();
1540
+ size_t size;
1541
+ char* serialized =
1542
+ google_protobuf_MethodOptions_serialize(opts, arena, &size);
1543
+ VALUE method_options = decode_options(_self, "MethodOptions", size,
1544
+ serialized, self->descriptor_pool);
1545
+ upb_Arena_Free(arena);
1546
+ return method_options;
1547
+ }
1548
+
1549
+ /*
1550
+ * call-seq:
1551
+ * MethodDescriptor.input_type => Descriptor
1552
+ *
1553
+ * Returns the `Descriptor` for the request message type of this method
1554
+ */
1555
+ static VALUE MethodDescriptor_input_type(VALUE _self) {
1556
+ MethodDescriptor* self = ruby_to_MethodDescriptor(_self);
1557
+ const upb_MessageDef* type = upb_MethodDef_InputType(self->methoddef);
1558
+ return get_msgdef_obj(self->descriptor_pool, type);
1559
+ }
1560
+
1561
+ /*
1562
+ * call-seq:
1563
+ * MethodDescriptor.output_type => Descriptor
1564
+ *
1565
+ * Returns the `Descriptor` for the response message type of this method
1566
+ */
1567
+ static VALUE MethodDescriptor_output_type(VALUE _self) {
1568
+ MethodDescriptor* self = ruby_to_MethodDescriptor(_self);
1569
+ const upb_MessageDef* type = upb_MethodDef_OutputType(self->methoddef);
1570
+ return get_msgdef_obj(self->descriptor_pool, type);
1571
+ }
1572
+
1573
+ /*
1574
+ * call-seq:
1575
+ * MethodDescriptor.client_streaming => bool
1576
+ *
1577
+ * Returns whether or not this is a streaming request method
1578
+ */
1579
+ static VALUE MethodDescriptor_client_streaming(VALUE _self) {
1580
+ MethodDescriptor* self = ruby_to_MethodDescriptor(_self);
1581
+ return upb_MethodDef_ClientStreaming(self->methoddef) ? Qtrue : Qfalse;
1582
+ }
1583
+
1584
+ /*
1585
+ * call-seq:
1586
+ * MethodDescriptor.server_streaming => bool
1587
+ *
1588
+ * Returns whether or not this is a streaming response method
1589
+ */
1590
+ static VALUE MethodDescriptor_server_streaming(VALUE _self) {
1591
+ MethodDescriptor* self = ruby_to_MethodDescriptor(_self);
1592
+ return upb_MethodDef_ServerStreaming(self->methoddef) ? Qtrue : Qfalse;
1593
+ }
1594
+
1595
+ static void MethodDescriptor_register(VALUE module) {
1596
+ VALUE klass = rb_define_class_under(module, "MethodDescriptor", rb_cObject);
1597
+ rb_define_alloc_func(klass, MethodDescriptor_alloc);
1598
+ rb_define_method(klass, "initialize", MethodDescriptor_initialize, 3);
1599
+ rb_define_method(klass, "name", MethodDescriptor_name, 0);
1600
+ rb_define_method(klass, "options", MethodDescriptor_options, 0);
1601
+ rb_define_method(klass, "input_type", MethodDescriptor_input_type, 0);
1602
+ rb_define_method(klass, "output_type", MethodDescriptor_output_type, 0);
1603
+ rb_define_method(klass, "client_streaming", MethodDescriptor_client_streaming,
1604
+ 0);
1605
+ rb_define_method(klass, "server_streaming", MethodDescriptor_server_streaming,
1606
+ 0);
1607
+ rb_gc_register_address(&cMethodDescriptor);
1608
+ cMethodDescriptor = klass;
1609
+ }
1610
+
1297
1611
  static VALUE get_def_obj(VALUE _descriptor_pool, const void* ptr, VALUE klass) {
1298
1612
  DescriptorPool* descriptor_pool = ruby_to_DescriptorPool(_descriptor_pool);
1299
1613
  VALUE key = ULL2NUM((intptr_t)ptr);
@@ -1335,6 +1649,16 @@ static VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_OneofDef* def) {
1335
1649
  return get_def_obj(descriptor_pool, def, cOneofDescriptor);
1336
1650
  }
1337
1651
 
1652
+ static VALUE get_servicedef_obj(VALUE descriptor_pool,
1653
+ const upb_ServiceDef* def) {
1654
+ return get_def_obj(descriptor_pool, def, cServiceDescriptor);
1655
+ }
1656
+
1657
+ static VALUE get_methoddef_obj(VALUE descriptor_pool,
1658
+ const upb_MethodDef* def) {
1659
+ return get_def_obj(descriptor_pool, def, cMethodDescriptor);
1660
+ }
1661
+
1338
1662
  // -----------------------------------------------------------------------------
1339
1663
  // Shared functions
1340
1664
  // -----------------------------------------------------------------------------
@@ -1410,6 +1734,8 @@ void Defs_register(VALUE module) {
1410
1734
  FieldDescriptor_register(module);
1411
1735
  OneofDescriptor_register(module);
1412
1736
  EnumDescriptor_register(module);
1737
+ ServiceDescriptor_register(module);
1738
+ MethodDescriptor_register(module);
1413
1739
 
1414
1740
  rb_gc_register_address(&c_only_cookie);
1415
1741
  c_only_cookie = rb_class_new_instance(0, NULL, rb_cObject);
@@ -54,3 +54,19 @@ char* FieldDescriptor_serialized_options(const upb_FieldDef* fielddef,
54
54
  char* serialized = google_protobuf_FieldOptions_serialize(opts, arena, size);
55
55
  return serialized;
56
56
  }
57
+
58
+ char* ServiceDescriptor_serialized_options(const upb_ServiceDef* servicedef,
59
+ size_t* size, upb_Arena* arena) {
60
+ const google_protobuf_ServiceOptions* opts =
61
+ upb_ServiceDef_Options(servicedef);
62
+ char* serialized =
63
+ google_protobuf_ServiceOptions_serialize(opts, arena, size);
64
+ return serialized;
65
+ }
66
+
67
+ char* MethodDescriptor_serialized_options(const upb_MethodDef* methoddef,
68
+ size_t* size, upb_Arena* arena) {
69
+ const google_protobuf_MethodOptions* opts = upb_MethodDef_Options(methoddef);
70
+ char* serialized = google_protobuf_MethodOptions_serialize(opts, arena, size);
71
+ return serialized;
72
+ }
@@ -63,9 +63,10 @@ static VALUE Map_alloc(VALUE klass) {
63
63
  return TypedData_Wrap_Struct(klass, &Map_type, self);
64
64
  }
65
65
 
66
- VALUE Map_GetRubyWrapper(upb_Map* map, upb_CType key_type, TypeInfo value_type,
67
- VALUE arena) {
66
+ VALUE Map_GetRubyWrapper(const upb_Map* map, upb_CType key_type,
67
+ TypeInfo value_type, VALUE arena) {
68
68
  PBRUBY_ASSERT(map);
69
+ PBRUBY_ASSERT(arena != Qnil);
69
70
 
70
71
  VALUE val = ObjectCache_Get(map);
71
72
 
@@ -83,7 +84,6 @@ VALUE Map_GetRubyWrapper(upb_Map* map, upb_CType key_type, TypeInfo value_type,
83
84
  }
84
85
  return ObjectCache_TryAdd(map, val);
85
86
  }
86
-
87
87
  return val;
88
88
  }
89
89
 
@@ -105,8 +105,9 @@ static TypeInfo Map_keyinfo(Map* self) {
105
105
  }
106
106
 
107
107
  static upb_Map* Map_GetMutable(VALUE _self) {
108
- rb_check_frozen(_self);
109
- return (upb_Map*)ruby_to_Map(_self)->map;
108
+ const upb_Map* map = ruby_to_Map(_self)->map;
109
+ Protobuf_CheckNotFrozen(_self, upb_Map_IsFrozen(map));
110
+ return (upb_Map*)map;
110
111
  }
111
112
 
112
113
  VALUE Map_CreateHash(const upb_Map* map, upb_CType key_type,
@@ -439,14 +440,14 @@ static VALUE Map_has_key(VALUE _self, VALUE key) {
439
440
  * nil if none was present. Throws an exception if the key is of the wrong type.
440
441
  */
441
442
  static VALUE Map_delete(VALUE _self, VALUE key) {
443
+ upb_Map* map = Map_GetMutable(_self);
442
444
  Map* self = ruby_to_Map(_self);
443
- rb_check_frozen(_self);
444
445
 
445
446
  upb_MessageValue key_upb =
446
447
  Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
447
448
  upb_MessageValue val_upb;
448
449
 
449
- if (upb_Map_Delete(Map_GetMutable(_self), key_upb, &val_upb)) {
450
+ if (upb_Map_Delete(map, key_upb, &val_upb)) {
450
451
  return Convert_UpbToRuby(val_upb, self->value_type_info, self->arena);
451
452
  } else {
452
453
  return Qnil;
@@ -560,29 +561,79 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
560
561
 
561
562
  /*
562
563
  * call-seq:
563
- * Message.freeze => self
564
+ * Map.frozen? => bool
565
+ *
566
+ * Returns true if the map is frozen in either Ruby or the underlying
567
+ * representation. Freezes the Ruby map object if it is not already frozen in
568
+ * Ruby but it is frozen in the underlying representation.
569
+ */
570
+ VALUE Map_frozen(VALUE _self) {
571
+ Map* self = ruby_to_Map(_self);
572
+ if (!upb_Map_IsFrozen(self->map)) {
573
+ PBRUBY_ASSERT(!RB_OBJ_FROZEN(_self));
574
+ return Qfalse;
575
+ }
576
+
577
+ // Lazily freeze the Ruby wrapper.
578
+ if (!RB_OBJ_FROZEN(_self)) RB_OBJ_FREEZE(_self);
579
+ return Qtrue;
580
+ }
581
+
582
+ /*
583
+ * call-seq:
584
+ * Map.freeze => self
564
585
  *
565
- * Freezes the message object. We have to intercept this so we can pin the
566
- * Ruby object into memory so we don't forget it's frozen.
586
+ * Freezes the map object. We have to intercept this so we can freeze the
587
+ * underlying representation, not just the Ruby wrapper.
567
588
  */
568
589
  VALUE Map_freeze(VALUE _self) {
569
590
  Map* self = ruby_to_Map(_self);
591
+ if (RB_OBJ_FROZEN(_self)) {
592
+ PBRUBY_ASSERT(upb_Map_IsFrozen(self->map));
593
+ return _self;
594
+ }
595
+
596
+ if (!upb_Map_IsFrozen(self->map)) {
597
+ if (self->value_type_info.type == kUpb_CType_Message) {
598
+ upb_Map_Freeze(
599
+ Map_GetMutable(_self),
600
+ upb_MessageDef_MiniTable(self->value_type_info.def.msgdef));
601
+ } else {
602
+ upb_Map_Freeze(Map_GetMutable(_self), NULL);
603
+ }
604
+ }
570
605
 
571
- if (RB_OBJ_FROZEN(_self)) return _self;
572
- Arena_Pin(self->arena, _self);
573
606
  RB_OBJ_FREEZE(_self);
574
607
 
575
- if (self->value_type_info.type == kUpb_CType_Message) {
576
- size_t iter = kUpb_Map_Begin;
577
- upb_MessageValue key, val;
608
+ return _self;
609
+ }
610
+
611
+ VALUE Map_EmptyFrozen(const upb_FieldDef* f) {
612
+ PBRUBY_ASSERT(upb_FieldDef_IsMap(f));
613
+ VALUE val = ObjectCache_Get(f);
578
614
 
579
- while (upb_Map_Next(self->map, &key, &val, &iter)) {
580
- VALUE val_val =
581
- Convert_UpbToRuby(val, self->value_type_info, self->arena);
582
- Message_freeze(val_val);
615
+ if (val == Qnil) {
616
+ const upb_FieldDef* key_f = map_field_key(f);
617
+ const upb_FieldDef* val_f = map_field_value(f);
618
+ upb_CType key_type = upb_FieldDef_CType(key_f);
619
+ TypeInfo value_type_info = TypeInfo_get(val_f);
620
+ val = Map_alloc(cMap);
621
+ Map* self;
622
+ TypedData_Get_Struct(val, Map, &Map_type, self);
623
+ self->arena = Arena_new();
624
+ self->map =
625
+ upb_Map_New(Arena_get(self->arena), key_type, value_type_info.type);
626
+ self->key_type = key_type;
627
+ self->value_type_info = value_type_info;
628
+ if (self->value_type_info.type == kUpb_CType_Message) {
629
+ const upb_MessageDef* val_m = value_type_info.def.msgdef;
630
+ self->value_type_class = Descriptor_DefToClass(val_m);
583
631
  }
632
+ return ObjectCache_TryAdd(f, Map_freeze(val));
584
633
  }
585
- return _self;
634
+ PBRUBY_ASSERT(RB_OBJ_FROZEN(val));
635
+ PBRUBY_ASSERT(upb_Map_IsFrozen(ruby_to_Map(val)->map));
636
+ return val;
586
637
  }
587
638
 
588
639
  /*
@@ -671,6 +722,7 @@ void Map_register(VALUE module) {
671
722
  rb_define_method(klass, "clone", Map_dup, 0);
672
723
  rb_define_method(klass, "==", Map_eq, 1);
673
724
  rb_define_method(klass, "freeze", Map_freeze, 0);
725
+ rb_define_method(klass, "frozen?", Map_frozen, 0);
674
726
  rb_define_method(klass, "hash", Map_hash, 0);
675
727
  rb_define_method(klass, "to_h", Map_to_h, 0);
676
728
  rb_define_method(klass, "inspect", Map_inspect, 0);
@@ -11,10 +11,14 @@
11
11
  #include "protobuf.h"
12
12
  #include "ruby-upb.h"
13
13
 
14
+ // Returns a frozen sentinel Ruby wrapper object for an empty upb_Map with the
15
+ // key and value types specified by the field. Creates one if it doesn't exist.
16
+ VALUE Map_EmptyFrozen(const upb_FieldDef* f);
17
+
14
18
  // Returns a Ruby wrapper object for the given map, which will be created if
15
19
  // one does not exist already.
16
- VALUE Map_GetRubyWrapper(upb_Map *map, upb_CType key_type, TypeInfo value_type,
17
- VALUE arena);
20
+ VALUE Map_GetRubyWrapper(const upb_Map *map, upb_CType key_type,
21
+ TypeInfo value_type, VALUE arena);
18
22
 
19
23
  // Gets the underlying upb_Map for this Ruby map object, which must have
20
24
  // key/value type that match |field|. If this is not a map or the type doesn't