Chris Fallin | 973f425 | 2014-11-18 14:19:58 -0800 | [diff] [blame] | 1 | // Protocol Buffers - Google's data interchange format |
| 2 | // Copyright 2014 Google Inc. All rights reserved. |
Chris Fallin | 973f425 | 2014-11-18 14:19:58 -0800 | [diff] [blame] | 3 | // |
Joshua Haberman | ba9e2af | 2023-09-08 17:13:26 -0700 | [diff] [blame] | 4 | // Use of this source code is governed by a BSD-style |
| 5 | // license that can be found in the LICENSE file or at |
| 6 | // https://developers.google.com/open-source/licenses/bsd |
Chris Fallin | 973f425 | 2014-11-18 14:19:58 -0800 | [diff] [blame] | 7 | |
| 8 | #include "protobuf.h" |
| 9 | |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 10 | #include <ruby/version.h> |
| 11 | |
| 12 | #include "defs.h" |
| 13 | #include "map.h" |
| 14 | #include "message.h" |
| 15 | #include "repeated_field.h" |
| 16 | |
Aaron Patterson | addd061 | 2021-03-10 13:54:04 -0800 | [diff] [blame] | 17 | VALUE cParseError; |
Erik Benoist | 74f8e24 | 2018-06-26 22:24:24 -0500 | [diff] [blame] | 18 | VALUE cTypeError; |
Chris Fallin | 973f425 | 2014-11-18 14:19:58 -0800 | [diff] [blame] | 19 | |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 20 | const upb_FieldDef *map_field_key(const upb_FieldDef *field) { |
| 21 | const upb_MessageDef *entry = upb_FieldDef_MessageSubDef(field); |
Joshua Haberman | 7ecf43f | 2022-03-14 13:11:29 -0700 | [diff] [blame] | 22 | return upb_MessageDef_FindFieldByNumber(entry, 1); |
Joshua Haberman | 1e37a94 | 2019-08-13 04:54:11 -0700 | [diff] [blame] | 23 | } |
| 24 | |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 25 | const upb_FieldDef *map_field_value(const upb_FieldDef *field) { |
| 26 | const upb_MessageDef *entry = upb_FieldDef_MessageSubDef(field); |
Joshua Haberman | 7ecf43f | 2022-03-14 13:11:29 -0700 | [diff] [blame] | 27 | return upb_MessageDef_FindFieldByNumber(entry, 2); |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 28 | } |
| 29 | |
| 30 | // ----------------------------------------------------------------------------- |
| 31 | // StringBuilder, for inspect |
| 32 | // ----------------------------------------------------------------------------- |
| 33 | |
| 34 | struct StringBuilder { |
| 35 | size_t size; |
| 36 | size_t cap; |
| 37 | char *data; |
| 38 | }; |
| 39 | |
| 40 | typedef struct StringBuilder StringBuilder; |
| 41 | |
| 42 | static size_t StringBuilder_SizeOf(size_t cap) { |
| 43 | return sizeof(StringBuilder) + cap; |
| 44 | } |
| 45 | |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 46 | StringBuilder *StringBuilder_New() { |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 47 | const size_t cap = 128; |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 48 | StringBuilder *builder = malloc(sizeof(*builder)); |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 49 | builder->size = 0; |
| 50 | builder->cap = cap; |
| 51 | builder->data = malloc(builder->cap); |
| 52 | return builder; |
| 53 | } |
| 54 | |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 55 | void StringBuilder_Free(StringBuilder *b) { |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 56 | free(b->data); |
| 57 | free(b); |
| 58 | } |
| 59 | |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 60 | void StringBuilder_Printf(StringBuilder *b, const char *fmt, ...) { |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 61 | size_t have = b->cap - b->size; |
| 62 | size_t n; |
| 63 | va_list args; |
| 64 | |
| 65 | va_start(args, fmt); |
| 66 | n = vsnprintf(&b->data[b->size], have, fmt, args); |
| 67 | va_end(args); |
| 68 | |
| 69 | if (have <= n) { |
| 70 | while (have <= n) { |
| 71 | b->cap *= 2; |
| 72 | have = b->cap - b->size; |
| 73 | } |
| 74 | b->data = realloc(b->data, StringBuilder_SizeOf(b->cap)); |
| 75 | va_start(args, fmt); |
| 76 | n = vsnprintf(&b->data[b->size], have, fmt, args); |
| 77 | va_end(args); |
| 78 | PBRUBY_ASSERT(n < have); |
| 79 | } |
| 80 | |
| 81 | b->size += n; |
| 82 | } |
| 83 | |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 84 | VALUE StringBuilder_ToRubyString(StringBuilder *b) { |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 85 | VALUE ret = rb_str_new(b->data, b->size); |
| 86 | rb_enc_associate(ret, rb_utf8_encoding()); |
| 87 | return ret; |
| 88 | } |
| 89 | |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 90 | static void StringBuilder_PrintEnum(StringBuilder *b, int32_t val, |
| 91 | const upb_EnumDef *e) { |
| 92 | const upb_EnumValueDef *ev = upb_EnumDef_FindValueByNumber(e, val); |
| 93 | if (ev) { |
| 94 | StringBuilder_Printf(b, ":%s", upb_EnumValueDef_Name(ev)); |
Joshua Haberman | 1e37a94 | 2019-08-13 04:54:11 -0700 | [diff] [blame] | 95 | } else { |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 96 | StringBuilder_Printf(b, "%" PRId32, val); |
| 97 | } |
| 98 | } |
| 99 | |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 100 | void StringBuilder_PrintMsgval(StringBuilder *b, upb_MessageValue val, |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 101 | TypeInfo info) { |
| 102 | switch (info.type) { |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 103 | case kUpb_CType_Bool: |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 104 | StringBuilder_Printf(b, "%s", val.bool_val ? "true" : "false"); |
| 105 | break; |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 106 | case kUpb_CType_Float: { |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 107 | VALUE str = rb_inspect(DBL2NUM(val.float_val)); |
| 108 | StringBuilder_Printf(b, "%s", RSTRING_PTR(str)); |
| 109 | break; |
| 110 | } |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 111 | case kUpb_CType_Double: { |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 112 | VALUE str = rb_inspect(DBL2NUM(val.double_val)); |
| 113 | StringBuilder_Printf(b, "%s", RSTRING_PTR(str)); |
| 114 | break; |
| 115 | } |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 116 | case kUpb_CType_Int32: |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 117 | StringBuilder_Printf(b, "%" PRId32, val.int32_val); |
| 118 | break; |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 119 | case kUpb_CType_UInt32: |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 120 | StringBuilder_Printf(b, "%" PRIu32, val.uint32_val); |
| 121 | break; |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 122 | case kUpb_CType_Int64: |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 123 | StringBuilder_Printf(b, "%" PRId64, val.int64_val); |
| 124 | break; |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 125 | case kUpb_CType_UInt64: |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 126 | StringBuilder_Printf(b, "%" PRIu64, val.uint64_val); |
| 127 | break; |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 128 | case kUpb_CType_String: |
| 129 | StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size, |
| 130 | val.str_val.data); |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 131 | break; |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 132 | case kUpb_CType_Bytes: |
| 133 | StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size, |
| 134 | val.str_val.data); |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 135 | break; |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 136 | case kUpb_CType_Enum: |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 137 | StringBuilder_PrintEnum(b, val.int32_val, info.def.enumdef); |
| 138 | break; |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 139 | case kUpb_CType_Message: |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 140 | Message_PrintMessage(b, val.msg_val, info.def.msgdef); |
| 141 | break; |
Joshua Haberman | 1e37a94 | 2019-08-13 04:54:11 -0700 | [diff] [blame] | 142 | } |
| 143 | } |
| 144 | |
Chris Fallin | 973f425 | 2014-11-18 14:19:58 -0800 | [diff] [blame] | 145 | // ----------------------------------------------------------------------------- |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 146 | // Arena |
Chris Fallin | 973f425 | 2014-11-18 14:19:58 -0800 | [diff] [blame] | 147 | // ----------------------------------------------------------------------------- |
| 148 | |
Joshua Haberman | 9879f42 | 2021-02-24 16:41:35 -0800 | [diff] [blame] | 149 | typedef struct { |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 150 | upb_Arena *arena; |
Jean byroot Boussier | d82d8a4 | 2023-02-23 13:44:39 -0800 | [diff] [blame] | 151 | // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE() |
| 152 | // macro to update VALUE references, as to trigger write barriers. |
Joshua Haberman | 9879f42 | 2021-02-24 16:41:35 -0800 | [diff] [blame] | 153 | VALUE pinned_objs; |
| 154 | } Arena; |
| 155 | |
| 156 | static void Arena_mark(void *data) { |
| 157 | Arena *arena = data; |
| 158 | rb_gc_mark(arena->pinned_objs); |
| 159 | } |
| 160 | |
| 161 | static void Arena_free(void *data) { |
| 162 | Arena *arena = data; |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 163 | upb_Arena_Free(arena->arena); |
Joshua Haberman | 67fee91 | 2021-04-07 10:30:51 -0700 | [diff] [blame] | 164 | xfree(arena); |
Joshua Haberman | 9879f42 | 2021-02-24 16:41:35 -0800 | [diff] [blame] | 165 | } |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 166 | |
| 167 | static VALUE cArena; |
| 168 | |
| 169 | const rb_data_type_t Arena_type = { |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 170 | "Google::Protobuf::Internal::Arena", |
| 171 | {Arena_mark, Arena_free, NULL}, |
Jean byroot Boussier | d82d8a4 | 2023-02-23 13:44:39 -0800 | [diff] [blame] | 172 | .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 173 | }; |
| 174 | |
Matt Fowles Kulukundis | a01d047 | 2023-07-08 16:17:11 -0700 | [diff] [blame] | 175 | static void *ruby_upb_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize, |
| 176 | size_t size) { |
zhangskz | 276add0 | 2022-03-08 12:05:34 -0500 | [diff] [blame] | 177 | if (size == 0) { |
| 178 | xfree(ptr); |
| 179 | return NULL; |
| 180 | } else { |
| 181 | return xrealloc(ptr, size); |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | upb_alloc ruby_upb_alloc = {&ruby_upb_allocfunc}; |
| 186 | |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 187 | static VALUE Arena_alloc(VALUE klass) { |
Joshua Haberman | 9879f42 | 2021-02-24 16:41:35 -0800 | [diff] [blame] | 188 | Arena *arena = ALLOC(Arena); |
zhangskz | 276add0 | 2022-03-08 12:05:34 -0500 | [diff] [blame] | 189 | arena->arena = upb_Arena_Init(NULL, 0, &ruby_upb_alloc); |
Joshua Haberman | 9879f42 | 2021-02-24 16:41:35 -0800 | [diff] [blame] | 190 | arena->pinned_objs = Qnil; |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 191 | return TypedData_Wrap_Struct(klass, &Arena_type, arena); |
Chris Fallin | 973f425 | 2014-11-18 14:19:58 -0800 | [diff] [blame] | 192 | } |
| 193 | |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 194 | upb_Arena *Arena_get(VALUE _arena) { |
Joshua Haberman | 9879f42 | 2021-02-24 16:41:35 -0800 | [diff] [blame] | 195 | Arena *arena; |
| 196 | TypedData_Get_Struct(_arena, Arena, &Arena_type, arena); |
| 197 | return arena->arena; |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 198 | } |
Chris Fallin | 973f425 | 2014-11-18 14:19:58 -0800 | [diff] [blame] | 199 | |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 200 | void Arena_fuse(VALUE _arena, upb_Arena *other) { |
Joshua Haberman | 367e469 | 2021-05-21 23:04:09 -0700 | [diff] [blame] | 201 | Arena *arena; |
| 202 | TypedData_Get_Struct(_arena, Arena, &Arena_type, arena); |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 203 | if (!upb_Arena_Fuse(arena->arena, other)) { |
Joshua Haberman | 367e469 | 2021-05-21 23:04:09 -0700 | [diff] [blame] | 204 | rb_raise(rb_eRuntimeError, |
| 205 | "Unable to fuse arenas. This should never happen since Ruby does " |
| 206 | "not use initial blocks"); |
| 207 | } |
| 208 | } |
| 209 | |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 210 | VALUE Arena_new() { return Arena_alloc(cArena); } |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 211 | |
Joshua Haberman | 9879f42 | 2021-02-24 16:41:35 -0800 | [diff] [blame] | 212 | void Arena_Pin(VALUE _arena, VALUE obj) { |
| 213 | Arena *arena; |
| 214 | TypedData_Get_Struct(_arena, Arena, &Arena_type, arena); |
| 215 | if (arena->pinned_objs == Qnil) { |
Jean byroot Boussier | d82d8a4 | 2023-02-23 13:44:39 -0800 | [diff] [blame] | 216 | RB_OBJ_WRITE(_arena, &arena->pinned_objs, rb_ary_new()); |
Joshua Haberman | 9879f42 | 2021-02-24 16:41:35 -0800 | [diff] [blame] | 217 | } |
| 218 | rb_ary_push(arena->pinned_objs, obj); |
| 219 | } |
| 220 | |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 221 | void Arena_register(VALUE module) { |
| 222 | VALUE internal = rb_define_module_under(module, "Internal"); |
| 223 | VALUE klass = rb_define_class_under(internal, "Arena", rb_cObject); |
| 224 | rb_define_alloc_func(klass, Arena_alloc); |
| 225 | rb_gc_register_address(&cArena); |
| 226 | cArena = klass; |
| 227 | } |
| 228 | |
| 229 | // ----------------------------------------------------------------------------- |
| 230 | // Object Cache |
| 231 | // ----------------------------------------------------------------------------- |
| 232 | |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 233 | // Public ObjectCache API. |
| 234 | |
Joshua Haberman | 9879f42 | 2021-02-24 16:41:35 -0800 | [diff] [blame] | 235 | VALUE weak_obj_cache = Qnil; |
| 236 | ID item_get; |
Matt Fowles Kulukundis | a01d047 | 2023-07-08 16:17:11 -0700 | [diff] [blame] | 237 | ID item_try_add; |
Joshua Haberman | 9879f42 | 2021-02-24 16:41:35 -0800 | [diff] [blame] | 238 | |
Matt Fowles Kulukundis | a01d047 | 2023-07-08 16:17:11 -0700 | [diff] [blame] | 239 | static void ObjectCache_Init(VALUE protobuf) { |
| 240 | item_get = rb_intern("get"); |
| 241 | item_try_add = rb_intern("try_add"); |
| 242 | |
Joshua Haberman | 9879f42 | 2021-02-24 16:41:35 -0800 | [diff] [blame] | 243 | rb_gc_register_address(&weak_obj_cache); |
Joshua Haberman | 3f98af2 | 2023-07-11 11:21:22 -0700 | [diff] [blame] | 244 | #if SIZEOF_LONG >= SIZEOF_VALUE |
Matt Fowles Kulukundis | a01d047 | 2023-07-08 16:17:11 -0700 | [diff] [blame] | 245 | VALUE cache_class = rb_const_get(protobuf, rb_intern("ObjectCache")); |
| 246 | #else |
| 247 | VALUE cache_class = rb_const_get(protobuf, rb_intern("LegacyObjectCache")); |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 248 | #endif |
Matt Fowles Kulukundis | a01d047 | 2023-07-08 16:17:11 -0700 | [diff] [blame] | 249 | |
| 250 | weak_obj_cache = rb_class_new_instance(0, NULL, cache_class); |
| 251 | rb_const_set(protobuf, rb_intern("OBJECT_CACHE"), weak_obj_cache); |
| 252 | rb_const_set(protobuf, rb_intern("SIZEOF_LONG"), INT2NUM(SIZEOF_LONG)); |
| 253 | rb_const_set(protobuf, rb_intern("SIZEOF_VALUE"), INT2NUM(SIZEOF_VALUE)); |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 254 | } |
| 255 | |
Stan Hu | 055c378 | 2023-08-15 12:25:13 -0700 | [diff] [blame] | 256 | static VALUE ObjectCache_GetKey(const void *key) { |
Matt Fowles Kulukundis | a01d047 | 2023-07-08 16:17:11 -0700 | [diff] [blame] | 257 | VALUE key_val = (VALUE)key; |
| 258 | PBRUBY_ASSERT((key_val & 3) == 0); |
Stan Hu | 055c378 | 2023-08-15 12:25:13 -0700 | [diff] [blame] | 259 | // Ensure the key can be stored as a Fixnum since 1 bit is needed for |
| 260 | // FIXNUM_FLAG and 1 bit is needed for the sign bit. |
| 261 | VALUE new_key = LL2NUM(key_val >> 2); |
| 262 | PBRUBY_ASSERT(FIXNUM_P(new_key)); |
| 263 | return new_key; |
| 264 | } |
| 265 | |
| 266 | VALUE ObjectCache_TryAdd(const void *key, VALUE val) { |
| 267 | VALUE key_val = ObjectCache_GetKey(key); |
| 268 | return rb_funcall(weak_obj_cache, item_try_add, 2, key_val, val); |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 269 | } |
| 270 | |
| 271 | // Returns the cached object for this key, if any. Otherwise returns Qnil. |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 272 | VALUE ObjectCache_Get(const void *key) { |
Stan Hu | 055c378 | 2023-08-15 12:25:13 -0700 | [diff] [blame] | 273 | VALUE key_val = ObjectCache_GetKey(key); |
| 274 | return rb_funcall(weak_obj_cache, item_get, 1, key_val); |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 275 | } |
| 276 | |
| 277 | /* |
| 278 | * call-seq: |
| 279 | * Google::Protobuf.discard_unknown(msg) |
| 280 | * |
| 281 | * Discard unknown fields in the given message object and recursively discard |
| 282 | * unknown fields in submessages. |
| 283 | */ |
| 284 | static VALUE Google_Protobuf_discard_unknown(VALUE self, VALUE msg_rb) { |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 285 | const upb_MessageDef *m; |
| 286 | upb_Message *msg = Message_GetMutable(msg_rb, &m); |
| 287 | if (!upb_Message_DiscardUnknown(msg, m, 128)) { |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 288 | rb_raise(rb_eRuntimeError, "Messages nested too deeply."); |
| 289 | } |
| 290 | |
| 291 | return Qnil; |
| 292 | } |
| 293 | |
| 294 | /* |
| 295 | * call-seq: |
| 296 | * Google::Protobuf.deep_copy(obj) => copy_of_obj |
| 297 | * |
| 298 | * Performs a deep copy of a RepeatedField instance, a Map instance, or a |
| 299 | * message object, recursively copying its members. |
| 300 | */ |
| 301 | VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) { |
| 302 | VALUE klass = CLASS_OF(obj); |
| 303 | if (klass == cRepeatedField) { |
| 304 | return RepeatedField_deep_copy(obj); |
| 305 | } else if (klass == cMap) { |
| 306 | return Map_deep_copy(obj); |
| 307 | } else { |
| 308 | VALUE new_arena_rb = Arena_new(); |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 309 | upb_Arena *new_arena = Arena_get(new_arena_rb); |
| 310 | const upb_MessageDef *m; |
| 311 | const upb_Message *msg = Message_Get(obj, &m); |
| 312 | upb_Message *new_msg = Message_deep_copy(msg, m, new_arena); |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 313 | return Message_GetRubyWrapper(new_msg, m, new_arena_rb); |
| 314 | } |
| 315 | } |
Chris Fallin | 231886f | 2015-05-19 15:33:48 -0700 | [diff] [blame] | 316 | |
Chris Fallin | 973f425 | 2014-11-18 14:19:58 -0800 | [diff] [blame] | 317 | // ----------------------------------------------------------------------------- |
| 318 | // Initialization/entry point. |
| 319 | // ----------------------------------------------------------------------------- |
| 320 | |
| 321 | // This must be named "Init_protobuf_c" because the Ruby module is named |
| 322 | // "protobuf_c" -- the VM looks for this symbol in our .so. |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 323 | __attribute__((visibility("default"))) void Init_protobuf_c() { |
Chris Fallin | 973f425 | 2014-11-18 14:19:58 -0800 | [diff] [blame] | 324 | VALUE google = rb_define_module("Google"); |
| 325 | VALUE protobuf = rb_define_module_under(google, "Protobuf"); |
Josh Haberman | a1daeab | 2015-07-10 11:56:06 -0700 | [diff] [blame] | 326 | |
Matt Fowles Kulukundis | a01d047 | 2023-07-08 16:17:11 -0700 | [diff] [blame] | 327 | ObjectCache_Init(protobuf); |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 328 | Arena_register(protobuf); |
| 329 | Defs_register(protobuf); |
Chris Fallin | 973f425 | 2014-11-18 14:19:58 -0800 | [diff] [blame] | 330 | RepeatedField_register(protobuf); |
Chris Fallin | fd1a3ff | 2015-01-06 15:44:09 -0800 | [diff] [blame] | 331 | Map_register(protobuf); |
Joshua Haberman | 9abf6e2 | 2021-01-13 12:16:25 -0800 | [diff] [blame] | 332 | Message_register(protobuf); |
Chris Fallin | 973f425 | 2014-11-18 14:19:58 -0800 | [diff] [blame] | 333 | |
Aaron Patterson | addd061 | 2021-03-10 13:54:04 -0800 | [diff] [blame] | 334 | cParseError = rb_const_get(protobuf, rb_intern("ParseError")); |
| 335 | rb_gc_register_mark_object(cParseError); |
Erik Benoist | 74f8e24 | 2018-06-26 22:24:24 -0500 | [diff] [blame] | 336 | cTypeError = rb_const_get(protobuf, rb_intern("TypeError")); |
Aaron Patterson | addd061 | 2021-03-10 13:54:04 -0800 | [diff] [blame] | 337 | rb_gc_register_mark_object(cTypeError); |
Josh Haberman | 181c7f2 | 2015-07-15 11:05:10 -0700 | [diff] [blame] | 338 | |
Paul Yang | 0e7b589 | 2017-12-07 14:18:38 -0800 | [diff] [blame] | 339 | rb_define_singleton_method(protobuf, "discard_unknown", |
| 340 | Google_Protobuf_discard_unknown, 1); |
Joshua Haberman | c153dd9 | 2022-01-21 15:46:56 -0800 | [diff] [blame] | 341 | rb_define_singleton_method(protobuf, "deep_copy", Google_Protobuf_deep_copy, |
| 342 | 1); |
Chris Fallin | 973f425 | 2014-11-18 14:19:58 -0800 | [diff] [blame] | 343 | } |